Skip to content

Commit

Permalink
docs: extend Couchbase docs (#971)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mdelapenya authored Mar 23, 2023
1 parent 78e86e5 commit 2de5486
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 32 deletions.
106 changes: 91 additions & 15 deletions docs/modules/couchbase.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
```

<!--codeinclude-->
[Start Couchbase](../../modules/couchbase/couchbase_test.go) inside_block:withBucket
<!--/codeinclude-->

2. The **ConnectionString** method returns the connection string to connect to the Couchbase container instance.
It returns a string with the format `couchbase://<host>:<port>`.
The **Username** method returns the username of the Couchbase administrator.
The **Password** method returns the password of the Couchbase administrator.

<!--codeinclude-->
[Connect to Couchbase](../../modules/couchbase/couchbase_test.go) inside_block:connectToCluster
<!--/codeinclude-->

## 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:

<!--codeinclude-->
[Default Docker image](../../modules/couchbase/couchbase.go) inside_block:defaultImage
<!--/codeinclude-->

#### 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.

<!--codeinclude-->
[Adding a new bucket](../../modules/couchbase/couchbase_test.go) inside_block:withBucket
<!--/codeinclude-->

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(),
})
```
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`.

<!--codeinclude-->
[Storage types](../../modules/couchbase/storage_mode.go) inside_block:storageTypes
<!--/codeinclude-->

#### 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.

<!--codeinclude-->
[Docker images](../../modules/couchbase/couchbase_test.go) inside_block:dockerImages
<!--/codeinclude-->

7 changes: 6 additions & 1 deletion modules/couchbase/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -29,20 +31,23 @@ 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
}

b.quota = quota
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
Expand Down
10 changes: 6 additions & 4 deletions modules/couchbase/couchbase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
37 changes: 25 additions & 12 deletions modules/couchbase/couchbase_test.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
package couchbase
package couchbase_test

import (
"context"
"testing"
"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() {
Expand All @@ -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)
}
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -127,3 +138,5 @@ func connectCluster(ctx context.Context, container *CouchbaseContainer) (*gocb.C
Password: container.Password(),
})
}

// }
10 changes: 10 additions & 0 deletions modules/couchbase/options.go
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -12,37 +14,45 @@ 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
c.password = password
}
}

// 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
Expand Down
3 changes: 3 additions & 0 deletions modules/couchbase/storage_mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -20,3 +21,5 @@ const (
// for the community edition.
ForestDB indexStorageMode = "forestdb"
)

// }

0 comments on commit 2de5486

Please sign in to comment.