Skip to content

Commit

Permalink
feat: added firebase module
Browse files Browse the repository at this point in the history
  • Loading branch information
xytis committed Jan 30, 2025
1 parent a43edc8 commit 29b1bba
Show file tree
Hide file tree
Showing 18 changed files with 682 additions and 3 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, firebase, 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]
uses: ./.github/workflows/ci-test-go.yml
with:
go-version: ${{ matrix.go-version }}
Expand Down
6 changes: 5 additions & 1 deletion .vscode/.testcontainers-go.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@
"name": "module / etcd",
"path": "../modules/etcd"
},
{
"name": "module / firebase",
"path": "../modules/firebase"
},
{
"name": "module / gcloud",
"path": "../modules/gcloud"
Expand Down Expand Up @@ -214,4 +218,4 @@
"path": "../modulegen"
}
]
}
}
47 changes: 47 additions & 0 deletions docs/modules/firebase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Firebase

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

## Adding this module to your project dependencies

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

```
go get github.com/testcontainers/testcontainers-go/modules/firebase
```

## Usage example

<!--codeinclude-->
[Creating a Firebase container](../../modules/firebase/examples_test.go) inside_block:runFirebaseContainer
<!--/codeinclude-->

## Module reference

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

```golang
func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*FirebaseContainer, error)
```

- `context.Context`, the Go context.
- `testcontainers.ContainerCustomizer`, a variadic argument for passing options.

### Container Options

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

#### Image

If you need to set a different Firebase Docker image, you can use `testcontainers.WithImage` with a valid Docker image
for Firebase. E.g. `testcontainers.WithImage("ghcr.io/thoughtgears/docker-firebase-emulator:13.6.0")`.

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

### Container Methods

The Firebase container exposes the following methods:
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ nav:
- modules/dynamodb.md
- modules/elasticsearch.md
- modules/etcd.md
- modules/firebase.md
- modules/gcloud.md
- modules/grafana-lgtm.md
- modules/inbucket.md
Expand Down
5 changes: 5 additions & 0 deletions modules/firebase/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include ../../commons-test.mk

.PHONY: test
test:
$(MAKE) test-firebase
13 changes: 13 additions & 0 deletions modules/firebase/anchor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package firebase_test

import (
"path/filepath"
"runtime"
)

// BasePath returns the catalog of the module this function resides in
func BasePath() string {
_, b, _, _ := runtime.Caller(0)
base := filepath.Dir(b)
return base
}
41 changes: 41 additions & 0 deletions modules/firebase/examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package firebase_test

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

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

func ExampleRunContainer() {
// runFirebaseContainer {
ctx := context.Background()

firebaseContainer, err := firebase.RunContainer(
ctx,
firebase.WithRoot(filepath.Join(BasePath(), "firebase")),
)
if err != nil {
log.Fatalf("failed to start container: %s", err)
}

// Clean up the container
defer func() {
if err := firebaseContainer.Terminate(ctx); err != nil {
log.Fatalf("failed to terminate container: %s", err) // nolint:gocritic
}
}()
// }

state, err := firebaseContainer.State(ctx)
if err != nil {
log.Fatalf("failed to get container state: %s", err) // nolint:gocritic
}

fmt.Println(state.Running)

// Output:
// true
}
109 changes: 109 additions & 0 deletions modules/firebase/firebase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package firebase

import (
"context"
"fmt"
"strings"
"time"

"github.com/docker/docker/api/types/mount"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

// FirebaseContainer represents the Firebase container type used in the module
type FirebaseContainer struct {
testcontainers.Container
}

const defaultImageName = "ghcr.io/u-health/docker-firebase-emulator:13.6.0"

// WithRoot sets the directory which is copied to the destination container as firebase root
func WithRoot(rootPath string) testcontainers.CustomizeRequestOption {
return func(req *testcontainers.GenericContainerRequest) error {
if !strings.HasSuffix(rootPath, "/firebase") {
return fmt.Errorf("root path must end with '/firebase': %s", rootPath)
}
req.Files = append(req.Files, testcontainers.ContainerFile{
HostFilePath: rootPath,
ContainerFilePath: "/srv/firebase",
})

return nil
}
}

// WithData names the data directory in firebase root
func WithData(dataPath string) testcontainers.CustomizeRequestOption {
return func(req *testcontainers.GenericContainerRequest) error {
req.Env["DATA_DIRECTORY"] = dataPath
return nil
}
}

func cache(volumeName string, volumeOptions *mount.VolumeOptions) testcontainers.CustomizeRequestOption {
return func(req *testcontainers.GenericContainerRequest) error {
m := testcontainers.ContainerMount{
Source: testcontainers.DockerVolumeMountSource{
Name: volumeName,
VolumeOptions: volumeOptions,
},
Target: "/root/.cache/firebase",
}
req.Mounts = append(req.Mounts, m)
return nil
}
}

// WithCache enables firebase binary cache based on session (meaningful only when multiple tests are used)
func WithCache() testcontainers.CustomizeRequestOption {
volumeName := fmt.Sprintf("firestore-cache-%s", testcontainers.SessionID())
volumeOptions := &mount.VolumeOptions{
Labels: testcontainers.GenericLabels(),
}

return cache(volumeName, volumeOptions)
}

// RunContainer creates an instance of the Firebase container type
func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*FirebaseContainer, error) {
req := testcontainers.ContainerRequest{
Image: defaultImageName,
ExposedPorts: []string{
UiPort,
HubPort,
LoggingPort,
FunctionsPort,
FirestorePort,
PubsubPort,
DatabasePort,
AuthPort,
StoragePort,
HostingPort,
},

Env: map[string]string{},
WaitingFor: wait.ForAll(
wait.ForHTTP("/").WithPort(UiPort).WithStartupTimeout(3 * time.Minute),
),
}

genericContainerReq := testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
}

for _, opt := range opts {
if err := opt.Customize(&genericContainerReq); err != nil {
return nil, fmt.Errorf("customize: %w", err)
}
}

container, err := testcontainers.GenericContainer(ctx, genericContainerReq)
if err != nil {
return nil, err
}

return &FirebaseContainer{Container: container}, nil
}
5 changes: 5 additions & 0 deletions modules/firebase/firebase/.firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projects": {
"default": "test"
}
}
37 changes: 37 additions & 0 deletions modules/firebase/firebase/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"emulators": {
"ui": {
"enabled": true,
"port": 4000,
"host": "0.0.0.0"
},
"hub": {
"port": 4400,
"host": "0.0.0.0"
},
"logging": {
"port": 4600,
"host": "0.0.0.0"
},
"firestore": {
"port": 8080,
"host": "0.0.0.0"
},
"auth": {
"port": 9099,
"host": "0.0.0.0"
},
"storage": {
"port": 9199,
"host": "0.0.0.0"
},
"singleProjectMode": true
},
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"storage": {
"rules": "storage.rules"
}
}
4 changes: 4 additions & 0 deletions modules/firebase/firebase/firestore.indexes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"indexes": [],
"fieldOverrides": []
}
9 changes: 9 additions & 0 deletions modules/firebase/firebase/firestore.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}

8 changes: 8 additions & 0 deletions modules/firebase/firebase/storage.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if true;
}
}
}
47 changes: 47 additions & 0 deletions modules/firebase/firebase_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package firebase_test

import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
"time"

"github.com/stretchr/testify/assert"

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

func TestFirebase(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(3*time.Minute))

thing := fmt.Sprintf("%s/test", os.Getenv("PWD"))
fmt.Println(thing)

container, err := firebase.RunContainer(
ctx,
firebase.WithRoot(filepath.Join(BasePath(), "firebase")),
firebase.WithCache(),
)
if err != nil {
t.Fatal(err)
}

// Clean up the container after the test is complete
t.Cleanup(func() {
if err := container.Terminate(ctx); err != nil {
t.Fatalf("failed to terminate container: %s", err)
}
cancel()
})

// perform assertions
firestoreUrl, err := container.FirestoreConnectionString(ctx)
assert.NoError(t, err)
assert.NotEmpty(t, firestoreUrl)

authUrl, err := container.AuthConnectionString(ctx)
assert.NoError(t, err)
assert.NotEmpty(t, authUrl)
}
Loading

0 comments on commit 29b1bba

Please sign in to comment.