go.mercari.io/datastore@v1.8.2/testbed/clouddatastore_test.go (about)

     1  package testbed
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"sync"
     8  	"testing"
     9  
    10  	"cloud.google.com/go/datastore"
    11  	"go.mercari.io/datastore/internal"
    12  	"golang.org/x/sync/errgroup"
    13  	"google.golang.org/api/iterator"
    14  )
    15  
    16  type CloudDatastoreStruct struct {
    17  	Test string
    18  }
    19  
    20  func cleanUp() error {
    21  	ctx := context.Background()
    22  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
    23  	if err != nil {
    24  		return err
    25  	}
    26  	defer client.Close()
    27  
    28  	q := datastore.NewQuery("__kind__").KeysOnly()
    29  	iter := client.Run(ctx, q)
    30  	var kinds []string
    31  	for {
    32  		key, err := iter.Next(nil)
    33  		if err == iterator.Done {
    34  			break
    35  		}
    36  		if err != nil {
    37  			return err
    38  		}
    39  		kinds = append(kinds, key.Name)
    40  	}
    41  
    42  	for _, kind := range kinds {
    43  		q := datastore.NewQuery(kind).KeysOnly()
    44  		keys, err := client.GetAll(ctx, q, nil)
    45  		if err != nil {
    46  			return err
    47  		}
    48  		err = client.DeleteMulti(ctx, keys)
    49  		if err != nil {
    50  			return err
    51  		}
    52  	}
    53  
    54  	return nil
    55  }
    56  
    57  func TestCloudDatastore_Put(t *testing.T) {
    58  	ctx := context.Background()
    59  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
    60  	if err != nil {
    61  		t.Fatal(err.Error())
    62  	}
    63  	defer client.Close()
    64  	defer cleanUp()
    65  
    66  	key := datastore.IncompleteKey("CloudDatastoreStruct", nil)
    67  	key, err = client.Put(ctx, key, &CloudDatastoreStruct{"Hi!"})
    68  	if err != nil {
    69  		t.Fatal(err.Error())
    70  	}
    71  
    72  	t.Logf("key: %s", key.String())
    73  }
    74  
    75  func TestCloudDatastore_GetMulti(t *testing.T) {
    76  	ctx := context.Background()
    77  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
    78  	if err != nil {
    79  		t.Fatal(err.Error())
    80  	}
    81  	defer client.Close()
    82  	defer cleanUp()
    83  
    84  	type Data struct {
    85  		Str string
    86  	}
    87  
    88  	key1, err := client.Put(ctx, datastore.IDKey("Data", 1, nil), &Data{"Data1"})
    89  	if err != nil {
    90  		t.Fatal(err.Error())
    91  	}
    92  	key2, err := client.Put(ctx, datastore.IDKey("Data", 2, nil), &Data{"Data2"})
    93  	if err != nil {
    94  		t.Fatal(err.Error())
    95  	}
    96  
    97  	list := make([]*Data, 2)
    98  	err = client.GetMulti(ctx, []*datastore.Key{key1, key2}, list)
    99  	if err != nil {
   100  		t.Fatal(err.Error())
   101  	}
   102  
   103  	if v := len(list); v != 2 {
   104  		t.Fatalf("unexpected: %v", v)
   105  	}
   106  }
   107  
   108  func TestCloudDatastore_Transaction(t *testing.T) {
   109  	ctx := context.Background()
   110  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   111  	if err != nil {
   112  		t.Fatal(err.Error())
   113  	}
   114  	defer client.Close()
   115  	defer cleanUp()
   116  
   117  	key := datastore.IncompleteKey("CloudDatastoreStruct", nil)
   118  	key, err = client.Put(ctx, key, &CloudDatastoreStruct{"Hi!"})
   119  	if err != nil {
   120  		t.Fatal(err.Error())
   121  	}
   122  
   123  	{ // Commit
   124  		tx, err := client.NewTransaction(ctx)
   125  		if err != nil {
   126  			t.Fatal(err.Error())
   127  		}
   128  
   129  		s := &CloudDatastoreStruct{}
   130  		err = tx.Get(key, s)
   131  		if err != nil {
   132  			t.Fatal(err.Error())
   133  		}
   134  
   135  		s.Test = "Updated 1"
   136  		_, err = tx.Put(key, s)
   137  		if err != nil {
   138  			t.Fatal(err.Error())
   139  		}
   140  
   141  		_, err = tx.Commit()
   142  		if err != nil {
   143  			t.Fatal(err.Error())
   144  		}
   145  
   146  		// should updated
   147  		newS := &CloudDatastoreStruct{}
   148  		err = client.Get(ctx, key, newS)
   149  		if err != nil {
   150  			t.Fatal(err.Error())
   151  		}
   152  
   153  		if v := newS.Test; v != "Updated 1" {
   154  			t.Fatalf("unexpected: %+v", v)
   155  		}
   156  	}
   157  	{ // Rollback
   158  		tx, err := client.NewTransaction(ctx)
   159  		if err != nil {
   160  			t.Fatal(err.Error())
   161  		}
   162  
   163  		s := &CloudDatastoreStruct{}
   164  		err = tx.Get(key, s)
   165  		if err != nil {
   166  			t.Fatal(err.Error())
   167  		}
   168  
   169  		s.Test = "Updated 2"
   170  		_, err = tx.Put(key, s)
   171  		if err != nil {
   172  			t.Fatal(err.Error())
   173  		}
   174  
   175  		err = tx.Rollback()
   176  		if err != nil {
   177  			t.Fatal(err.Error())
   178  		}
   179  
   180  		// should not updated
   181  		newS := &CloudDatastoreStruct{}
   182  		err = client.Get(ctx, key, newS)
   183  		if err != nil {
   184  			t.Fatal(err.Error())
   185  		}
   186  
   187  		if v := newS.Test; v != "Updated 1" {
   188  			t.Fatalf("unexpected: %+v", v)
   189  		}
   190  	}
   191  
   192  	t.Logf("key: %s", key.String())
   193  }
   194  
   195  func TestCloudDatastore_TransactionDeleteAndGet(t *testing.T) {
   196  	ctx := context.Background()
   197  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   198  	if err != nil {
   199  		t.Fatal(err.Error())
   200  	}
   201  	defer client.Close()
   202  	defer cleanUp()
   203  
   204  	type Data struct {
   205  		Str string
   206  	}
   207  
   208  	key, err := client.Put(ctx, datastore.IncompleteKey("Data", nil), &Data{"Data"})
   209  	if err != nil {
   210  		t.Fatal(err.Error())
   211  	}
   212  
   213  	tx, err := client.NewTransaction(ctx)
   214  	if err != nil {
   215  		t.Fatal(err.Error())
   216  	}
   217  
   218  	err = tx.Delete(key)
   219  	if err != nil {
   220  		t.Fatal(err.Error())
   221  	}
   222  
   223  	obj := &Data{}
   224  	err = tx.Get(key, obj)
   225  	if err != nil {
   226  		t.Fatalf("unexpected: %v", err)
   227  	}
   228  
   229  	err = tx.Rollback()
   230  	if err != nil {
   231  		t.Fatal(err.Error())
   232  	}
   233  }
   234  
   235  func TestCloudDatastore_SingleToBatch(t *testing.T) {
   236  	ctx := context.Background()
   237  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   238  	if err != nil {
   239  		t.Fatal(err.Error())
   240  	}
   241  	defer client.Close()
   242  	defer cleanUp()
   243  
   244  	type putResult struct {
   245  		key   *datastore.Key
   246  		error error
   247  	}
   248  
   249  	var m sync.Mutex
   250  	var keys []*datastore.Key
   251  	var srcList []interface{}
   252  	var cList []chan *putResult
   253  
   254  	put := func(key *datastore.Key, src interface{}) chan *putResult {
   255  		m.Lock()
   256  		defer m.Unlock()
   257  
   258  		c := make(chan *putResult)
   259  
   260  		keys = append(keys, key)
   261  		srcList = append(srcList, src)
   262  		cList = append(cList, c)
   263  
   264  		return c
   265  	}
   266  	execBatchOps := func() {
   267  		newKeys, err := client.PutMulti(ctx, keys, srcList)
   268  		if merr, ok := err.(datastore.MultiError); ok {
   269  			for idx, err := range merr {
   270  				c := cList[idx]
   271  				if err != nil {
   272  					c <- &putResult{error: err}
   273  				} else {
   274  					c <- &putResult{key: newKeys[idx]}
   275  				}
   276  			}
   277  			return
   278  		} else if err != nil {
   279  			for _, c := range cList {
   280  				c <- &putResult{error: err}
   281  			}
   282  			return
   283  		}
   284  
   285  		for idx, newKey := range newKeys {
   286  			c := cList[idx]
   287  			c <- &putResult{key: newKey}
   288  		}
   289  	}
   290  	unwrap := func(r *putResult) (key *datastore.Key, err error) {
   291  		if r.error != nil {
   292  			return nil, r.error
   293  		}
   294  
   295  		return r.key, nil
   296  	}
   297  
   298  	eg := &errgroup.Group{}
   299  	{ // 1st entity
   300  
   301  		key := datastore.IncompleteKey("CloudDatastoreStruct", nil)
   302  		c := put(key, &CloudDatastoreStruct{"Hi!"})
   303  		eg.Go(func() error {
   304  			key, err := unwrap(<-c)
   305  			if err != nil {
   306  				return err
   307  			}
   308  			t.Logf("#1: %s", key.String())
   309  			return nil
   310  		})
   311  	}
   312  	{ // 2nd entity
   313  		key := datastore.IncompleteKey("CloudDatastoreStruct", nil)
   314  		c := put(key, &CloudDatastoreStruct{"Hi!"})
   315  		eg.Go(func() error {
   316  			key, err := unwrap(<-c)
   317  			if err != nil {
   318  				return err
   319  			}
   320  			t.Logf("#2: %s", key.String())
   321  			return nil
   322  		})
   323  	}
   324  
   325  	execBatchOps()
   326  	err = eg.Wait()
   327  	if err != nil {
   328  		t.Fatal(err.Error())
   329  	}
   330  }
   331  
   332  func TestCloudDatastore_Query(t *testing.T) {
   333  	ctx := context.Background()
   334  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   335  	if err != nil {
   336  		t.Fatal(err.Error())
   337  	}
   338  	defer client.Close()
   339  	defer cleanUp()
   340  
   341  	type Data struct {
   342  		Str string
   343  	}
   344  
   345  	_, err = client.Put(ctx, datastore.IncompleteKey("Data", nil), &Data{"Data1"})
   346  	if err != nil {
   347  		t.Fatal(err.Error())
   348  	}
   349  	_, err = client.Put(ctx, datastore.IncompleteKey("Data", nil), &Data{"Data2"})
   350  	if err != nil {
   351  		t.Fatal(err.Error())
   352  	}
   353  
   354  	q := datastore.NewQuery("Data").Filter("Str =", "Data2")
   355  	{
   356  		var list []*Data
   357  		_, err = client.GetAll(ctx, q, &list)
   358  		if err != nil {
   359  			t.Fatal(err.Error())
   360  		}
   361  
   362  		if v := len(list); v != 1 {
   363  			t.Fatalf("unexpected: %v", v)
   364  		}
   365  	}
   366  	{
   367  		keys, err := client.GetAll(ctx, q.KeysOnly(), nil)
   368  		if err != nil {
   369  			t.Fatal(err.Error())
   370  		}
   371  
   372  		if v := len(keys); v != 1 {
   373  			t.Fatalf("unexpected: %v", v)
   374  		}
   375  	}
   376  }
   377  
   378  func TestCloudDatastore_QueryCursor(t *testing.T) {
   379  	ctx := context.Background()
   380  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   381  	if err != nil {
   382  		t.Fatal(err.Error())
   383  	}
   384  	defer client.Close()
   385  	defer cleanUp()
   386  
   387  	type Data struct {
   388  		Str string
   389  	}
   390  
   391  	{
   392  		var keys []*datastore.Key
   393  		var entities []*Data
   394  		for i := 0; i < 100; i++ {
   395  			keys = append(keys, datastore.IncompleteKey("Data", nil))
   396  			entities = append(entities, &Data{Str: fmt.Sprintf("#%d", i+1)})
   397  		}
   398  		_, err = client.PutMulti(ctx, keys, entities)
   399  		if err != nil {
   400  			t.Fatal(err)
   401  		}
   402  	}
   403  
   404  	var cur datastore.Cursor
   405  	var dataList []*Data
   406  	const limit = 3
   407  outer:
   408  	for {
   409  		q := datastore.NewQuery("Data").Order("Str").Limit(limit)
   410  		if cur.String() != "" {
   411  			q = q.Start(cur)
   412  		}
   413  		it := client.Run(ctx, q)
   414  
   415  		count := 0
   416  		for {
   417  			obj := &Data{}
   418  			_, err := it.Next(obj)
   419  			if err == iterator.Done {
   420  				break
   421  			} else if err != nil {
   422  				t.Fatal(err)
   423  			}
   424  
   425  			dataList = append(dataList, obj)
   426  			count++
   427  		}
   428  		if count != limit {
   429  			break
   430  		}
   431  
   432  		cur, err = it.Cursor()
   433  		if err != nil {
   434  			t.Fatal(err)
   435  		}
   436  		if cur.String() == "" {
   437  			break outer
   438  		}
   439  	}
   440  
   441  	if v := len(dataList); v != 100 {
   442  		t.Errorf("unexpected: %v", v)
   443  	}
   444  }
   445  
   446  func TestCloudDatastore_ErrConcurrentTransaction(t *testing.T) {
   447  	ctx := context.Background()
   448  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   449  	if err != nil {
   450  		t.Fatal(err.Error())
   451  	}
   452  	defer client.Close()
   453  	defer cleanUp()
   454  
   455  	type Data struct {
   456  		Str string
   457  	}
   458  
   459  	key := datastore.NameKey("Data", "a", nil)
   460  	_, err = client.Put(ctx, key, &Data{})
   461  	if err != nil {
   462  		t.Fatal(err)
   463  	}
   464  
   465  	// ErrConcurrent will be occur
   466  	_, err = client.RunInTransaction(ctx, func(tx1 *datastore.Transaction) error {
   467  		err := tx1.Get(key, &Data{})
   468  		if err != nil {
   469  			return err
   470  		}
   471  
   472  		_, err = client.RunInTransaction(ctx, func(tx2 *datastore.Transaction) error {
   473  			err := tx2.Get(key, &Data{})
   474  			if err != nil {
   475  				return err
   476  			}
   477  
   478  			_, err = tx2.Put(key, &Data{Str: "#2"})
   479  			return err
   480  		})
   481  		if err != nil {
   482  			return err
   483  		}
   484  
   485  		_, err = tx1.Put(key, &Data{Str: "#1"})
   486  		return err
   487  	})
   488  	if err != datastore.ErrConcurrentTransaction {
   489  		t.Fatal(err)
   490  	}
   491  }
   492  
   493  func TestCloudDatastore_ObjectHasObjectSlice(t *testing.T) {
   494  	type Inner struct {
   495  		A string
   496  		B string
   497  	}
   498  
   499  	type Data struct {
   500  		Slice []Inner
   501  	}
   502  
   503  	ps, err := datastore.SaveStruct(&Data{
   504  		Slice: []Inner{
   505  			{A: "A1", B: "B1"},
   506  			{A: "A2", B: "B2"},
   507  			{A: "A3", B: "B3"},
   508  		},
   509  	})
   510  	if err != nil {
   511  		t.Fatal(err)
   512  	}
   513  
   514  	if v := len(ps); v != 1 {
   515  		t.Fatalf("unexpected: %v", v)
   516  	}
   517  	p := ps[0]
   518  	if v := p.Name; v != "Slice" {
   519  		t.Fatalf("unexpected: %v", v)
   520  	}
   521  	es := p.Value.([]interface{})
   522  	if v := len(es); v != 3 {
   523  		t.Fatalf("unexpected: %v", v)
   524  	}
   525  
   526  	expects := []struct {
   527  		Name  string
   528  		Value string
   529  	}{
   530  		{"A", "A1"},
   531  		{"B", "B1"},
   532  		{"A", "A2"},
   533  		{"B", "B2"},
   534  		{"A", "A3"},
   535  		{"B", "B3"},
   536  	}
   537  
   538  	for idx, entity := range es {
   539  		e := entity.(*datastore.Entity)
   540  		if v := len(e.Properties); v != 2 {
   541  			t.Fatalf("unexpected: %v", v)
   542  		}
   543  		for pIdx, p := range e.Properties {
   544  			expect := expects[idx*len(e.Properties)+pIdx]
   545  			if v := p.Name; v != expect.Name {
   546  				t.Errorf("unexpected: %v", v)
   547  			}
   548  			if v := p.Value.(string); v != expect.Value {
   549  				t.Errorf("unexpected: %v", v)
   550  			}
   551  		}
   552  	}
   553  }
   554  
   555  func TestCloudDatastore_ObjectHasObjectSliceFlatten(t *testing.T) {
   556  	type Inner struct {
   557  		A string
   558  		B string
   559  	}
   560  
   561  	type Data struct {
   562  		Slice []Inner `datastore:",flatten"`
   563  	}
   564  
   565  	ps, err := datastore.SaveStruct(&Data{
   566  		Slice: []Inner{
   567  			{A: "A1", B: "B1"},
   568  			{A: "A2", B: "B2"},
   569  			{A: "A3", B: "B3"},
   570  		},
   571  	})
   572  	if err != nil {
   573  		t.Fatal(err)
   574  	}
   575  
   576  	if v := len(ps); v != 2 {
   577  		t.Fatalf("unexpected: %v", v)
   578  	}
   579  
   580  	expects := []struct {
   581  		Name   string
   582  		Values []interface{}
   583  	}{
   584  		{"Slice.A", []interface{}{"A1", "A2", "A3"}},
   585  		{"Slice.B", []interface{}{"B1", "B2", "B3"}},
   586  	}
   587  	for idx, expect := range expects {
   588  		p := ps[idx]
   589  		if v := p.Name; v != expect.Name {
   590  			t.Fatalf("unexpected: %v", v)
   591  		}
   592  		if v := p.Value.([]interface{}); !reflect.DeepEqual(v, expect.Values) {
   593  			t.Fatalf("unexpected: %v", v)
   594  		}
   595  	}
   596  }
   597  
   598  func TestCloudDatastore_NestedEntityWithKey(t *testing.T) {
   599  	ctx := context.Background()
   600  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   601  	if err != nil {
   602  		t.Fatal(err.Error())
   603  	}
   604  	defer client.Close()
   605  	defer cleanUp()
   606  
   607  	type Inner struct {
   608  		K *datastore.Key `datastore:"__key__"`
   609  		A string
   610  		B string
   611  	}
   612  
   613  	type Data struct {
   614  		Slice []Inner
   615  	}
   616  
   617  	_, err = client.Put(ctx, datastore.IncompleteKey("Test", nil), &Data{
   618  		Slice: []Inner{
   619  			{K: datastore.IDKey("TestInner", 1, nil), A: "A1", B: "B1"},
   620  			{K: datastore.IDKey("TestInner", 2, nil), A: "A2", B: "B2"},
   621  			{K: datastore.IDKey("TestInner", 3, nil), A: "A3", B: "B3"},
   622  		},
   623  	})
   624  	if err != nil {
   625  		t.Fatal(err)
   626  	}
   627  }
   628  
   629  func TestCloudDatastore_GeoPoint(t *testing.T) {
   630  	ctx := context.Background()
   631  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   632  	if err != nil {
   633  		t.Fatal(err.Error())
   634  	}
   635  	defer client.Close()
   636  	defer cleanUp()
   637  
   638  	type Data struct {
   639  		A datastore.GeoPoint
   640  		B *datastore.GeoPoint
   641  		C []datastore.GeoPoint
   642  		D []*datastore.GeoPoint
   643  	}
   644  
   645  	// NOTE Cloud Datastore can save *datastore.GeoPoint.
   646  	// but it is not means that is can handling *datastore.GeoPoint.
   647  	// *datastore.GeoPoint will convert to *datastore.Entity.
   648  	obj := &Data{
   649  		A: datastore.GeoPoint{Lat: 1.1, Lng: 2.2},
   650  		B: &datastore.GeoPoint{Lat: 3.3, Lng: 4.4},
   651  		C: []datastore.GeoPoint{
   652  			{Lat: 5.5, Lng: 6.6},
   653  			{Lat: 7.7, Lng: 8.8},
   654  		},
   655  		D: []*datastore.GeoPoint{
   656  			{Lat: 9.9, Lng: 10.10},
   657  			{Lat: 11.11, Lng: 12.12},
   658  		},
   659  	}
   660  
   661  	key, err := client.Put(ctx, datastore.IncompleteKey("Data", nil), obj)
   662  	if err != nil {
   663  		t.Fatal(err)
   664  	}
   665  
   666  	obj = &Data{}
   667  	err = client.Get(ctx, key, obj)
   668  	if err != nil {
   669  		t.Fatal(err)
   670  	}
   671  
   672  	if v := obj.A.Lat; v != 1.1 {
   673  		t.Errorf("unexpected: %v", v)
   674  	}
   675  	if v := obj.A.Lng; v != 2.2 {
   676  		t.Errorf("unexpected: %v", v)
   677  	}
   678  
   679  	if v := obj.B.Lat; v != 3.3 {
   680  		t.Errorf("unexpected: %v", v)
   681  	}
   682  	if v := obj.B.Lng; v != 4.4 {
   683  		t.Errorf("unexpected: %v", v)
   684  	}
   685  
   686  	if v := len(obj.C); v != 2 {
   687  		t.Fatalf("unexpected: %v", v)
   688  	}
   689  	if v := obj.C[0].Lat; v != 5.5 {
   690  		t.Errorf("unexpected: %v", v)
   691  	}
   692  	if v := obj.C[0].Lng; v != 6.6 {
   693  		t.Errorf("unexpected: %v", v)
   694  	}
   695  	if v := obj.C[1].Lat; v != 7.7 {
   696  		t.Errorf("unexpected: %v", v)
   697  	}
   698  	if v := obj.C[1].Lng; v != 8.8 {
   699  		t.Errorf("unexpected: %v", v)
   700  	}
   701  
   702  	if v := len(obj.D); v != 2 {
   703  		t.Fatalf("unexpected: %v", v)
   704  	}
   705  	if v := obj.D[0].Lat; v != 9.9 {
   706  		t.Errorf("unexpected: %v", v)
   707  	}
   708  	if v := obj.D[0].Lng; v != 10.10 {
   709  		t.Errorf("unexpected: %v", v)
   710  	}
   711  	if v := obj.D[1].Lat; v != 11.11 {
   712  		t.Errorf("unexpected: %v", v)
   713  	}
   714  	if v := obj.D[1].Lng; v != 12.12 {
   715  		t.Errorf("unexpected: %v", v)
   716  	}
   717  }
   718  
   719  func TestCloudDatastore_PutInterface(t *testing.T) {
   720  	ctx := context.Background()
   721  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   722  	if err != nil {
   723  		t.Fatal(err.Error())
   724  	}
   725  	defer client.Close()
   726  	defer cleanUp()
   727  
   728  	var e EntityInterface = &PutInterfaceTest{}
   729  
   730  	key := datastore.IncompleteKey("Test", nil)
   731  	_, err = client.Put(ctx, key, e)
   732  	if err != nil {
   733  		t.Fatal(err)
   734  	}
   735  }
   736  
   737  func TestCloudDatastore_PutAndGetPropertyList(t *testing.T) {
   738  	ctx := context.Background()
   739  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   740  	if err != nil {
   741  		t.Fatal(err.Error())
   742  	}
   743  	defer client.Close()
   744  	defer cleanUp()
   745  
   746  	var ps datastore.PropertyList
   747  	ps = append(ps, datastore.Property{
   748  		Name:  "A",
   749  		Value: "A-Value",
   750  	})
   751  	ps = append(ps, datastore.Property{
   752  		Name:  "B",
   753  		Value: true,
   754  	})
   755  
   756  	key := datastore.IncompleteKey("Test", nil)
   757  	// passed datastore.PropertyList, would be error.
   758  	_, err = client.Put(ctx, key, ps)
   759  	if err != datastore.ErrInvalidEntityType {
   760  		t.Fatal(err)
   761  	}
   762  
   763  	// ok!
   764  	key, err = client.Put(ctx, key, &ps)
   765  	if err != nil {
   766  		t.Fatal(err)
   767  	}
   768  
   769  	// passed datastore.PropertyList, would be error.
   770  	ps = datastore.PropertyList{}
   771  	err = client.Get(ctx, key, ps)
   772  	if err != datastore.ErrInvalidEntityType {
   773  		t.Fatal(err)
   774  	}
   775  
   776  	// ok!
   777  	ps = datastore.PropertyList{}
   778  	err = client.Get(ctx, key, &ps)
   779  	if err != nil {
   780  		t.Fatal(err)
   781  	}
   782  
   783  	if v := len(ps); v != 2 {
   784  		t.Fatalf("unexpected: %v", v)
   785  	}
   786  }
   787  
   788  func TestCloudDatastore_PutAndGetMultiPropertyListSlice(t *testing.T) {
   789  	ctx := context.Background()
   790  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   791  	if err != nil {
   792  		t.Fatal(err.Error())
   793  	}
   794  	defer client.Close()
   795  	defer cleanUp()
   796  
   797  	var pss []datastore.PropertyList
   798  	var keys []*datastore.Key
   799  	{
   800  		var ps datastore.PropertyList
   801  		ps = append(ps, datastore.Property{
   802  			Name:  "A",
   803  			Value: "A-Value",
   804  		})
   805  		ps = append(ps, datastore.Property{
   806  			Name:  "B",
   807  			Value: true,
   808  		})
   809  
   810  		key := datastore.IncompleteKey("Test", nil)
   811  
   812  		pss = append(pss, ps)
   813  		keys = append(keys, key)
   814  	}
   815  
   816  	// passed *[]datastore.PropertyList, would be error.
   817  	_, err = client.PutMulti(ctx, keys, &pss)
   818  	if err == nil {
   819  		t.Fatal(err)
   820  	}
   821  
   822  	// ok! []datastore.PropertyList
   823  	keys, err = client.PutMulti(ctx, keys, pss)
   824  	if err != nil {
   825  		t.Fatal(err)
   826  	}
   827  
   828  	// passed *[]datastore.PropertyList, would be error.
   829  	pss = make([]datastore.PropertyList, len(keys))
   830  	err = client.GetMulti(ctx, keys, &pss)
   831  	if err == nil {
   832  		t.Fatal(err)
   833  	}
   834  
   835  	// passed []datastore.PropertyList with length 0, would be error.
   836  	pss = make([]datastore.PropertyList, 0)
   837  	err = client.GetMulti(ctx, keys, pss)
   838  	if err == nil {
   839  		t.Fatal(err)
   840  	}
   841  
   842  	// ok! []datastore.PropertyList with length == len(keys)
   843  	pss = make([]datastore.PropertyList, len(keys))
   844  	err = client.GetMulti(ctx, keys, pss)
   845  	if err != nil {
   846  		t.Fatal(err)
   847  	}
   848  
   849  	if v := len(pss); v != 1 {
   850  		t.Fatalf("unexpected: %v", v)
   851  	}
   852  }
   853  
   854  func TestCloudDatastore_PutAndGetBareStruct(t *testing.T) {
   855  	ctx := context.Background()
   856  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   857  	if err != nil {
   858  		t.Fatal(err.Error())
   859  	}
   860  	defer client.Close()
   861  	defer cleanUp()
   862  
   863  	type Data struct {
   864  		Name string
   865  	}
   866  
   867  	key := datastore.IncompleteKey("Test", nil)
   868  	// passed Data, would be error.
   869  	_, err = client.Put(ctx, key, Data{Name: "A"})
   870  	if err != datastore.ErrInvalidEntityType {
   871  		t.Fatal(err)
   872  	}
   873  
   874  	// ok! *Data
   875  	key, err = client.Put(ctx, key, &Data{Name: "A"})
   876  	if err != nil {
   877  		t.Fatal(err)
   878  	}
   879  
   880  	// ok! but struct are copied. can't watching Get result.
   881  	obj := Data{}
   882  	err = client.Get(ctx, key, obj)
   883  	if err != datastore.ErrInvalidEntityType {
   884  		t.Fatal(err)
   885  	}
   886  
   887  	if v := obj.Name; v != "" {
   888  		t.Errorf("unexpected: '%v'", v)
   889  	}
   890  }
   891  
   892  func TestCloudDatastore_PutAndGetMultiBareStruct(t *testing.T) {
   893  	ctx := context.Background()
   894  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   895  	if err != nil {
   896  		t.Fatal(err.Error())
   897  	}
   898  	defer client.Close()
   899  	defer cleanUp()
   900  
   901  	type Data struct {
   902  		Name string
   903  	}
   904  
   905  	var list []Data
   906  	var keys []*datastore.Key
   907  	{
   908  		obj := Data{Name: "A"}
   909  		key := datastore.IncompleteKey("Test", nil)
   910  
   911  		list = append(list, obj)
   912  		keys = append(keys, key)
   913  	}
   914  
   915  	// ok!
   916  	keys, err = client.PutMulti(ctx, keys, list)
   917  	if err != nil {
   918  		t.Fatal(err)
   919  	}
   920  
   921  	// passed []Data with length 0, would be error.
   922  	list = make([]Data, 0)
   923  	err = client.GetMulti(ctx, keys, list)
   924  	if err == nil {
   925  		t.Fatal(err)
   926  	}
   927  
   928  	// ok! []Data with length == len(keys)
   929  	list = make([]Data, len(keys))
   930  	err = client.GetMulti(ctx, keys, list)
   931  	if err != nil {
   932  		t.Fatal(err)
   933  	}
   934  
   935  	if v := len(list); v != 1 {
   936  		t.Fatalf("unexpected: '%v'", v)
   937  	}
   938  	if v := list[0].Name; v != "A" {
   939  		t.Errorf("unexpected: '%v'", v)
   940  	}
   941  }
   942  
   943  func TestCloudDatastore_PutAndGetStringSynonym(t *testing.T) {
   944  	ctx := context.Background()
   945  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   946  	if err != nil {
   947  		t.Fatal(err.Error())
   948  	}
   949  	defer client.Close()
   950  	defer cleanUp()
   951  
   952  	type Email string
   953  
   954  	type Data struct {
   955  		Email Email
   956  	}
   957  
   958  	key, err := client.Put(ctx, datastore.IncompleteKey("Data", nil), &Data{Email: "test@example.com"})
   959  	if err != nil {
   960  		t.Fatal(err)
   961  	}
   962  
   963  	obj := &Data{}
   964  	err = client.Get(ctx, key, obj)
   965  	if err != nil {
   966  		t.Fatal(err)
   967  	}
   968  
   969  	if v := obj.Email; v != "test@example.com" {
   970  		t.Errorf("unexpected: '%v'", v)
   971  	}
   972  }
   973  
   974  func TestCloudDatastore_QueryNextByPropertyList(t *testing.T) {
   975  	ctx := context.Background()
   976  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
   977  	if err != nil {
   978  		t.Fatal(err.Error())
   979  	}
   980  	defer client.Close()
   981  	defer cleanUp()
   982  
   983  	type Data struct {
   984  		Name string
   985  	}
   986  
   987  	_, err = client.Put(ctx, datastore.IncompleteKey("Data", nil), &Data{Name: "A"})
   988  	if err != nil {
   989  		t.Fatal(err)
   990  	}
   991  
   992  	q := datastore.NewQuery("Data")
   993  
   994  	{ // passed datastore.PropertyList, would be error.
   995  		iter := client.Run(ctx, q)
   996  
   997  		var ps datastore.PropertyList
   998  		_, err = iter.Next(ps)
   999  		if err == nil {
  1000  			t.Fatal(err)
  1001  		}
  1002  	}
  1003  	{ // ok! *datastore.PropertyList
  1004  		iter := client.Run(ctx, q)
  1005  
  1006  		var ps datastore.PropertyList
  1007  		_, err = iter.Next(&ps)
  1008  		if err != nil {
  1009  			t.Fatal(err)
  1010  		}
  1011  	}
  1012  }
  1013  
  1014  func TestCloudDatastore_GetAllByPropertyListSlice(t *testing.T) {
  1015  	ctx := context.Background()
  1016  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
  1017  	if err != nil {
  1018  		t.Fatal(err.Error())
  1019  	}
  1020  	defer client.Close()
  1021  	defer cleanUp()
  1022  
  1023  	type Data struct {
  1024  		Name string
  1025  	}
  1026  
  1027  	_, err = client.Put(ctx, datastore.IncompleteKey("Data", nil), &Data{Name: "A"})
  1028  	if err != nil {
  1029  		t.Fatal(err)
  1030  	}
  1031  
  1032  	q := datastore.NewQuery("Data")
  1033  	var psList []datastore.PropertyList
  1034  
  1035  	// passed []datastore.PropertyList, would be error.
  1036  	_, err = client.GetAll(ctx, q, psList)
  1037  	if err == nil {
  1038  		t.Fatal(err)
  1039  	}
  1040  
  1041  	// ok! *[]datastore.PropertyList
  1042  	psList = nil
  1043  	_, err = client.GetAll(ctx, q, &psList)
  1044  	if err != nil {
  1045  		t.Fatal(err)
  1046  	}
  1047  }
  1048  
  1049  func TestCloudDatastore_PendingKeyWithCompleteKey(t *testing.T) {
  1050  	ctx := context.Background()
  1051  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
  1052  	if err != nil {
  1053  		t.Fatal(err.Error())
  1054  	}
  1055  	defer client.Close()
  1056  	defer cleanUp()
  1057  
  1058  	type Data struct {
  1059  		Name string
  1060  	}
  1061  
  1062  	tx, err := client.NewTransaction(ctx)
  1063  	if err != nil {
  1064  		t.Fatal(err)
  1065  	}
  1066  
  1067  	pKey, err := tx.Put(datastore.NameKey("Data", "a", nil), &Data{Name: "Test"})
  1068  	if err != nil {
  1069  		t.Fatal(err)
  1070  	}
  1071  
  1072  	commit, err := tx.Commit()
  1073  	if err != nil {
  1074  		t.Fatal(err)
  1075  	}
  1076  
  1077  	// don't panic occurred after https://github.com/GoogleCloudPlatform/google-cloud-go/commit/02a2d936c7c22d0d585fb1e86ac05043bacb3a13
  1078  	commit.Key(pKey)
  1079  }
  1080  
  1081  func TestCloudDatastore_Namespace(t *testing.T) {
  1082  	ctx := context.Background()
  1083  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
  1084  	if err != nil {
  1085  		t.Fatal(err.Error())
  1086  	}
  1087  	defer client.Close()
  1088  	defer cleanUp()
  1089  
  1090  	type Data struct {
  1091  		Name string
  1092  	}
  1093  
  1094  	key := datastore.IDKey("Test", 1, nil)
  1095  	key.Namespace = "no1"
  1096  	if v := key.String(); v != "/Test,1" {
  1097  		t.Fatalf("unexpected: %v", v)
  1098  	}
  1099  
  1100  	_, err = client.Put(ctx, key, &Data{"Name #1"})
  1101  	if err != nil {
  1102  		t.Fatal(err)
  1103  	}
  1104  
  1105  	key.Namespace = ""
  1106  	err = client.Get(ctx, key, &Data{})
  1107  	if err != datastore.ErrNoSuchEntity {
  1108  		t.Fatal(err)
  1109  	}
  1110  
  1111  	key.Namespace = "no1"
  1112  	err = client.Get(ctx, key, &Data{})
  1113  	if err != nil {
  1114  		t.Fatal(err)
  1115  	}
  1116  
  1117  	q := datastore.NewQuery("Test")
  1118  	q = q.KeysOnly()
  1119  
  1120  	var keys []*datastore.Key
  1121  
  1122  	keys, err = client.GetAll(ctx, q, nil)
  1123  	if err != nil {
  1124  		t.Fatal(err)
  1125  	}
  1126  	if v := len(keys); v != 0 {
  1127  		t.Fatalf("unexpected: %v", v)
  1128  	}
  1129  
  1130  	q = q.Namespace("no1")
  1131  	keys, err = client.GetAll(ctx, q, nil)
  1132  	if err != nil {
  1133  		t.Fatal(err)
  1134  	}
  1135  	if v := len(keys); v != 1 {
  1136  		t.Fatalf("unexpected: %v", v)
  1137  	}
  1138  }
  1139  
  1140  func TestCloudDatastore_RollbackAfterCommit(t *testing.T) {
  1141  	ctx := context.Background()
  1142  	client, err := datastore.NewClient(ctx, internal.GetProjectID())
  1143  	if err != nil {
  1144  		t.Fatal(err)
  1145  	}
  1146  	defer client.Close()
  1147  	defer cleanUp()
  1148  
  1149  	tx, err := client.NewTransaction(ctx)
  1150  	if err != nil {
  1151  		t.Fatal(err)
  1152  	}
  1153  
  1154  	_, err = tx.Commit()
  1155  	if err != nil {
  1156  		t.Fatal(err)
  1157  	}
  1158  
  1159  	err = tx.Rollback()
  1160  	if err == nil || err.Error() != "datastore: transaction expired" {
  1161  		t.Fatal(err)
  1162  	}
  1163  
  1164  	_, err = tx.Commit()
  1165  	if err == nil || err.Error() != "datastore: transaction expired" {
  1166  		t.Fatal(err)
  1167  	}
  1168  }