github.com/cornelk/go-cloud@v0.17.1/docstore/gcpfirestore/fs_test.go (about)

     1  // Copyright 2019 The Go Cloud Development Kit Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package gcpfirestore
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"testing"
    21  
    22  	vkit "cloud.google.com/go/firestore/apiv1"
    23  	"github.com/cornelk/go-cloud/docstore"
    24  	"github.com/cornelk/go-cloud/docstore/driver"
    25  	"github.com/cornelk/go-cloud/docstore/drivertest"
    26  	"github.com/cornelk/go-cloud/internal/testing/setup"
    27  	"github.com/golang/protobuf/proto"
    28  	tspb "github.com/golang/protobuf/ptypes/timestamp"
    29  	"google.golang.org/api/option"
    30  	pb "google.golang.org/genproto/googleapis/firestore/v1"
    31  	"google.golang.org/grpc/status"
    32  )
    33  
    34  const (
    35  	// projectID is the project ID that was used during the last test run using --record.
    36  	projectID       = "go-cloud-test-216917"
    37  	collectionName1 = "docstore-test-1"
    38  	collectionName2 = "docstore-test-2"
    39  	collectionName3 = "docstore-test-3"
    40  	endPoint        = "firestore.googleapis.com:443"
    41  )
    42  
    43  type harness struct {
    44  	client *vkit.Client
    45  	done   func()
    46  }
    47  
    48  func newHarness(ctx context.Context, t *testing.T) (drivertest.Harness, error) {
    49  	conn, done := setup.NewGCPgRPCConn(ctx, t, endPoint, "docstore")
    50  	client, err := vkit.NewClient(ctx, option.WithGRPCConn(conn))
    51  	if err != nil {
    52  		done()
    53  		return nil, err
    54  	}
    55  	return &harness{client, done}, nil
    56  }
    57  
    58  func (h *harness) MakeCollection(_ context.Context, kind drivertest.CollectionKind) (driver.Collection, error) {
    59  	switch kind {
    60  	case drivertest.SingleKey, drivertest.NoRev:
    61  		return newCollection(h.client, CollectionResourceID(projectID, collectionName1), drivertest.KeyField, nil, nil)
    62  	case drivertest.TwoKey:
    63  		return newCollection(h.client, CollectionResourceID(projectID, collectionName2), "",
    64  			func(doc docstore.Document) string {
    65  				return drivertest.HighScoreKey(doc).(string)
    66  			}, &Options{AllowLocalFilters: true})
    67  	case drivertest.AltRev:
    68  		return newCollection(h.client, CollectionResourceID(projectID, collectionName1), drivertest.KeyField, nil,
    69  			&Options{RevisionField: drivertest.AlternateRevisionField})
    70  	default:
    71  		panic("bad kind")
    72  	}
    73  }
    74  
    75  func (*harness) BeforeDoTypes() []interface{} {
    76  	return []interface{}{&pb.BatchGetDocumentsRequest{}, &pb.CommitRequest{}}
    77  }
    78  
    79  func (*harness) BeforeQueryTypes() []interface{} {
    80  	return []interface{}{&pb.RunQueryRequest{}}
    81  }
    82  
    83  func (*harness) RevisionsEqual(rev1, rev2 interface{}) bool {
    84  	return proto.Equal(rev1.(*tspb.Timestamp), rev2.(*tspb.Timestamp))
    85  }
    86  
    87  func (h *harness) Close() {
    88  	_ = h.client.Close()
    89  	h.done()
    90  }
    91  
    92  // codecTester implements drivertest.CodecTester.
    93  type codecTester struct {
    94  	nc *nativeCodec
    95  }
    96  
    97  func (*codecTester) UnsupportedTypes() []drivertest.UnsupportedType {
    98  	return []drivertest.UnsupportedType{drivertest.Uint, drivertest.Arrays}
    99  }
   100  
   101  func (c *codecTester) NativeEncode(x interface{}) (interface{}, error) {
   102  	return c.nc.Encode(x)
   103  }
   104  
   105  func (c *codecTester) NativeDecode(value, dest interface{}) error {
   106  	return c.nc.Decode(value.(*pb.Document), dest)
   107  }
   108  
   109  func (c *codecTester) DocstoreEncode(x interface{}) (interface{}, error) {
   110  	var e encoder
   111  	if err := drivertest.MustDocument(x).Encode(&e); err != nil {
   112  		return nil, err
   113  	}
   114  	return &pb.Document{
   115  		Name:   "projects/P/databases/(default)/documents/C/D",
   116  		Fields: e.pv.GetMapValue().Fields,
   117  	}, nil
   118  }
   119  
   120  func (c *codecTester) DocstoreDecode(value, dest interface{}) error {
   121  	mv := &pb.Value{ValueType: &pb.Value_MapValue{MapValue: &pb.MapValue{
   122  		Fields: value.(*pb.Document).Fields,
   123  	}}}
   124  	return drivertest.MustDocument(dest).Decode(decoder{mv})
   125  }
   126  
   127  type verifyAs struct{}
   128  
   129  func (verifyAs) Name() string {
   130  	return "verify As"
   131  }
   132  
   133  func (verifyAs) CollectionCheck(coll *docstore.Collection) error {
   134  	var fc *vkit.Client
   135  	if !coll.As(&fc) {
   136  		return errors.New("Collection.As failed")
   137  	}
   138  	return nil
   139  }
   140  
   141  func (verifyAs) QueryCheck(it *docstore.DocumentIterator) error {
   142  	var c pb.Firestore_RunQueryClient
   143  	if !it.As(&c) {
   144  		return errors.New("DocumentIterator.As failed")
   145  	}
   146  	_, err := c.Header()
   147  	return err
   148  }
   149  
   150  func (v verifyAs) ErrorCheck(c *docstore.Collection, err error) error {
   151  	var s *status.Status
   152  	if !c.ErrorAs(err, &s) {
   153  		return errors.New("Collection.ErrorAs failed")
   154  	}
   155  	return nil
   156  }
   157  
   158  func TestConformance(t *testing.T) {
   159  	drivertest.MakeUniqueStringDeterministicForTesting(1)
   160  	nc, err := newNativeCodec()
   161  	if err != nil {
   162  		t.Fatal(err)
   163  	}
   164  	drivertest.RunConformanceTests(t, newHarness, &codecTester{nc}, []drivertest.AsTest{verifyAs{}})
   165  }
   166  
   167  func BenchmarkConformance(b *testing.B) {
   168  	ctx := context.Background()
   169  	client, err := vkit.NewClient(ctx)
   170  	if err != nil {
   171  		b.Fatal(err)
   172  	}
   173  	coll, err := newCollection(client, CollectionResourceID(projectID, collectionName3), drivertest.KeyField, nil, nil)
   174  	if err != nil {
   175  		b.Fatal(err)
   176  	}
   177  	drivertest.RunBenchmarks(b, docstore.NewCollection(coll))
   178  }
   179  
   180  // gcpfirestore-specific tests.
   181  
   182  func TestResourceIDRegexp(t *testing.T) {
   183  	for _, good := range []string{
   184  		"projects/abc-_.309/databases/(default)/documents/C",
   185  		"projects/P/databases/(default)/documents/C/D/E",
   186  	} {
   187  		if !resourceIDRE.MatchString(good) {
   188  			t.Errorf("%q did not match but should have", good)
   189  		}
   190  	}
   191  
   192  	for _, bad := range []string{
   193  		"",
   194  		"Projects/P/databases/(default)/documents/C",
   195  		"P/databases/(default)/documents/C",
   196  		"projects/P/Q/databases/(default)/documents/C",
   197  		"projects/P/databases/mydb/documents/C",
   198  		"projects/P/databases/(default)/C",
   199  		"projects/P/databases/(default)/documents/",
   200  		"projects/P/databases/(default)",
   201  	} {
   202  		if resourceIDRE.MatchString(bad) {
   203  			t.Errorf("%q matched but should not have", bad)
   204  		}
   205  	}
   206  }