From 2de5486e359bbf5fc3147087ae5b4f0c69133a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 23 Mar 2023 15:59:07 +0100 Subject: [PATCH] docs: extend Couchbase docs (#971) * chore: use a test package for couchbase * docs: document Couchbase module reference * docs: document bucket * docs: document Options * docs: include enabled services * docs: inline code snippets * chore: properly handle error --- docs/modules/couchbase.md | 106 ++++++++++++++++++++++++---- modules/couchbase/bucket.go | 7 +- modules/couchbase/couchbase.go | 10 +-- modules/couchbase/couchbase_test.go | 37 ++++++---- modules/couchbase/options.go | 10 +++ modules/couchbase/storage_mode.go | 3 + 6 files changed, 141 insertions(+), 32 deletions(-) diff --git a/docs/modules/couchbase.md b/docs/modules/couchbase.md index adc9fc450e..f4307bad43 100644 --- a/docs/modules/couchbase.md +++ b/docs/modules/couchbase.md @@ -18,23 +18,99 @@ go get github.com/testcontainers/testcontainers-go/modules/couchbase It takes a context and zero or more Option values to configure the container. It creates a new container instance, initializes the couchbase cluster, and creates buckets. If successful, it returns the **CouchbaseContainer** instance. -```go -container, err := couchbase.StartContainer(ctx, - WithImageName("couchbase:community-7.1.1"), - WithBucket(NewBucket(bucketName))) -``` + + +[Start Couchbase](../../modules/couchbase/couchbase_test.go) inside_block:withBucket + + 2. The **ConnectionString** method returns the connection string to connect to the Couchbase container instance. It returns a string with the format `couchbase://:`. The **Username** method returns the username of the Couchbase administrator. The **Password** method returns the password of the Couchbase administrator. + + +[Connect to Couchbase](../../modules/couchbase/couchbase_test.go) inside_block:connectToCluster + + +## Module Reference + +The Couchbase module exposes one entrypoint function to create the Couchbase container, and this function receives two parameters: + +```golang +func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, error) +``` + +- `context.Context`, the Go context. +- `Option`, a variad argument for passing options. + +### Container Options + +When starting the Couchbase container, you can pass options in a variadic way to configure it. + +#### Image + +If you need to set a different Couchbase Docker image, you can use `WithImageName` with a valid Docker image +for Couchbase. E.g. `WithImageName("docker.io/couchbase:6.5.1")`. + +By default, the container will use the following Docker image: + + +[Default Docker image](../../modules/couchbase/couchbase.go) inside_block:defaultImage + + +#### Credentials + +If you need to change the default credentials for the admin user, you can use `WithCredentials(user, password)` with a valid username and password. + +!!!info + The default username is `Administrator` and the default password is `password`. + +#### Bucket + +When creating a new Couchbase container, you can create one or more buckets. The module provides a `NewBucket` function to create a new bucket, where +you can pass the bucket name. + + +[Adding a new bucket](../../modules/couchbase/couchbase_test.go) inside_block:withBucket + + +It's possible to customize a newly created bucket, using the following options: + +- `WithQuota`: sets the bucket quota in megabytes. The minimum value is 100 MB. +- `WithReplicas`: sets the number of replicas for this bucket. The minimum value is 0 and the maximum value is 3. +- `WithFlushEnabled`: sets whether the bucket should be flushed when the container is stopped. +- `WithPrimaryIndex`: sets whether the primary index should be created for this bucket. + ```go -connectionString, err := container.ConnectionString(ctx) -if err != nil { - return nil, err -} - -cluster, err := gocb.Connect(connectionString, gocb.ClusterOptions{ - Username: container.Username(), - Password: container.Password(), -}) -``` \ No newline at end of file +bucket := NewBucket( + "bucketName", + WithQuota(100), + WithReplicas(1), + WithFlushEnabled(true), + WithPrimaryIndex(true), +) +``` + +#### Index Storage + +It's possible to set the storage mode to be used for all global secondary indexes in the cluster. + +!!!warning + Please note: `plasma` and `memory optimized` are options in the **Enterprise Edition** of Couchbase Server. If you are using the Community Edition, the only value allowed is `forestdb`. + + +[Storage types](../../modules/couchbase/storage_mode.go) inside_block:storageTypes + + +#### Services + +By default, the container will start with the following services: `kv`, `n1ql`, `fts` and `index`. + +!!!warning + When running the Enterprise Edition of Couchbase Server, the module provides two functions to enable or disable services: + `WithAnalyticsService` and `WithEventingService`. Else, it will throw an error and the container won't be created. + + +[Docker images](../../modules/couchbase/couchbase_test.go) inside_block:dockerImages + + diff --git a/modules/couchbase/bucket.go b/modules/couchbase/bucket.go index cfef779d8c..40b9e91159 100644 --- a/modules/couchbase/bucket.go +++ b/modules/couchbase/bucket.go @@ -8,6 +8,7 @@ type bucket struct { numReplicas int } +// NewBucket creates a new bucket with the given name, using default values for all other fields. func NewBucket(name string) bucket { return bucket{ name: name, @@ -18,6 +19,7 @@ func NewBucket(name string) bucket { } } +// WithReplicas sets the number of replicas for this bucket. The minimum value is 0 and the maximum value is 3. func (b bucket) WithReplicas(numReplicas int) bucket { if numReplicas < 0 { numReplicas = 0 @@ -29,13 +31,15 @@ func (b bucket) WithReplicas(numReplicas int) bucket { return b } +// WithFlushEnabled sets whether the bucket should be flushed when the container is stopped. func (b bucket) WithFlushEnabled(flushEnabled bool) bucket { b.flushEnabled = flushEnabled return b } +// WithQuota sets the bucket quota in megabytes. The minimum value is 100 MB. func (b bucket) WithQuota(quota int) bucket { - if quota < 100 { + if quota < 100 { // Couchbase Server 6.5.0 has a minimum of 100 MB quota = 100 } @@ -43,6 +47,7 @@ func (b bucket) WithQuota(quota int) bucket { return b } +// WithPrimaryIndex sets whether the primary index should be created for this bucket. func (b bucket) WithPrimaryIndex(primaryIndex bool) bucket { b.queryPrimaryIndex = primaryIndex return b diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 6ac6586d8a..63656781a6 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -51,10 +51,12 @@ type CouchbaseContainer struct { // StartContainer creates an instance of the Couchbase container type func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, error) { config := &Config{ - enabledServices: []service{kv, query, search, index}, - username: "Administrator", - password: "password", - imageName: "couchbase:6.5.1", + enabledServices: []service{kv, query, search, index}, + username: "Administrator", + password: "password", + // defaultImage { + imageName: "couchbase:6.5.1", + // } indexStorageMode: MemoryOptimized, } diff --git a/modules/couchbase/couchbase_test.go b/modules/couchbase/couchbase_test.go index 017fa37547..11133c4044 100644 --- a/modules/couchbase/couchbase_test.go +++ b/modules/couchbase/couchbase_test.go @@ -1,4 +1,4 @@ -package couchbase +package couchbase_test import ( "context" @@ -6,21 +6,27 @@ import ( "time" "github.com/couchbase/gocb/v2" + tccouchbase "github.com/testcontainers/testcontainers-go/modules/couchbase" ) +// dockerImages { const ( enterpriseEdition = "couchbase:enterprise-7.1.3" communityEdition = "couchbase:community-7.1.1" ) +// } + func TestCouchbaseWithCommunityContainer(t *testing.T) { ctx := context.Background() + // withBucket { bucketName := "testBucket" - container, err := StartContainer(ctx, WithImageName(communityEdition), WithBucket(NewBucket(bucketName))) + container, err := tccouchbase.StartContainer(ctx, tccouchbase.WithImageName(communityEdition), tccouchbase.WithBucket(tccouchbase.NewBucket(bucketName))) if err != nil { t.Fatal(err) } + // } // Clean up the container after the test is complete t.Cleanup(func() { @@ -41,7 +47,7 @@ func TestCouchbaseWithEnterpriseContainer(t *testing.T) { ctx := context.Background() bucketName := "testBucket" - container, err := StartContainer(ctx, WithImageName(enterpriseEdition), WithBucket(NewBucket(bucketName))) + container, err := tccouchbase.StartContainer(ctx, tccouchbase.WithImageName(enterpriseEdition), tccouchbase.WithBucket(tccouchbase.NewBucket(bucketName))) if err != nil { t.Fatal(err) } @@ -65,10 +71,10 @@ func TestAnalyticsServiceWithCommunityContainer(t *testing.T) { ctx := context.Background() bucketName := "testBucket" - _, err := StartContainer(ctx, - WithImageName(communityEdition), - WithAnalyticsService(), - WithBucket(NewBucket(bucketName))) + _, err := tccouchbase.StartContainer(ctx, + tccouchbase.WithImageName(communityEdition), + tccouchbase.WithAnalyticsService(), + tccouchbase.WithBucket(tccouchbase.NewBucket(bucketName))) if err == nil { t.Errorf("Expected error to be [%v] , got nil", err) @@ -79,10 +85,10 @@ func TestEventingServiceWithCommunityContainer(t *testing.T) { ctx := context.Background() bucketName := "testBucket" - _, err := StartContainer(ctx, - WithImageName(communityEdition), - WithEventingService(), - WithBucket(NewBucket(bucketName))) + _, err := tccouchbase.StartContainer(ctx, + tccouchbase.WithImageName(communityEdition), + tccouchbase.WithEventingService(), + tccouchbase.WithBucket(tccouchbase.NewBucket(bucketName))) if err == nil { t.Errorf("Expected error to be [%v] , got nil", err) @@ -111,12 +117,17 @@ func testBucketUsage(t *testing.T, bucket *gocb.Bucket) { var resultData map[string]string err = result.Content(&resultData) + if err != nil { + t.Fatalf("could not asign content: %s", err) + } + if resultData["key"] != "value" { t.Errorf("Expected value to be [%s], got %s", "value", resultData["key"]) } } -func connectCluster(ctx context.Context, container *CouchbaseContainer) (*gocb.Cluster, error) { +// connectToCluster { +func connectCluster(ctx context.Context, container *tccouchbase.CouchbaseContainer) (*gocb.Cluster, error) { connectionString, err := container.ConnectionString(ctx) if err != nil { return nil, err @@ -127,3 +138,5 @@ func connectCluster(ctx context.Context, container *CouchbaseContainer) (*gocb.C Password: container.Password(), }) } + +// } diff --git a/modules/couchbase/options.go b/modules/couchbase/options.go index 4da15c50e8..81d7db655d 100644 --- a/modules/couchbase/options.go +++ b/modules/couchbase/options.go @@ -1,7 +1,9 @@ package couchbase +// Option is a function that configures the Couchbase container. type Option func(*Config) +// Config is the configuration for the Couchbase container, that will be stored in the container itself. type Config struct { enabledServices []service username string @@ -12,18 +14,23 @@ type Config struct { indexStorageMode indexStorageMode } +// WithEnterpriseService enables the eventing service in the container. +// Only available in the Enterprise Edition of Couchbase Server. func WithEventingService() Option { return func(c *Config) { c.enabledServices = append(c.enabledServices, eventing) } } +// WithAnalyticsService enables the analytics service in the container. +// Only available in the Enterprise Edition of Couchbase Server. func WithAnalyticsService() Option { return func(c *Config) { c.enabledServices = append(c.enabledServices, analytics) } } +// WithCredentials sets the username and password for the administrator user. func WithCredentials(username, password string) Option { return func(c *Config) { c.username = username @@ -31,18 +38,21 @@ func WithCredentials(username, password string) Option { } } +// WithBucket adds a bucket to the container. func WithBucket(bucket bucket) Option { return func(c *Config) { c.buckets = append(c.buckets, bucket) } } +// WithImageName allows to override the default image name. func WithImageName(imageName string) Option { return func(c *Config) { c.imageName = imageName } } +// WithIndexStorageMode sets the storage mode to be used in the cluster. func WithIndexStorageMode(indexStorageMode indexStorageMode) Option { return func(c *Config) { c.indexStorageMode = indexStorageMode diff --git a/modules/couchbase/storage_mode.go b/modules/couchbase/storage_mode.go index 97d521ae3d..2f65886688 100644 --- a/modules/couchbase/storage_mode.go +++ b/modules/couchbase/storage_mode.go @@ -5,6 +5,7 @@ package couchbase // using the Community Edition, the only value allowed is forestdb. type indexStorageMode string +// storageTypes { const ( // MemoryOptimized sets the cluster-wide index storage mode to use memory optimized global // secondary indexes which can perform index maintenance and index scan faster at in-memory speeds. @@ -20,3 +21,5 @@ const ( // for the community edition. ForestDB indexStorageMode = "forestdb" ) + +// }