Skip to content
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

firestore: Provide function to configure emulator #1978

Closed
joshlf opened this issue May 9, 2020 · 8 comments
Closed

firestore: Provide function to configure emulator #1978

joshlf opened this issue May 9, 2020 · 8 comments
Assignees
Labels
api: firestore Issues related to the Firestore API. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@joshlf
Copy link

joshlf commented May 9, 2020

Is your feature request related to a problem? Please describe.
I'm writing unit tests to exercise code which connects to Firestore. What would be really nice is to have an in-process mock for testing. However, barring that, it's sufficient to run the Firestore emulator as a subprocess, and connect to it from unit tests.

However, the only officially supported way to connect to an emulator is to set the FIRESTORE_EMULATOR_HOST environment variable. Even if I were to do something like os.Setenv("FIRESTORE_EMULATOR_HOST", ...), that would mean that I couldn't run tests in parallel with different emulators, as the environment variable is global.

What I've resorted to instead is to adapt the logic that is used internally here:

// If this environment variable is defined, configure the client to talk to the emulator.
if addr := os.Getenv("FIRESTORE_EMULATOR_HOST"); addr != "" {
conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithPerRPCCredentials(emulatorCreds{}))
if err != nil {
return nil, fmt.Errorf("firestore: dialing address from env var FIRESTORE_EMULATOR_HOST: %s", err)
}
o = []option.ClientOption{option.WithGRPCConn(conn)}
}

and here:

// emulatorCreds is an instance of grpc.PerRPCCredentials that will configure a
// client to act as an admin for the Firestore emulator. It always hardcodes
// the "authorization" metadata field to contain "Bearer owner", which the
// Firestore emulator accepts as valid admin credentials.
type emulatorCreds struct{}
func (ec emulatorCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{"authorization": "Bearer owner"}, nil
}
func (ec emulatorCreds) RequireTransportSecurity() bool {
return false
}

Describe the solution you'd like
I would like there to be a first-class API for creating a *firestore.Client which accepts an emulator address as an argument rather than by consulting FIRESTORE_EMULATOR_HOST.

@joshlf joshlf added the triage me I really want to be triaged. label May 9, 2020
@product-auto-label product-auto-label bot added the api: firestore Issues related to the Firestore API. label May 9, 2020
@codyoss codyoss added type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. and removed triage me I really want to be triaged. labels May 11, 2020
@tritone
Copy link
Contributor

tritone commented May 15, 2020

Thanks for filing the issue and for your clear description!

I know the FIRESTORE_EMULATOR_HOST approach is used across the language clients for firestore. @BenWhitehead is an owner for the firestore clients so I'm asking him to chime in on whether adding an API for this as well would be feasible.

@BenWhitehead
Copy link

Emulator boostrapping and lifecycle management is something that has recently come up for several languages and as such is going to be larger than any one client to be improved. I'll include this request in the discussion around the improvements.

Related issues:

@tv42
Copy link

tv42 commented Oct 8, 2020

Even if I were to do something like os.Setenv("FIRESTORE_EMULATOR_HOST", ...), that would mean that I couldn't run tests in parallel with different emulators, as the environment variable is global.

For what it's worth, the emulator is a reasonably heavyweight and slow-starting Java process, I wouldn't want to run multiple, nor would I want to start a new one per test.

Since the Firestore emulator accepts any project id and doesn't require authentication, I have a helper that picks a random project id (prefixed with the test name, for debugging), and clears the data for each project id before the test. It works great with parallel tests, subtests, etc.

@tritone tritone assigned crwilcox and unassigned tritone, crwilcox and BenWhitehead Jan 22, 2021
@crwilcox
Copy link
Contributor

This is a reasonable point, have you considered using unique project ids per test (or per parallel group)?

@joshlf
Copy link
Author

joshlf commented Aug 13, 2021

I'm no longer working on this project, but I don't see why that approach wouldn't work (maybe with the modification that, instead of random project IDs, you use an atomic counter to guarantee uniqueness).

@tv42
Copy link

tv42 commented Aug 13, 2021

@joshlf In my case, the tests run in multiple subprocesses, and I didn't want to impose coordination. The project id used concatenates a prefix, name of current test, and a 64-bit random number. It's realistically never going to collide.

@crwilcox crwilcox assigned dmahugh and unassigned crwilcox Nov 1, 2021
@telpirion telpirion self-assigned this Nov 2, 2022
@telpirion
Copy link
Contributor

If you look at the Firestore tests, you'll see that we use a mockServer that creates a gRPC interceptor for emulating service responses. If the emulator is too-heavyweight for you, you might consider a similar approach.

@eddumelendez
Copy link

Hi, I want to write a test using testcontainers-go and as you can see here java client already allows to set the host and port, which is a random port provided by testcontainers. Can we reconsider it and make it available in go client, please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: firestore Issues related to the Firestore API. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

No branches or pull requests

9 participants