Skip to content

Commit 751e94a

Browse files
authored
feat(aerospike): add Aerospike module (#3094)
* Implemented Aerospike Test Container * Removed unnecessary code and added doc * added suggested changes * fixed suggested changes * fixed lint and suggested changes * added client example in read me * Removed terminate and used CleanupContainer * fixed read me file * fixed code snippet render issue in docs * fixed suggested changes * removed unnecessary testcases and reverted log
1 parent 0c9dfe7 commit 751e94a

File tree

9 files changed

+584
-0
lines changed

9 files changed

+584
-0
lines changed

.github/dependabot.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ updates:
1616
- /examples/nginx
1717
- /examples/toxiproxy
1818
- /modulegen
19+
- /modules/aerospike
1920
- /modules/arangodb
2021
- /modules/artemis
2122
- /modules/azure

docs/modules/aerospike.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Aerospike
2+
3+
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>
4+
5+
## Introduction
6+
7+
The Testcontainers module for Aerospike.
8+
9+
## Adding this module to your project dependencies
10+
11+
Please run the following command to add the Aerospike module to your Go dependencies:
12+
13+
```
14+
go get github.com/testcontainers/testcontainers-go/modules/aerospike
15+
```
16+
17+
## Usage example
18+
19+
<!--codeinclude-->
20+
[Creating a Aerospike container](../../modules/aerospike/examples_test.go) inside_block:runAerospikeContainer
21+
<!--/codeinclude-->
22+
23+
## Module Reference
24+
25+
### Run function
26+
27+
- 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>
28+
29+
The Aerospike module exposes one entrypoint function to create the Aerospike container, and this function receives three parameters:
30+
31+
```golang
32+
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*AerospikeContainer, error)
33+
```
34+
35+
- `context.Context`, the Go context.
36+
- `string`, the Docker image to use.
37+
- `testcontainers.ContainerCustomizer`, a variadic argument for passing options.
38+
39+
### Container Options
40+
41+
When starting the Aerospike container, you can pass options in a variadic way to configure it.
42+
43+
#### Image
44+
45+
Use the second argument in the `Run` function to set a valid Docker image.
46+
In example: `Run(context.Background(), "aerospike/aerospike-server:latest")`.
47+
48+
{% include "../features/common_functional_options.md" %}
49+
50+
## Examples
51+
52+
### Aerospike Client
53+
54+
<!--codeinclude-->
55+
[Aerospike Client](../../modules/aerospike/examples_test.go) inside_block:usingClient
56+
<!--/codeinclude-->

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ nav:
6868
- Walk: features/wait/walk.md
6969
- Modules:
7070
- modules/index.md
71+
- modules/aerospike.md
7172
- modules/arangodb.md
7273
- modules/artemis.md
7374
- modules/azure.md

modules/aerospike/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
include ../../commons-test.mk
2+
3+
.PHONY: test
4+
test:
5+
$(MAKE) test-aerospike

modules/aerospike/aerospike.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package aerospike
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/testcontainers/testcontainers-go"
9+
"github.com/testcontainers/testcontainers-go/wait"
10+
)
11+
12+
const (
13+
// port is the port used for client connections
14+
port = "3000/tcp"
15+
// fabricPort is the port used for Intra-cluster communication port.
16+
// Replica writes, migrations, and other node-to-node communications use the Fabric port.
17+
fabricPort = "3001/tcp"
18+
// heartbeatPort is the port used for heartbeat communication
19+
// between nodes in the Aerospike cluster
20+
heartbeatPort = "3002/tcp"
21+
// infoPort is the port used for info commands
22+
infoPort = "3003/tcp"
23+
)
24+
25+
// Container is the Aerospike container type used in the module
26+
type Container struct {
27+
testcontainers.Container
28+
}
29+
30+
// Run creates an instance of the Aerospike container type
31+
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) {
32+
req := testcontainers.ContainerRequest{
33+
Image: img,
34+
ExposedPorts: []string{port, fabricPort, heartbeatPort, infoPort},
35+
Env: map[string]string{
36+
"AEROSPIKE_CONFIG_FILE": "/etc/aerospike/aerospike.conf",
37+
},
38+
WaitingFor: wait.ForAll(
39+
wait.ForLog("migrations: complete"),
40+
wait.ForListeningPort(port).WithStartupTimeout(10*time.Second),
41+
wait.ForListeningPort(fabricPort).WithStartupTimeout(10*time.Second),
42+
wait.ForListeningPort(heartbeatPort).WithStartupTimeout(10*time.Second),
43+
),
44+
}
45+
46+
genericContainerReq := testcontainers.GenericContainerRequest{
47+
ContainerRequest: req,
48+
Started: true,
49+
}
50+
51+
for _, opt := range opts {
52+
if err := opt.Customize(&genericContainerReq); err != nil {
53+
return nil, fmt.Errorf("customize: %w", err)
54+
}
55+
}
56+
57+
container, err := testcontainers.GenericContainer(ctx, genericContainerReq)
58+
var c *Container
59+
if container != nil {
60+
c = &Container{Container: container}
61+
}
62+
63+
if err != nil {
64+
return c, fmt.Errorf("generic container: %w", err)
65+
}
66+
67+
return c, nil
68+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package aerospike_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/testcontainers/testcontainers-go"
11+
"github.com/testcontainers/testcontainers-go/modules/aerospike"
12+
)
13+
14+
const (
15+
aerospikeImage = "aerospike/aerospike-server:latest"
16+
)
17+
18+
// TestAerospike tests the Aerospike container functionality
19+
// It includes tests for starting the container with a valid image,
20+
// applying container customizations, and handling context cancellation.
21+
// It also includes a test for an invalid image to ensure proper error handling.
22+
// The tests use the testcontainers-go library to manage container lifecycle
23+
func TestAeroSpike(t *testing.T) {
24+
t.Run("valid-image-succeeds", func(t *testing.T) {
25+
ctx := context.Background()
26+
container, err := aerospike.Run(ctx, aerospikeImage)
27+
testcontainers.CleanupContainer(t, container)
28+
require.NoError(t, err)
29+
require.NotNil(t, container)
30+
})
31+
32+
t.Run("applies-container-customizations", func(t *testing.T) {
33+
ctx := context.Background()
34+
customEnv := "TEST_ENV=value"
35+
container, err := aerospike.Run(ctx, aerospikeImage,
36+
testcontainers.WithEnv(map[string]string{"CUSTOM_ENV": customEnv}))
37+
testcontainers.CleanupContainer(t, container)
38+
require.NoError(t, err)
39+
require.NotNil(t, container)
40+
})
41+
42+
t.Run("respects-context-cancellation", func(t *testing.T) {
43+
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
44+
defer cancel()
45+
container, err := aerospike.Run(ctx, aerospikeImage)
46+
testcontainers.CleanupContainer(t, container)
47+
require.Error(t, err)
48+
})
49+
}

modules/aerospike/examples_test.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package aerospike_test
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"time"
8+
9+
aero "github.com/aerospike/aerospike-client-go/v8"
10+
11+
"github.com/testcontainers/testcontainers-go"
12+
"github.com/testcontainers/testcontainers-go/modules/aerospike"
13+
)
14+
15+
func ExampleRun() {
16+
// runAerospikeContainer {
17+
ctx := context.Background()
18+
19+
aerospikeContainer, err := aerospike.Run(ctx, "aerospike/aerospike-server:latest")
20+
defer func() {
21+
if err := testcontainers.TerminateContainer(aerospikeContainer); err != nil {
22+
log.Printf("failed to terminate container: %s", err)
23+
}
24+
}()
25+
if err != nil {
26+
log.Printf("failed to start container: %s", err)
27+
return
28+
}
29+
// }
30+
state, err := aerospikeContainer.State(ctx)
31+
if err != nil {
32+
log.Printf("failed to get container state: %s", err)
33+
return
34+
}
35+
36+
fmt.Println(state.Running)
37+
38+
// Output:
39+
// true
40+
}
41+
42+
func ExampleRun_usingClient() {
43+
ctx := context.Background()
44+
45+
aerospikeContainer, err := aerospike.Run(
46+
ctx, "aerospike/aerospike-server:latest",
47+
)
48+
defer func() {
49+
if err := testcontainers.TerminateContainer(aerospikeContainer); err != nil {
50+
log.Printf("failed to terminate container: %s", err)
51+
}
52+
}()
53+
if err != nil {
54+
log.Printf("failed to start container: %s", err)
55+
return
56+
}
57+
58+
// Get the host and port
59+
host, err := aerospikeContainer.Host(ctx)
60+
if err != nil {
61+
log.Printf("failed to get container host: %s", err)
62+
return
63+
}
64+
65+
// Get the mapped port
66+
port, err := aerospikeContainer.MappedPort(ctx, "3000/tcp")
67+
if err != nil {
68+
log.Printf("failed to get container port: %s", err)
69+
return
70+
}
71+
72+
aeroHost := []*aero.Host{aero.NewHost(host, port.Int())}
73+
74+
// connect to the host
75+
cp := aero.NewClientPolicy()
76+
cp.Timeout = 10 * time.Second
77+
78+
// Create a client
79+
client, err := aero.NewClientWithPolicyAndHost(cp, aeroHost...)
80+
if err != nil {
81+
log.Printf("Failed to create aerospike client: %v", err)
82+
return
83+
}
84+
85+
// Close the client
86+
defer client.Close()
87+
88+
// Create a key
89+
schemaKey, err := aero.NewKey("test", "test", "_schema_info")
90+
if err != nil {
91+
log.Printf("Failed to create key: %v", err)
92+
return
93+
}
94+
95+
version := 1
96+
description := "test aerospike schema info"
97+
nowStr := time.Now().Format(time.RFC3339)
98+
99+
// Create schema record
100+
bins := aero.BinMap{
101+
"version": version,
102+
"created_at": nowStr,
103+
"updated_at": nowStr,
104+
"description": description,
105+
}
106+
107+
// Never expire the schema info
108+
writePolicy := aero.NewWritePolicy(0, 0)
109+
110+
// Store in Aerospike
111+
err = client.Put(writePolicy, schemaKey, bins)
112+
if err != nil {
113+
log.Printf("Failed to put schema info: %v", err)
114+
return
115+
}
116+
117+
// Get schema record
118+
record, err := client.Get(nil, schemaKey, "version", "created_at", "updated_at", "description")
119+
if err != nil {
120+
log.Printf("Failed to get schema info: %v", err)
121+
return
122+
}
123+
124+
// Schema exists, check version
125+
existingVersion, _ := record.Bins["version"].(int)
126+
existingDescription, _ := record.Bins["description"].(string)
127+
128+
fmt.Println(existingVersion)
129+
fmt.Println(existingDescription)
130+
131+
// Output:
132+
// 1
133+
// test aerospike schema info
134+
}

0 commit comments

Comments
 (0)