Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion firebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,16 @@ func (a *App) Storage(ctx context.Context) (*storage.Client, error) {
// Firestore returns a new firestore.Client instance from the https://godoc.org/cloud.google.com/go/firestore
// package.
func (a *App) Firestore(ctx context.Context) (*firestore.Client, error) {
return a.FirestoreWithDatabaseID(ctx, firestore.DefaultDatabaseID)
}

// FirestoreWithDatabaseID returns a new firestore.Client instance with the specified named database from the
// https://godoc.org/cloud.google.com/go/firestore package.
func (a *App) FirestoreWithDatabaseID(ctx context.Context, databaseID string) (*firestore.Client, error) {
if a.projectID == "" {
return nil, errors.New("project id is required to access Firestore")
}
return firestore.NewClient(ctx, a.projectID, a.opts...)
return firestore.NewClientWithDatabase(ctx, a.projectID, databaseID, a.opts...)
}

// InstanceID returns an instance of iid.Client.
Expand Down
16 changes: 16 additions & 0 deletions firebase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,18 @@ func TestFirestore(t *testing.T) {
}
}

func TestFirestoreWithDatabaseID(t *testing.T) {
ctx := context.Background()
app, err := NewApp(ctx, nil, option.WithCredentialsFile("testdata/service_account.json"))
if err != nil {
t.Fatal(err)
}

if c, err := app.FirestoreWithDatabaseID(ctx, "other-db"); c == nil || err != nil {
t.Errorf("FirestoreWithDatabaseID() = (%v, %v); want (client, nil)", c, err)
}
}

func TestFirestoreWithProjectID(t *testing.T) {
verify := func(varName string) {
current := os.Getenv(varName)
Expand Down Expand Up @@ -336,6 +348,10 @@ func TestFirestoreWithNoProjectID(t *testing.T) {
if c, err := app.Firestore(ctx); c != nil || err == nil {
t.Errorf("Firestore() = (%v, %v); want (nil, error)", c, err)
}

if c, err := app.FirestoreWithDatabaseID(ctx, "other-db"); c != nil || err == nil {
t.Errorf("FirestoreWithDatabaseID() = (%v, %v); want (nil, error)", c, err)
}
}

func TestInstanceID(t *testing.T) {
Expand Down
149 changes: 139 additions & 10 deletions integration/firestore/firestore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,43 @@ package firestore

import (
"context"
"flag"
"log"
"os"
"reflect"
"testing"

"time"

"cloud.google.com/go/firestore"
"firebase.google.com/go/v4/integration/internal"
)

func TestFirestore(t *testing.T) {
var (
cityData = map[string]interface{}{
"name": "Mountain View",
"country": "USA",
"population": int64(77846),
"capital": false,
}
movieData = map[string]interface{}{
"Name": "Interstellar",
"Year": int64(2014),
"Runtime": "2h 49m",
"Academy Award Winner": true,
}
)

func TestMain(m *testing.M) {
flag.Parse()
if testing.Short() {
log.Println("skipping Firestore integration tests in short mode.")
return
os.Exit(0)
}
os.Exit(m.Run())
}

func TestFirestore(t *testing.T) {
ctx := context.Background()
app, err := internal.NewTestApp(ctx, nil)
if err != nil {
Expand All @@ -40,23 +65,127 @@ func TestFirestore(t *testing.T) {
}

doc := client.Collection("cities").Doc("Mountain View")
if _, err := doc.Set(ctx, cityData); err != nil {
t.Fatal(err)
}
defer doc.Delete(ctx)

snap, err := doc.Get(ctx)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(snap.Data(), cityData) {
t.Errorf("Get() = %v; want %v", snap.Data(), cityData)
}
}

func TestFirestoreWithDatabaseID(t *testing.T) {
ctx := context.Background()
app, err := internal.NewTestApp(ctx, nil)
if err != nil {
t.Fatal(err)
}

// This test requires a non-default database to exist in the project.
// If it doesn't exist, this test will fail.
client, err := app.FirestoreWithDatabaseID(ctx, "testing-database")
if err != nil {
t.Fatal(err)
}

doc := client.Collection("cities").NewDoc()
if _, err := doc.Set(ctx, cityData); err != nil {
t.Fatal(err)
}
defer doc.Delete(ctx)

snap, err := doc.Get(ctx)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(snap.Data(), cityData) {
t.Errorf("Get() = %v; want %v", snap.Data(), cityData)
}
}

func TestFirestoreMultiDB(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels repetitive. Doesn't TestFirestoreWithDatabaseID and TestFirestore cover this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test in for verifying that two databases clients can be opened and modified at once with no impact on the other.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. We can keep this, but as a clarification, to me this feels like we are trying to test the cloud firestore SDK here. This should be a more fitting test for the Firestore SDK and slightly beyond the Admin SDK scope. The Admin SDK should test the part where we are setting the database ID in the Firestore SDK and everything beyond that should be tested in the Firestore SDK itself (which I think they do).

ctx := context.Background()
app, err := internal.NewTestApp(ctx, nil)
if err != nil {
t.Fatal(err)
}

cityClient, err := app.Firestore(ctx)
if err != nil {
t.Fatal(err)
}
// This test requires a non-default database to exist in the project.
movieClient, err := app.FirestoreWithDatabaseID(ctx, "testing-database")
if err != nil {
t.Fatal(err)
}

cityDoc := cityClient.Collection("cities").NewDoc()
movieDoc := movieClient.Collection("movies").NewDoc()

if _, err := cityDoc.Set(ctx, cityData); err != nil {
t.Fatal(err)
}
defer cityDoc.Delete(ctx)

if _, err := movieDoc.Set(ctx, movieData); err != nil {
t.Fatal(err)
}
defer movieDoc.Delete(ctx)

citySnap, err := cityDoc.Get(ctx)
if err != nil {
t.Fatal(err)
}
movieSnap, err := movieDoc.Get(ctx)
if err != nil {
t.Fatal(err)
}

if !reflect.DeepEqual(citySnap.Data(), cityData) {
t.Errorf("City Get() = %v; want %v", citySnap.Data(), cityData)
}
if !reflect.DeepEqual(movieSnap.Data(), movieData) {
t.Errorf("Movie Get() = %v; want %v", movieSnap.Data(), movieData)
}
}

func TestServerTimestamp(t *testing.T) {
ctx := context.Background()
app, err := internal.NewTestApp(ctx, nil)
if err != nil {
t.Fatal(err)
}

client, err := app.Firestore(ctx)
if err != nil {
t.Fatal(err)
}

doc := client.Collection("cities").NewDoc()
data := map[string]interface{}{
"name": "Mountain View",
"country": "USA",
"population": int64(77846),
"capital": false,
"name": "Mountain View",
"timestamp": firestore.ServerTimestamp,
}
if _, err := doc.Set(ctx, data); err != nil {
t.Fatal(err)
}
defer doc.Delete(ctx)

snap, err := doc.Get(ctx)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(snap.Data(), data) {
t.Errorf("Get() = %v; want %v", snap.Data(), data)
got := snap.Data()
if got["name"] != "Mountain View" {
t.Errorf("Name = %v; want Mountain View", got["name"])
}
if _, err := doc.Delete(ctx); err != nil {
t.Fatal(err)
if _, ok := got["timestamp"].(time.Time); !ok {
t.Errorf("Timestamp is not a time.Time: %v", got["timestamp"])
}
}
Loading