Documentation
¶
Index ¶
- Constants
- func NewEmulator(ctx context.Context, options ...Option) (emulator *tcspanner.Container, teardown func(), err error)deprecated
- type Clients
- func NewClients(ctx context.Context, emulator *tcspanner.Container, options ...Option) (clients *Clients, teardown func(), err error)deprecated
- func NewEmulatorWithClients(ctx context.Context, options ...Option) (emulator *tcspanner.Container, clients *Clients, teardown func(), err error)deprecated
- func OpenClients(ctx context.Context, emu abstractEmulator, options ...Option) (*Clients, error)
- func SetupClients(tb testing.TB, emu abstractEmulator, options ...Option) *Clients
- type Emulator
- func (e *Emulator) ClientOptions() []option.ClientOption
- func (e *Emulator) Close() error
- func (e *Emulator) Container() *tcspanner.Container
- func (e *Emulator) DatabaseID() string
- func (e *Emulator) DatabasePath() string
- func (e *Emulator) InstanceID() string
- func (e *Emulator) InstancePath() string
- func (e *Emulator) ProjectID() string
- func (e *Emulator) ProjectPath() string
- func (e *Emulator) TestMain(m *testing.M)
- func (e *Emulator) URI() string
- type Env
- type LazyEmulator
- type Option
- func DisableAutoConfig() Option
- func EnableAutoConfig() Option
- func EnableDatabaseAutoConfigOnly() Option
- func EnableFaultInjection() Option
- func EnableInstanceAutoConfigOnly() Option
- func ForceSchemaTeardown() Option
- func SkipSchemaTeardown() Option
- func WithClientConfig(config spanner.ClientConfig) Option
- func WithClientOptionsForClient(option ...option.ClientOption) Option
- func WithContainerCustomizers(containerCustomizers ...testcontainers.ContainerCustomizer) Option
- func WithDatabaseDialect(dialect databasepb.DatabaseDialect) Option
- func WithDatabaseID(databaseID string) Option
- func WithEmulatorImage(image string) Option
- func WithInstanceID(instanceID string) Option
- func WithProjectID(projectID string) Option
- func WithRandomDatabaseID() Option
- func WithRandomInstanceID() Option
- func WithRandomProjectID() Option
- func WithSetupDDLs(ddls []string) Option
- func WithSetupDMLs(dmls []spanner.Statement) Option
- func WithSetupRawDMLs(rawDMLs []string) Option
- func WithStrictTeardown() Optiondeprecated
- func WithoutRandomDatabaseID() Option
- func WithoutRandomInstanceID() Option
- func WithoutRandomProjectID() Option
Examples ¶
Constants ¶
const ( DefaultEmulatorImage = "gcr.io/cloud-spanner-emulator/emulator:1.5.50" DefaultProjectID = "emulator-project" DefaultInstanceID = "emulator-instance" DefaultDatabaseID = "emulator-database" )
Variables ¶
This section is empty.
Functions ¶
func NewEmulator
deprecated
func NewEmulator(ctx context.Context, options ...Option) (emulator *tcspanner.Container, teardown func(), err error)
Deprecated: Use SetupEmulator (for tests) or RunEmulator instead.
NewEmulator initializes Cloud Spanner Emulator. The emulator will be closed when teardown is called. You should call it.
Types ¶
type Clients ¶
type Clients struct {
InstanceClient *instance.InstanceAdminClient
DatabaseClient *database.DatabaseAdminClient
Client *spanner.Client
ProjectID, InstanceID, DatabaseID string
// contains filtered or unexported fields
}
Clients holds Spanner clients and manages the lifecycle of schema resources (instances and databases) auto-created during bootstrap.
By default, auto-created resources with fixed IDs are dropped on Clients.Close, while resources with random IDs are not (since they never collide). Use ForceSchemaTeardown or SkipSchemaTeardown to override.
For RunEmulatorWithClients/SetupEmulatorWithClients, teardown is disabled because the emulator container owns the resource lifecycle; use ForceSchemaTeardown to override.
func NewClients
deprecated
added in
v0.2.0
func NewClients(ctx context.Context, emulator *tcspanner.Container, options ...Option) (clients *Clients, teardown func(), err error)
Deprecated: Use SetupClients (for tests) or OpenClients instead.
NewClients setup existing Cloud Spanner Emulator with Spanner clients. The clients will be closed when teardown is called. You should call it.
Example ¶
package main
import (
"context"
"fmt"
"log"
"cloud.google.com/go/spanner"
"github.com/apstndb/spanemuboost"
)
func main() {
ctx := context.Background()
emulator, emulatorTeardown, err := spanemuboost.NewEmulator(ctx,
spanemuboost.EnableInstanceAutoConfigOnly(),
)
if err != nil {
log.Fatalln(err)
return
}
defer emulatorTeardown()
var pks []int64
for i := range 10 {
func() {
clients, clientsTeardown, err := spanemuboost.NewClients(ctx, emulator,
spanemuboost.EnableDatabaseAutoConfigOnly(),
spanemuboost.WithRandomDatabaseID(),
spanemuboost.WithSetupDDLs([]string{"CREATE TABLE tbl (PK INT64 PRIMARY KEY)"}),
spanemuboost.WithSetupDMLs([]spanner.Statement{
{SQL: "INSERT INTO tbl(PK) VALUES(@i)", Params: map[string]any{"i": i}},
}),
)
if err != nil {
log.Fatalln(err)
return
}
defer clientsTeardown()
err = clients.Client.Single().Query(ctx, spanner.NewStatement("SELECT PK FROM tbl")).Do(func(r *spanner.Row) error {
var pk int64
if err := r.ColumnByName("PK", &pk); err != nil {
return err
}
pks = append(pks, pk)
return nil
})
if err != nil {
log.Fatalln(err)
}
}()
}
fmt.Println(pks)
}
Output: [0 1 2 3 4 5 6 7 8 9]
func NewEmulatorWithClients
deprecated
func NewEmulatorWithClients(ctx context.Context, options ...Option) (emulator *tcspanner.Container, clients *Clients, teardown func(), err error)
Deprecated: Use SetupEmulatorWithClients (for tests) or RunEmulatorWithClients instead.
NewEmulatorWithClients initializes Cloud Spanner Emulator with Spanner clients. The emulator and clients will be closed when teardown is called. You should call it.
Example ¶
package main
import (
"context"
"fmt"
"log"
"cloud.google.com/go/spanner"
"github.com/apstndb/spanemuboost"
)
func main() {
ctx := context.Background()
_, clients, teardown, err := spanemuboost.NewEmulatorWithClients(ctx)
if err != nil {
log.Fatalln(err)
return
}
defer teardown()
err = clients.Client.Single().Query(ctx, spanner.NewStatement("SELECT 1")).Do(func(r *spanner.Row) error {
fmt.Println(r)
return nil
})
if err != nil {
log.Fatalln(err)
}
}
Output: {fields: [type:{code:INT64}], values: [string_value:"1"]}
func OpenClients ¶ added in v0.3.0
OpenClients connects to an existing emulator and opens Spanner clients. The emu parameter accepts both *Emulator and *LazyEmulator. When a *LazyEmulator is passed, the emulator is started automatically on first use. Options inherit the emulator's projectID and instanceID; instance creation is disabled by default (use EnableAutoConfig to override). Call Clients.Close to close the clients when done. In tests, prefer SetupClients which handles cleanup automatically.
Example ¶
package main
import (
"context"
"fmt"
"log"
"cloud.google.com/go/spanner"
"github.com/apstndb/spanemuboost"
)
func main() {
ctx := context.Background()
emu, err := spanemuboost.RunEmulator(ctx,
spanemuboost.EnableInstanceAutoConfigOnly(),
)
if err != nil {
log.Fatalln(err)
return
}
defer emu.Close() //nolint:errcheck
var pks []int64
for i := range 10 {
func() {
clients, err := spanemuboost.OpenClients(ctx, emu,
spanemuboost.WithRandomDatabaseID(),
spanemuboost.WithSetupDDLs([]string{"CREATE TABLE tbl (PK INT64 PRIMARY KEY)"}),
spanemuboost.WithSetupDMLs([]spanner.Statement{
{SQL: "INSERT INTO tbl(PK) VALUES(@i)", Params: map[string]any{"i": i}},
}),
)
if err != nil {
log.Fatalln(err)
return
}
defer clients.Close() //nolint:errcheck
err = clients.Client.Single().Query(ctx, spanner.NewStatement("SELECT PK FROM tbl")).Do(func(r *spanner.Row) error {
var pk int64
if err := r.ColumnByName("PK", &pk); err != nil {
return err
}
pks = append(pks, pk)
return nil
})
if err != nil {
log.Fatalln(err)
}
}()
}
fmt.Println(pks)
}
Output: [0 1 2 3 4 5 6 7 8 9]
func SetupClients ¶ added in v0.3.0
SetupClients opens Spanner clients against an existing emulator and registers cleanup via testing.TB.Cleanup. It calls testing.TB.Fatal on setup error. The emu parameter accepts both *Emulator and *LazyEmulator. When a *LazyEmulator is passed, the emulator is started automatically on first use. Use OpenClients if you need a context.Context or are not in a test.
func (*Clients) ClientOptions ¶ added in v0.3.3
func (c *Clients) ClientOptions() []option.ClientOption
ClientOptions returns the option.ClientOption values used to connect to the emulator. This is useful when callers need to create additional gRPC clients (e.g., with custom interceptors) against the same emulator without holding a separate *Emulator reference.
func (*Clients) Close ¶ added in v0.3.0
Close closes all Spanner clients. By default, auto-created resources with fixed IDs are dropped before the clients are closed. See ForceSchemaTeardown and SkipSchemaTeardown. spanner.Client.Close does not return an error, so only admin client and resource cleanup errors are returned.
func (*Clients) DatabasePath ¶ added in v0.2.2
func (*Clients) InstancePath ¶ added in v0.2.2
func (*Clients) ProjectPath ¶ added in v0.2.2
type Emulator ¶ added in v0.3.0
type Emulator struct {
// contains filtered or unexported fields
}
Emulator wraps a Cloud Spanner Emulator container. Use RunEmulator or SetupEmulator to create one.
func RunEmulator ¶ added in v0.3.0
RunEmulator starts a Cloud Spanner Emulator container and performs any configured bootstrap (instance/database creation, DDL, DML). Call Emulator.Close to terminate the container when done. In tests, prefer SetupEmulator which handles cleanup automatically. In TestMain, use this function since testing.M does not implement testing.TB.
func SetupEmulator ¶ added in v0.3.0
SetupEmulator starts a Cloud Spanner Emulator and registers cleanup via testing.TB.Cleanup. It calls testing.TB.Fatal on setup error. Use RunEmulator if you need a context.Context or are not in a test. Note that testing.M does not implement testing.TB, so use RunEmulator in TestMain.
func (*Emulator) ClientOptions ¶ added in v0.3.0
func (e *Emulator) ClientOptions() []option.ClientOption
ClientOptions returns option.ClientOption values configured for connecting to this emulator (endpoint, insecure credentials, no authentication).
The endpoint uses the passthrough:/// scheme to bypass gRPC name resolution and avoid the slow authentication code path that would otherwise be triggered when grpc.NewClient (dns resolver by default) is used by the auth layer. This mirrors the approach used by the Spanner client library's SPANNER_EMULATOR_HOST handling (googleapis/google-cloud-go#10947), as well as the Bigtable and Datastore SDKs for their emulator paths.
Currently the auth layer uses grpc.DialContext (passthrough by default), so this is a defensive measure for the planned migration to grpc.NewClient.
func (*Emulator) Container ¶ added in v0.3.0
Container returns the underlying *tcspanner.Container for direct access. Most users should use Emulator.URI or Emulator.ClientOptions instead.
func (*Emulator) DatabaseID ¶ added in v0.3.0
DatabaseID returns the database ID configured for this emulator.
func (*Emulator) DatabasePath ¶ added in v0.3.0
DatabasePath returns the database resource path.
func (*Emulator) InstanceID ¶ added in v0.3.0
InstanceID returns the instance ID configured for this emulator.
func (*Emulator) InstancePath ¶ added in v0.3.0
InstancePath returns the instance resource path.
func (*Emulator) ProjectID ¶ added in v0.3.0
ProjectID returns the project ID configured for this emulator.
func (*Emulator) ProjectPath ¶ added in v0.3.0
ProjectPath returns the project resource path.
func (*Emulator) TestMain ¶ added in v0.3.4
TestMain runs m.Run(), closes the emulator, and calls os.Exit with the appropriate code. A close failure is logged and causes a non-zero exit code.
Because TestMain calls os.Exit, it must be the last statement in your TestMain function. If you need additional cleanup, refer to the source of this method and write the logic manually.
Usage in TestMain:
func TestMain(m *testing.M) {
var err error
emulator, err = spanemuboost.RunEmulator(context.Background(),
spanemuboost.EnableInstanceAutoConfigOnly(),
)
if err != nil { log.Fatal(err) }
emulator.TestMain(m)
}
func (*Emulator) URI ¶ added in v0.3.0
URI returns the gRPC endpoint (host:port) of the emulator, suitable for use as SPANNER_EMULATOR_HOST.
In serial tests, you can use testing.T.Setenv to set the environment variable:
t.Setenv("SPANNER_EMULATOR_HOST", emu.URI())
Note that testing.T.Setenv panics if the test or an ancestor has called testing.T.Parallel. Prefer Emulator.ClientOptions when possible.
type Env ¶ added in v0.3.0
type Env struct {
*Clients
// contains filtered or unexported fields
}
Env combines an Emulator with Clients for the single-call use case. Use RunEmulatorWithClients or SetupEmulatorWithClients to create one.
func RunEmulatorWithClients ¶ added in v0.3.0
RunEmulatorWithClients starts a Cloud Spanner Emulator and opens Spanner clients. Call Env.Close to close clients and terminate the container. In tests, prefer SetupEmulatorWithClients which handles cleanup automatically.
Example ¶
package main
import (
"context"
"fmt"
"log"
"cloud.google.com/go/spanner"
"github.com/apstndb/spanemuboost"
)
func main() {
ctx := context.Background()
env, err := spanemuboost.RunEmulatorWithClients(ctx)
if err != nil {
log.Fatalln(err)
return
}
defer env.Close() //nolint:errcheck
err = env.Client.Single().Query(ctx, spanner.NewStatement("SELECT 1")).Do(func(r *spanner.Row) error {
fmt.Println(r)
return nil
})
if err != nil {
log.Fatalln(err)
}
}
Output: {fields: [type:{code:INT64}], values: [string_value:"1"]}
func SetupEmulatorWithClients ¶ added in v0.3.0
SetupEmulatorWithClients starts a Cloud Spanner Emulator with clients and registers cleanup via testing.TB.Cleanup. It calls testing.TB.Fatal on setup error. Use RunEmulatorWithClients if you need a context.Context or are not in a test.
type LazyEmulator ¶ added in v0.3.3
type LazyEmulator struct {
// contains filtered or unexported fields
}
LazyEmulator defers emulator startup until first use. Use NewLazyEmulator in a package-level var, then pass directly to SetupClients or OpenClients. Call LazyEmulator.Setup or LazyEmulator.Get for standalone access. LazyEmulator.Close is safe to call even if the emulator was never started (no-op).
Example ¶
package main
import (
"context"
"fmt"
"log"
"cloud.google.com/go/spanner"
"github.com/apstndb/spanemuboost"
)
func main() {
ctx := context.Background()
lazy := spanemuboost.NewLazyEmulator(
spanemuboost.EnableInstanceAutoConfigOnly(),
)
defer func() {
if err := lazy.Close(); err != nil {
log.Printf("failed to close lazy emulator: %v", err)
}
}()
// OpenClients accepts a *LazyEmulator directly and starts it on first use.
clients, err := spanemuboost.OpenClients(ctx, lazy,
spanemuboost.WithRandomDatabaseID(),
)
if err != nil {
log.Fatalln(err)
return
}
defer func() {
if err := clients.Close(); err != nil {
log.Printf("failed to close clients: %v", err)
}
}()
err = clients.Client.Single().Query(ctx, spanner.NewStatement("SELECT 1")).Do(func(r *spanner.Row) error {
fmt.Println(r)
return nil
})
if err != nil {
log.Fatalln(err)
}
}
Output: {fields: [type:{code:INT64}], values: [string_value:"1"]}
func NewLazyEmulator ¶ added in v0.3.3
func NewLazyEmulator(options ...Option) *LazyEmulator
NewLazyEmulator creates a LazyEmulator that will start an emulator with the given options on first use. The emulator is not started until it is passed to SetupClients, OpenClients, or until LazyEmulator.Setup / LazyEmulator.Get is called directly.
func (*LazyEmulator) Close ¶ added in v0.3.3
func (le *LazyEmulator) Close() error
Close terminates the emulator if it was started. No-op otherwise. Close is idempotent — subsequent calls return the result of the first call. Close waits for any in-progress initialization to complete before checking. If Close is called before any Get or Setup, the emulator will never be started.
func (*LazyEmulator) Get ¶ added in v0.3.3
func (le *LazyEmulator) Get(ctx context.Context) (*Emulator, error)
Get starts the emulator on first call (thread-safe via sync.Once) and returns the cached *Emulator on subsequent calls.
func (*LazyEmulator) Setup ¶ added in v0.3.3
func (le *LazyEmulator) Setup(tb testing.TB) *Emulator
Setup starts the emulator on first call (thread-safe via sync.Once) and returns the cached *Emulator on subsequent calls. It calls testing.TB.Fatal if startup fails. For use with SetupClients or OpenClients, you can pass *LazyEmulator directly without calling Setup.
func (*LazyEmulator) TestMain ¶ added in v0.3.4
func (le *LazyEmulator) TestMain(m *testing.M)
TestMain runs m.Run(), closes the lazy emulator, and calls os.Exit with the appropriate code. A close failure is logged and causes a non-zero exit code. If the emulator was never started, Close is a no-op.
Because TestMain calls os.Exit, it must be the last statement in your TestMain function. If you need additional cleanup, refer to the source of this method and write the logic manually.
Usage in TestMain:
var lazyEmu = spanemuboost.NewLazyEmulator(spanemuboost.EnableInstanceAutoConfigOnly())
func TestMain(m *testing.M) { lazyEmu.TestMain(m) }
type Option ¶
type Option func(*emulatorOptions) error
func DisableAutoConfig ¶
func DisableAutoConfig() Option
DisableAutoConfig disables auto config.(default enable)
func EnableAutoConfig ¶
func EnableAutoConfig() Option
EnableAutoConfig enables auto config.(default enable)
func EnableDatabaseAutoConfigOnly ¶ added in v0.2.0
func EnableDatabaseAutoConfigOnly() Option
func EnableFaultInjection ¶ added in v0.2.5
func EnableFaultInjection() Option
EnableFaultInjection enables fault injection of Cloud Spanner Emulator.
func EnableInstanceAutoConfigOnly ¶ added in v0.2.0
func EnableInstanceAutoConfigOnly() Option
func ForceSchemaTeardown ¶ added in v0.3.2
func ForceSchemaTeardown() Option
ForceSchemaTeardown forces schema resource cleanup on Clients.Close, dropping any auto-created database or instance before closing the Go clients.
By default, schema teardown is enabled for fixed IDs and disabled for random IDs. This option overrides that default for all resources.
func SkipSchemaTeardown ¶ added in v0.3.2
func SkipSchemaTeardown() Option
SkipSchemaTeardown disables schema resource cleanup on Clients.Close. Auto-created databases and instances will not be dropped on close.
By default, schema teardown is enabled for fixed IDs; use this option to opt out.
func WithClientConfig ¶ added in v0.2.0
func WithClientConfig(config spanner.ClientConfig) Option
WithClientConfig sets spanner.ClientConfig for NewClients and NewEmulatorWithClients.
When this option is not used, spanemuboost sets DisableNativeMetrics to true by default, since the Spanner native metrics infrastructure is unnecessary for emulator connections and can add overhead (metadata server lookups, monitoring exporter creation). If you provide a custom spanner.ClientConfig, consider setting DisableNativeMetrics: true explicitly.
func WithClientOptionsForClient ¶ added in v0.2.5
func WithClientOptionsForClient(option ...option.ClientOption) Option
WithClientOptionsForClient configures ClientOption for Clients.Client.
func WithContainerCustomizers ¶ added in v0.2.5
func WithContainerCustomizers(containerCustomizers ...testcontainers.ContainerCustomizer) Option
WithContainerCustomizers sets any testcontainers.ContainerCustomizer
func WithDatabaseDialect ¶
func WithDatabaseDialect(dialect databasepb.DatabaseDialect) Option
WithDatabaseDialect configures the database dialect.
func WithDatabaseID ¶
WithDatabaseID configures the database ID. Empty string resets to default.
func WithEmulatorImage ¶
WithEmulatorImage configures the Spanner Emulator container image. Empty string will be ignored.
func WithInstanceID ¶
WithInstanceID configures the instance ID. Empty string resets to default.
func WithProjectID ¶
WithProjectID configures the project ID. Empty string resets to default.
func WithRandomDatabaseID ¶ added in v0.2.3
func WithRandomDatabaseID() Option
WithRandomDatabaseID enables the random database ID. Default is disabled. This clears any previously set database ID (including inherited values from OpenClients).
Because a random ID will never match an existing database, this option also enables database auto-creation (sets disableCreateDatabase to false). To disable creation again, call DisableAutoConfig after this option.
func WithRandomInstanceID ¶ added in v0.2.4
func WithRandomInstanceID() Option
WithRandomInstanceID enables the random instance ID. Default is disabled. This clears any previously set instance ID (including inherited values from OpenClients).
Because a random ID will never match an existing instance, this option also enables instance auto-creation (sets disableCreateInstance to false). To disable creation again, call DisableAutoConfig after this option.
func WithRandomProjectID ¶ added in v0.2.4
func WithRandomProjectID() Option
WithRandomProjectID enables the random project ID. Default is disabled. This clears any previously set project ID (including inherited values from OpenClients).
func WithSetupDDLs ¶
WithSetupDDLs sets DDLs to be executed. Calling this multiple times replaces the previous value.
func WithSetupDMLs ¶
WithSetupDMLs sets DMLs in spanner.Statement to be executed. Calling this multiple times replaces the previous value. This is mutually exclusive with WithSetupRawDMLs; the last one called wins.
func WithSetupRawDMLs ¶
WithSetupRawDMLs sets string DMLs to be executed. Calling this multiple times replaces the previous value. This is mutually exclusive with WithSetupDMLs; the last one called wins.
func WithStrictTeardown
deprecated
added in
v0.3.0
func WithStrictTeardown() Option
Deprecated: Use ForceSchemaTeardown instead.
func WithoutRandomDatabaseID ¶ added in v0.2.4
func WithoutRandomDatabaseID() Option
WithoutRandomDatabaseID disables the random database ID. Default is disabled.
func WithoutRandomInstanceID ¶ added in v0.2.4
func WithoutRandomInstanceID() Option
WithoutRandomInstanceID disables the random instance ID. Default is disabled.
func WithoutRandomProjectID ¶ added in v0.2.4
func WithoutRandomProjectID() Option
WithoutRandomProjectID disables the random project ID. Default is disabled.