Skip to content

New easymongotest subpackage wrapping mongotest/v2 #7

Description

@TopherGopher

Part of the easymongo refactor (see PLAN.md on the refactor branch). This is where the helpers that used to live in mongotest (EasyMongoWithContainer, the TestConnection that embedded *easymongo.Connection) now live, so the module dependency is one-way: easymongo depends on mongotest, never the reverse.

Working context (read this first)

Scope

Package github.com/tophergopher/easymongo/easymongotest inside the easymongo module (a subpackage, not a separate module), requiring github.com/tophergopher/mongotest/v2:

type TestConnection struct {
    *easymongo.Connection
    Mongo *mongotest.Instance   // the underlying mongotest/v2 instance (container + driver client)
}

func Start(ctx context.Context, opts ...mongotest.Option) (*TestConnection, error)
func Run(tb testing.TB, opts ...mongotest.Option) *TestConnection   // tb.Fatal on error, tb.Cleanup(Stop)
func (tc *TestConnection) Stop(ctx context.Context) error            // Disconnect easymongo, then Mongo.Stop

// Convenience wrappers migrated from mongotest, documented as plain wrappers (not deprecated):
func NewTestConnection(spinupDockerContainer bool) (*TestConnection, error)
func (tc *TestConnection) KillMongoContainer() error
func WithContainer(f func(*easymongo.Connection) error) error         // was mongotest.EasyMongoWithContainer
  • Start builds the easymongo connection with easymongo.ConnectWith(inst.URI()), applying .TLSConfig(inst.Container.TLSConfig()) when the instance is in TLS mode, then .Connect(). Because easymongo caches the last connection globally, Start documents that side effect.
  • Because this is a subpackage of the easymongo module, github.com/tophergopher/mongotest/v2 becomes a regular requirement in easymongo's go.mod. It is small (driver v2 plus the root mongotest module) and is only compiled by importers of easymongotest. Document this in the package doc.
  • Package doc with a full example test.

Implementation details

Files: easymongotest/doc.go, easymongotest/easymongotest.go, easymongotest/compat.go (the migrated wrappers), easymongotest/easymongotest_test.go, easymongotest/example_test.go.

Import of the container library: mongotest "github.com/tophergopher/mongotest/v2". Until that module is tagged, go.mod gets replace github.com/tophergopher/mongotest/v2 => ../mongotest/v2 (a sibling checkout of the mongotest repo on its refactor branch); this is temporary and removed by #10.

Only these members of mongotest.Instance / mongod.Container are used here: Start(ctx, opts...), Run(tb, opts...), inst.URI(), inst.Container (may be nil for attached instances), inst.Container.TLSConfig() (nil when TLS is off), inst.Stop(ctx). easymongo itself may still be on driver v1 when this lands; that is fine because none of the driver types of mongotest's embedded client are touched here.

func Start(ctx context.Context, opts ...mongotest.Option) (*TestConnection, error) {
    inst, err := mongotest.Start(ctx, opts...)
    if err != nil { return nil, err }
    b := easymongo.ConnectWith(inst.URI())
    if inst.Container != nil && inst.Container.TLSConfig() != nil { b = b.TLSConfig(inst.Container.TLSConfig()) }
    conn, err := b.Connect()
    if err != nil { _ = inst.Stop(ctx); return nil, err }
    return &TestConnection{Connection: conn, Mongo: inst}, nil
}
func Run(tb testing.TB, opts ...mongotest.Option) *TestConnection {
    tb.Helper()
    tc, err := Start(context.Background(), opts...)
    if err != nil { tb.Fatalf("easymongotest: %v", err) }
    tb.Cleanup(func() { _ = tc.Stop(context.Background()) })
    return tc
}

Stop calls Connection.Disconnect (from #6; if #6 has not landed, call MongoDriverClient().Disconnect(ctx) directly) and then Mongo.Stop(ctx), and is idempotent.

To verify in a test that the container is gone after WithContainer, build a client with github.com/tophergopher/mongotest/dockerapi and check the error with the shared helper in github.com/tophergopher/mongotest/dockerclient: c, _ := dockerapi.FromEnv(); _, err := c.ContainerInspect(ctx, id); require.True(t, dockerclient.IsNotFound(err), "the container must be gone once WithContainer returns"). The Docker client is an interface (dockerclient.Client) with dockerapi as the default implementation; dockerapi.IsNotFound still exists as an alias, but new code should name dockerclient.

Tests first (easymongotest/easymongotest_test.go, integration against Docker)

  • Run(t) then conn.D("db").C("c").Insert().One(...) and Find(...).One(...) round-trip.
  • WithContainer runs the callback and the container is gone afterwards (capture Mongo.Container.ID() through a pointer, then inspect it with a dockerapi client and assert dockerclient.IsNotFound).
  • NewTestConnection(true) then KillMongoContainer() works; KillMongoContainer twice returns nil.
  • TLS: Run(t, mongotest.WithTLS()) inserts and reads.
  • Replica set: Run(t, mongotest.WithReplicaSet("rs0")) and a simple insert succeed.

Acceptance

  • go test ./easymongotest/... passes against Docker.
  • Importing only github.com/tophergopher/easymongo in a scratch program does not compile any mongotest, dockerclient, dockerapi or dockermock package (go list -deps).

Depends on: TopherGopher/mongotest#42 (use the local replace described above until it is tagged). Does not depend on any driver v2 change in this repository.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions