Skip to content

Commit

Permalink
Merge pull request #1 from basementdevs/feat/scylladb
Browse files Browse the repository at this point in the history
feat(scylladb): Adding ScyllaDB as a Container Provider
  • Loading branch information
danielhe4rt authored Dec 13, 2024
2 parents 83b47ca + 0b3064d commit 9d50ec1
Show file tree
Hide file tree
Showing 12 changed files with 1,059 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
matrix:
go-version: [1.22.x, 1.x]
platform: [ubuntu-latest]
module: [artemis, azurite, cassandra, chroma, clickhouse, cockroachdb, compose, consul, couchbase, databend, dolt, dynamodb, elasticsearch, etcd, gcloud, grafana-lgtm, inbucket, influxdb, k3s, k6, kafka, localstack, mariadb, meilisearch, milvus, minio, mockserver, mongodb, mssql, mysql, nats, neo4j, ollama, openfga, openldap, opensearch, postgres, pulsar, qdrant, rabbitmq, redis, redpanda, registry, surrealdb, valkey, vault, vearch, weaviate, yugabytedb]
module: [artemis, azurite, cassandra, chroma, clickhouse, cockroachdb, compose, consul, couchbase, databend, dolt, dynamodb, elasticsearch, etcd, gcloud, grafana-lgtm, inbucket, influxdb, k3s, k6, kafka, localstack, mariadb, meilisearch, milvus, minio, mockserver, mongodb, mssql, mysql, nats, neo4j, ollama, openfga, openldap, opensearch, postgres, pulsar, qdrant, rabbitmq, redis, redpanda, registry, scylladb, surrealdb, valkey, vault, vearch, weaviate, yugabytedb]
uses: ./.github/workflows/ci-test-go.yml
with:
go-version: ${{ matrix.go-version }}
Expand Down
4 changes: 4 additions & 0 deletions .vscode/.testcontainers-go.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@
"name": "module / registry",
"path": "../modules/registry"
},
{
"name": "module / scylladb",
"path": "../modules/scylladb"
},
{
"name": "module / surrealdb",
"path": "../modules/surrealdb"
Expand Down
131 changes: 131 additions & 0 deletions docs/modules/scylladb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# ScyllaDB

Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

## Introduction

The Testcontainers module for ScyllaDB, a NoSQL database fully compatible with Apache Cassandra and DynamoDB, allows you
to create a ScyllaDB container for testing purposes.

## Adding this module to your project dependencies

Please run the following command to add the ScyllaDB module to your Go dependencies:

```shell
go get github.com/testcontainers/testcontainers-go/modules/scylladb
```

## Usage example

<!--codeinclude-->
[Creating a ScyllaDB container](../../modules/scylladb/examples_test.go) inside_block:ExampleRun
<!--/codeinclude-->

## Module Reference

### Run function

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

The ScyllaDB module exposes one entrypoint function to create the ScyllaDB container, and this function receives three parameters:

```golang
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*ScyllaDBContainer, error)
```

- `context.Context`, the Go context.
- `string`, the Docker image to use.
- `testcontainers.ContainerCustomizer`, a variadic argument for passing options.

!!! info
By default, we add the `--developer-mode=1` flag to the ScyllaDB container to disable the various checks Scylla
performs.
Also In scenarios in which static partitioning is not desired - like mostly-idle cluster without hard latency
requirements, the --overprovisioned command-line option is recommended. This enables certain optimizations for ScyllaDB
to run efficiently in an overprovisioned environment. You can change it by using the `WithCustomCommand` function.

### Container Options

When starting the ScyllaDB container, you can pass options in a variadic way to configure it.

#### Image

If you need to set a different ScyllaDB Docker image, you can set a valid Docker image as the second argument in the
`Run` function. Eg:

```golang
scylladb.Run(context.Background(), "scylladb/scylla:6.2.1")
// OR
scylladb.Run(context.Background(), "scylladb/scylla:5.6")
```

{% include "../features/common_functional_options.md" %}

#### With Database Configuration File (scylla.yaml)

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

In the case you have a custom config file for ScyllaDB, it's possible to copy that file into the container before it's
started, using the `WithConfigFile(cfgPath string)` function.

<!--codeinclude-->
[With Config YAML](../../modules/scylladb/examples_test.go) inside_block:runScyllaDBContainerWithConfigFile
<!--/codeinclude-->
!!!warning
You should provide a valid ScyllaDB configuration file when using the function, otherwise the container will fail to
start. The configuration file should be a valid YAML file and follows
the [ScyllaDB configuration file](https://github.com/scylladb/scylladb/blob/master/conf/scylla.yaml).

#### With Shard Awareness

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you want to test ScyllaDB with shard awareness, you can use the `WithShardAwareness` function. This function will
configure the ScyllaDB container to use the `19042` port and ask the container to wait until the port is ready.

<!--codeinclude-->
[With Shard Awareness](../../modules/scylladb/examples_test.go) inside_block:runScyllaDBContainerWithShardAwareness
<!--/codeinclude-->

#### With Alternator (DynamoDB Compatible API)

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you want to test ScyllaDB with the Alternator API, you can use the `WithAlternator` function. This function will
configure the ScyllaDB container to use the port any port you want and ask the container to wait until the port is
ready.
By default, you can choose the port `8000`.

<!--codeinclude-->
[With Alternator API](../../modules/scylladb/examples_test.go) inside_block:runScyllaDBContainerWithAlternator
<!--/codeinclude-->

#### With Custom Commands

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

If you need to pass any flag to the ScyllaDB container, you can use the `WithCustomCommand` function. This also rewrites
predefined commands like `--developer-mode=1`. You can check
the [ScyllaDB Docker Best Practices](https://opensource.docs.scylladb.com/stable/operating-scylla/procedures/tips/best-practices-scylla-on-docker.html) for more information.

<!--codeinclude-->
[With Custom Commands](../../modules/scylladb/examples_test.go) inside_block:runScyllaDBContainerWithCustomCommands
<!--/codeinclude-->

### Container Methods

The ScyllaDB container exposes the following methods:

#### ConnectionHost

- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>

This method returns the host and port of the ScyllaDB container, depending on the feature you want.
If you just want to test it with a single node and a single core, you can use port `9042`. However, if you're planning
to
more than one core, you should use the **shard-awareness** port `19042`. If you're planning to use the **Alternator**?
API, you should use the port you select in the `WithAlternator` function.

<!--codeinclude-->
[Get connection host](../../modules/scylladb/examples_test.go) inside_block:BaseConnectionHost
<!--/codeinclude-->
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ nav:
- modules/redis.md
- modules/redpanda.md
- modules/registry.md
- modules/scylladb.md
- modules/surrealdb.md
- modules/valkey.md
- modules/vault.md
Expand Down
5 changes: 5 additions & 0 deletions modules/scylladb/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include ../../commons-test.mk

.PHONY: test
test:
$(MAKE) test-scylladb
226 changes: 226 additions & 0 deletions modules/scylladb/examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package scylladb_test

import (
"context"
"fmt"
"log"
"path/filepath"

"github.com/gocql/gocql"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/scylladb"
)

func ExampleRun_withCustomCommands() {
ctx := context.Background()

// runScyllaDBContainerWithCustomCommands {
scyllaContainer, err := scylladb.Run(ctx,
"scylladb/scylla:6.2",
scylladb.WithCustomCommand("--memory", "1G"),
scylladb.WithCustomCommand("--smp", "2"),
)
// }
defer func() {
if err := testcontainers.TerminateContainer(scyllaContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}

state, err := scyllaContainer.State(ctx)
if err != nil {
log.Printf("failed to get container state: %s", err)
return
}

fmt.Println(state.Running)

connectionHost, err := scyllaContainer.ConnectionHost(ctx, 9042) // Non ShardAwareness port
if err != nil {
log.Printf("failed to get connection host: %s", err)
return
}

runGoCQLExampleTest(connectionHost)

// Output:
// true
}

func ExampleRun_withAlternator() {
ctx := context.Background()

// runScyllaDBContainerWithAlternator {
scyllaContainer, err := scylladb.Run(ctx,
"scylladb/scylla:6.2",
scylladb.WithAlternator(8000), // Choose which port to use on Alternator
)
// }
defer func() {
if err := testcontainers.TerminateContainer(scyllaContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}

state, err := scyllaContainer.State(ctx)
if err != nil {
log.Printf("failed to get container state: %s", err)
return
}

fmt.Println(state.Running)

connectionHost, err := scyllaContainer.ConnectionHost(ctx, 8080) // Alternator port
if err != nil {
log.Printf("failed to get connection host: %s", err)
return
}

runGoCQLExampleTest(connectionHost)

// Output:
// true
}

func ExampleRun_withShardAwareness() {
ctx := context.Background()

// runScyllaDBContainerWithShardAwareness {
scyllaContainer, err := scylladb.Run(ctx,
"scylladb/scylla:6.2",
scylladb.WithShardAwareness(),
)
// }
defer func() {
if err := testcontainers.TerminateContainer(scyllaContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}

state, err := scyllaContainer.State(ctx)
if err != nil {
log.Printf("failed to get container state: %s", err)
return
}

fmt.Println(state.Running)

connectionHost, err := scyllaContainer.ConnectionHost(ctx, 19042) // ShardAwareness port
if err != nil {
log.Printf("failed to get connection host: %s", err)
return
}

runGoCQLExampleTest(connectionHost)

// Output:
// true
}

func ExampleRun_withConfigFile() {
ctx := context.Background()

// runScyllaDBContainerWithConfigFile {
scyllaContainer, err := scylladb.Run(ctx,
"scylladb/scylla:6.2",
scylladb.WithConfigFile(filepath.Join("testdata", "scylla.yaml")),
)
// }
defer func() {
if err := testcontainers.TerminateContainer(scyllaContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
// }

state, err := scyllaContainer.State(ctx)
if err != nil {
log.Printf("failed to get container state: %s", err)
return
}

fmt.Println(state.Running)

connectionHost, err := scyllaContainer.ConnectionHost(ctx, 9042) // Non ShardAwareness port
if err != nil {
log.Printf("failed to get connection host: %s", err)
return
}

runGoCQLExampleTest(connectionHost)

// Output:
// true
}

func ExampleRun() {
// runBaseScyllaDBContainer {
ctx := context.Background()

scyllaContainer, err := scylladb.Run(ctx,
"scylladb/scylla:6.2",
scylladb.WithShardAwareness(),
)
defer func() {
if err := testcontainers.TerminateContainer(scyllaContainer); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Printf("failed to start container: %s", err)
return
}
// }

state, err := scyllaContainer.State(ctx)
if err != nil {
log.Printf("failed to get container state: %s", err)
return
}

fmt.Println(state.Running)

// BaseConnectionHost {
connectionHost, err := scyllaContainer.ConnectionHost(ctx, 9042)
// }
if err != nil {
log.Printf("failed to get connection host: %s", err)
return
}
runGoCQLExampleTest(connectionHost)

// Output:
// true
}

func runGoCQLExampleTest(connectionHost string) {
cluster := gocql.NewCluster(connectionHost)
session, err := cluster.CreateSession()
if err != nil {
log.Printf("failed to create session: %s", err)
}
defer session.Close()

var driver string
err = session.Query("SELECT driver_name FROM system.clients").Scan(&driver)
if err != nil {
log.Printf("failed to query: %s", err)
}
}
Loading

0 comments on commit 9d50ec1

Please sign in to comment.