-
-
Notifications
You must be signed in to change notification settings - Fork 584
feat: added firebase module #2954
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
29b1bba
6a88123
4105b0a
cc2bfa4
7c24032
bc68bb3
bc33438
1a72008
c2b8e2b
ba0bdc0
80298e5
4e271db
34409eb
fb2c0aa
88cb16d
aa4c29c
458cc7c
ae27c74
ae49941
cff37d9
9fe4988
3ed1839
d578817
72c1f45
fd6035e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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")`. | ||
mdelapenya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| {% include "../features/common_functional_options.md" %} | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. docsd: we need to add here all the functional options for the module. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @xytis let's not forget adding the WithData option here 🙏 |
||
| ### Container Methods | ||
|
|
||
| The Firebase container exposes the following methods: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. docs: we probably need to append here the new methods the container expose There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @xytis let's not forget adding here |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| include ../../commons-test.mk | ||
|
|
||
| .PHONY: test | ||
| test: | ||
| $(MAKE) test-firebase |
| 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 { | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| _, b, _, _ := runtime.Caller(0) | ||
| base := filepath.Dir(b) | ||
| return base | ||
| } | ||
| 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")), | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) | ||
| if err != nil { | ||
| log.Fatalf("failed to start container: %s", err) | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Clean up the container | ||
| defer func() { | ||
| if err := firebaseContainer.Terminate(ctx); err != nil { | ||
| log.Fatalf("failed to terminate container: %s", err) // nolint:gocritic | ||
| } | ||
| }() | ||
| // } | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| 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 | ||
| } | ||
| 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.29.2" | ||
|
|
||
| // 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 { | ||
mdelapenya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return func(req *testcontainers.GenericContainerRequest) error { | ||
| req.Env["DATA_DIRECTORY"] = dataPath | ||
stevenh marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return nil | ||
| } | ||
| } | ||
|
|
||
| func cache(volumeName string, volumeOptions *mount.VolumeOptions) testcontainers.CustomizeRequestOption { | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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) | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return &FirebaseContainer{Container: container}, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "projects": { | ||
| "default": "test" | ||
| } | ||
| } |
| 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" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "indexes": [], | ||
| "fieldOverrides": [] | ||
| } |
| 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; | ||
| } | ||
| } | ||
| } | ||
|
|
| 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; | ||
| } | ||
| } | ||
| } |
| 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)) | ||
xytis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| thing := fmt.Sprintf("%s/test", os.Getenv("PWD")) | ||
| fmt.Println(thing) | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| container, err := firebase.RunContainer( | ||
| ctx, | ||
| firebase.WithRoot(filepath.Join(BasePath(), "firebase")), | ||
| firebase.WithCache(), | ||
| ) | ||
| if err != nil { | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| t.Fatal(err) | ||
| } | ||
|
|
||
| // Clean up the container after the test is complete | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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) | ||
xytis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| assert.NotEmpty(t, firestoreUrl) | ||
|
|
||
| authUrl, err := container.AuthConnectionString(ctx) | ||
| assert.NoError(t, err) | ||
| assert.NotEmpty(t, authUrl) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.