Skip to content

Datastore

package datastore

import (
    "context"
    "fmt"
    "github.com/testcontainers/testcontainers-go"
    "github.com/testcontainers/testcontainers-go/wait"
)

// datastoreContainer represents the datastore container type used in the module
type datastoreContainer struct {
    testcontainers.Container
    URI string
}

// setupDatastore creates an instance of the datastore container type
func setupDatastore(ctx context.Context) (*datastoreContainer, error) {
    req := testcontainers.ContainerRequest{
        Image:        "gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators",
        ExposedPorts: []string{"8081/tcp"},
        WaitingFor:   wait.ForHTTP("/").WithPort("8081/tcp"),
        Cmd: []string{
            "/bin/sh",
            "-c",
            "gcloud beta emulators datastore start --project test-project --host-port 0.0.0.0:8081",
        },
    }
    container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
        ContainerRequest: req,
        Started:          true,
    })
    if err != nil {
        return nil, err
    }

    mappedPort, err := container.MappedPort(ctx, "8081")
    if err != nil {
        return nil, err
    }

    hostIP, err := container.Host(ctx)
    if err != nil {
        return nil, err
    }

    uri := fmt.Sprintf("%s:%s", hostIP, mappedPort.Port())

    return &datastoreContainer{Container: container, URI: uri}, nil
}
package datastore

import (
    "cloud.google.com/go/datastore"
    "context"
    "google.golang.org/api/option"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "testing"
)

type Task struct {
    Description string
}

func TestDatastore(t *testing.T) {
    ctx := context.Background()

    container, err := setupDatastore(ctx)
    if err != nil {
        t.Fatal(err)
    }

    // Clean up the container after the test is complete
    t.Cleanup(func() {
        if err := container.Terminate(ctx); err != nil {
            t.Fatalf("failed to terminate container: %s", err)
        }
    })

    options := []option.ClientOption{
        option.WithEndpoint(container.URI),
        option.WithoutAuthentication(),
        option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
    }
    dsClient, err := datastore.NewClient(ctx, "test-project", options...)
    if err != nil {
        t.Fatal(err)
    }
    defer dsClient.Close()

    k := datastore.NameKey("Task", "sample", nil)
    data := Task{
        Description: "my description",
    }
    _, err = dsClient.Put(ctx, k, &data)
    if err != nil {
        t.Fatal(err)
    }

    saved := Task{}
    err = dsClient.Get(ctx, k, &saved)
    if err != nil {
        t.Fatal(err)
    }

    // perform assertions
    if saved != data {
        t.Fatalf("Expected value %s. Got %s.", data, saved)
    }
}