I am having problems creating a Cloud Function in Golang and creating unit tests for it. Specifically, the environment variables that I want to inject during the test phase are not recognized, since the init() function always runs before the test. This init() function uses the environment variables to create a client. Is there any way around this problem?
Google recommends putting global variables like clients in the init() function, to reuse those objects in future invocations. This reduces startup time (source).
Directory structure
/function
do_something.go
do_something_test.go
do_something.go
package main
import (
"context"
"log"
"os"
"cloud.google.com/go/firestore"
)
var (
projectID = os.Getenv("GCLOUD_PROJECT")
client *firestore.Client
)
func init() {
ctx := context.Background()
var err error
client, err = firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Firestore: %v", err)
}
}
func Main(w http.ResponseWriter, r *http.Request) {
// Do something
}
do_something_test.go
package main
import (
"os"
"testing"
)
func init() {
os.Setenv("GCLOUD_PROJECT", "my-test-project") // This does not work because of lexigraphical order, init() in do_something.go before this init().
}
func TestMain(t *testing.T) {
os.Setenv("GCLOUD_PROJECT", "my-test-project") // This does not work because init() is run before TestMain.
}
Possible solutions
- Do not use init() in
do_something.go. However, this gives a penalty in cloud function performance, latency is increased due to extended startup time. - Inject variables through a configuration file. However, I think this introduces the same problem.
- Set environment variables before running
go test. This is feasible, however I find this a suboptimal solution, since I don't want to run extra arguments before doing the actual test. - Always default to the development environment unless an environment variable specifies the code runs in production:
projectID = GetEnv("GCLOUD_PROJECT", "my-test-project")
func GetEnv(key string, defaultVal string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultVal
}