github.com/willyham/dosa@v2.3.1-0.20171024181418-1e446d37ee71+incompatible/client_test.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package dosa_test
    22  
    23  import (
    24  	"context"
    25  	"io/ioutil"
    26  	"os"
    27  	"path/filepath"
    28  	"testing"
    29  
    30  	"github.com/golang/mock/gomock"
    31  	"github.com/pkg/errors"
    32  	"github.com/stretchr/testify/assert"
    33  
    34  	"fmt"
    35  	"time"
    36  
    37  	dosaRenamed "github.com/uber-go/dosa"
    38  	_ "github.com/uber-go/dosa/connectors/devnull"
    39  	_ "github.com/uber-go/dosa/connectors/memory"
    40  	"github.com/uber-go/dosa/mocks"
    41  	"github.com/uber-go/dosa/testutil"
    42  )
    43  
    44  type ClientTestEntity1 struct {
    45  	dosaRenamed.Entity `dosa:"primaryKey=(ID)"`
    46  	dosaRenamed.Index  `dosa:"key=Name, name=username"`
    47  	ID                 int64
    48  	Name               string
    49  	Email              string
    50  }
    51  
    52  type ClientTestEntity2 struct {
    53  	dosaRenamed.Entity `dosa:"primaryKey=(UUID,Color)"`
    54  	SearchByColor      dosaRenamed.Index `dosa:"key=Color"`
    55  	UUID               string
    56  	Color              string
    57  	IsActive           bool
    58  	ignoreme           int32
    59  }
    60  
    61  var (
    62  	cte1          = &ClientTestEntity1{ID: int64(1), Name: "foo", Email: "foo@uber.com"}
    63  	cte2          = &ClientTestEntity2{UUID: "b1f23fa3-f453-45b4-a5d5-6d73078ac3bd", Color: "blue", IsActive: true}
    64  	ctx           = context.TODO()
    65  	scope         = "test"
    66  	namePrefix    = "team.service"
    67  	nullConnector dosaRenamed.Connector
    68  )
    69  
    70  func init() {
    71  	nullConnector, _ = dosaRenamed.GetConnector("devnull", nil)
    72  }
    73  
    74  // ExampleNewClient initializes a client using the devnull connector, which discards all
    75  // the data you send it and always returns no rows. It's only useful for testing dosa.
    76  func ExampleNewClient() {
    77  	// initialize registrar
    78  	reg, err := dosaRenamed.NewRegistrar("test", "myteam.myservice", cte1)
    79  	if err != nil {
    80  		// registration will fail if the object is tagged incorrectly
    81  		fmt.Printf("NewRegistrar error: %s", err)
    82  		return
    83  	}
    84  
    85  	// use a devnull connector for example purposes
    86  	conn, err := dosaRenamed.GetConnector("devnull", nil)
    87  	if err != nil {
    88  		fmt.Printf("GetConnector error: %s", err)
    89  		return
    90  	}
    91  
    92  	// create the client using the registry and connector
    93  	client := dosaRenamed.NewClient(reg, conn)
    94  
    95  	err = client.Initialize(context.Background())
    96  	if err != nil {
    97  		fmt.Printf("Initialize error: %s", err)
    98  		return
    99  	}
   100  }
   101  
   102  // ExampleGetConnector gets an in-memory connector that can be used for testing your code.
   103  // The in-memory connector always starts off with no rows, so you'll need to add rows to
   104  // your "database" before reading them
   105  func ExampleGetConnector() {
   106  	// register your entities so the engine can separate your data based on table names.
   107  	// Scopes and prefixes are not used by the in-memory connector, and are ignored, but
   108  	// your list of entities is important. In this case, we only have one, our ClientTestEntity1
   109  	reg, err := dosaRenamed.NewRegistrar("test", "myteam.myservice", &ClientTestEntity1{})
   110  	if err != nil {
   111  		fmt.Printf("NewRegistrar error: %s", err)
   112  		return
   113  	}
   114  
   115  	// Find the memory connector. There is no configuration information so pass a nil
   116  	// For this to work, you must force the init method of memory to run first, which happens
   117  	// when we imported memory in the import list, with an underscore to just get the side effects
   118  	conn, _ := dosaRenamed.GetConnector("memory", nil)
   119  
   120  	// now construct a client from the registry and the connector
   121  	client := dosaRenamed.NewClient(reg, conn)
   122  
   123  	// initialize the client; this should always work for the in-memory connector
   124  	if err = client.Initialize(context.Background()); err != nil {
   125  		fmt.Printf("Initialize error: %s", err)
   126  		return
   127  	}
   128  
   129  	// now populate an entity and insert it into the memory store
   130  	if err := client.CreateIfNotExists(context.Background(), &ClientTestEntity1{
   131  		ID:    int64(1),
   132  		Name:  "rkuris",
   133  		Email: "rkuris@uber.com"}); err != nil {
   134  		fmt.Printf("CreateIfNotExists error: %s", err)
   135  		return
   136  	}
   137  
   138  	// create an entity to hold the read result, just populate the key
   139  	e := ClientTestEntity1{ID: int64(1)}
   140  	// now read the data from the "database", all columns
   141  	err = client.Read(context.Background(), dosaRenamed.All(), &e)
   142  	if err != nil {
   143  		fmt.Printf("Read error: %s", err)
   144  		return
   145  	}
   146  	// great! It worked, so display the information we stored earlier
   147  	fmt.Printf("id:%d Name:%q Email:%q\n", e.ID, e.Name, e.Email)
   148  	// Output: id:1 Name:"rkuris" Email:"rkuris@uber.com"
   149  }
   150  
   151  func testAssert(t *testing.T) testutil.TestAssertFn {
   152  	return func(a, b interface{}) {
   153  		assert.Equal(t, a, b)
   154  	}
   155  }
   156  
   157  func TestNewClient(t *testing.T) {
   158  	// initialize registrar
   159  	reg, err := dosaRenamed.NewRegistrar("test", "myteam.myservice", cte1)
   160  	assert.NoError(t, err)
   161  	assert.NotNil(t, reg)
   162  
   163  	// initialize a pseudo-connected client
   164  	client := dosaRenamed.NewClient(reg, nullConnector)
   165  	err = client.Initialize(ctx)
   166  	assert.NoError(t, err)
   167  }
   168  
   169  func TestClient_Initialize(t *testing.T) {
   170  	ctrl := gomock.NewController(t)
   171  	defer ctrl.Finish()
   172  	emptyReg, _ := dosaRenamed.NewRegistrar("test", "team.service")
   173  	reg, _ := dosaRenamed.NewRegistrar("test", "team.service", cte1)
   174  
   175  	// find error
   176  	c1 := dosaRenamed.NewClient(emptyReg, nullConnector)
   177  	assert.Error(t, c1.Initialize(ctx))
   178  
   179  	// CheckSchema error
   180  	errConn := mocks.NewMockConnector(ctrl)
   181  	errConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(-1), errors.New("CheckSchema error")).AnyTimes()
   182  	c2 := dosaRenamed.NewClient(reg, errConn)
   183  	assert.Error(t, c2.Initialize(ctx))
   184  
   185  	// happy path
   186  	c3 := dosaRenamed.NewClient(reg, nullConnector)
   187  	assert.NoError(t, c3.Initialize(ctx))
   188  
   189  	// already initialized
   190  	assert.NoError(t, c3.Initialize(ctx))
   191  }
   192  
   193  func TestClient_Read(t *testing.T) {
   194  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   195  	reg2, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1, cte2)
   196  	fieldsToRead := []string{"ID", "Email"}
   197  	results := map[string]dosaRenamed.FieldValue{
   198  		"id":    int64(2),
   199  		"name":  "bar",
   200  		"email": "bar@email.com",
   201  	}
   202  
   203  	// uninitialized
   204  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   205  	assert.Error(t, c1.Read(ctx, fieldsToRead, cte1))
   206  
   207  	// unregistered object
   208  	c1.Initialize(ctx)
   209  	err := c1.Read(ctx, dosaRenamed.All(), cte2)
   210  	assert.Error(t, err)
   211  	assert.Contains(t, err.Error(), "ClientTestEntity2")
   212  
   213  	// happy path, mock connector
   214  	ctrl := gomock.NewController(t)
   215  	defer ctrl.Finish()
   216  	mockConn := mocks.NewMockConnector(ctrl)
   217  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   218  	mockConn.EXPECT().Read(ctx, gomock.Any(), gomock.Any(), gomock.Any()).
   219  		Do(func(_ context.Context, _ *dosaRenamed.EntityInfo, columnValues map[string]dosaRenamed.FieldValue, columnsToRead []string) {
   220  			assert.Equal(t, columnValues["id"], cte1.ID)
   221  			assert.Equal(t, columnsToRead, []string{"id", "email"})
   222  
   223  		}).Return(results, nil).MinTimes(1)
   224  	c3 := dosaRenamed.NewClient(reg2, mockConn)
   225  	assert.NoError(t, c3.Initialize(ctx))
   226  	assert.NoError(t, c3.Read(ctx, fieldsToRead, cte1))
   227  	assert.Equal(t, cte1.ID, results["id"])
   228  	assert.NotEqual(t, cte1.Name, results["name"])
   229  	assert.Equal(t, cte1.Email, results["email"])
   230  }
   231  
   232  func TestClient_Read_pointer_result(t *testing.T) {
   233  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   234  	reg2, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1, cte2)
   235  	fieldsToRead := []string{"ID", "Email"}
   236  	results := map[string]dosaRenamed.FieldValue{
   237  		"id":    testutil.TestInt64Ptr(int64(2)),
   238  		"name":  testutil.TestStringPtr("bar"),
   239  		"email": testutil.TestStringPtr("bar@email.com"),
   240  	}
   241  
   242  	// uninitialized
   243  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   244  	assert.Error(t, c1.Read(ctx, fieldsToRead, cte1))
   245  
   246  	// unregistered object
   247  	c1.Initialize(ctx)
   248  	err := c1.Read(ctx, dosaRenamed.All(), cte2)
   249  	assert.Error(t, err)
   250  	assert.Contains(t, err.Error(), "ClientTestEntity2")
   251  
   252  	// happy path, mock connector
   253  	ctrl := gomock.NewController(t)
   254  	defer ctrl.Finish()
   255  	mockConn := mocks.NewMockConnector(ctrl)
   256  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   257  	mockConn.EXPECT().Read(ctx, gomock.Any(), gomock.Any(), gomock.Any()).
   258  		Do(func(_ context.Context, _ *dosaRenamed.EntityInfo, columnValues map[string]dosaRenamed.FieldValue, columnsToRead []string) {
   259  			assert.Equal(t, columnValues["id"], cte1.ID)
   260  			assert.Equal(t, columnsToRead, []string{"id", "email"})
   261  
   262  		}).Return(results, nil).MinTimes(1)
   263  	c3 := dosaRenamed.NewClient(reg2, mockConn)
   264  	assert.NoError(t, c3.Initialize(ctx))
   265  	assert.NoError(t, c3.Read(ctx, fieldsToRead, cte1))
   266  	testutil.AssertEqForPointer(testAssert(t), cte1.ID, results["id"])
   267  	assert.NotEqual(t, cte1.Name, results["name"])
   268  	testutil.AssertEqForPointer(testAssert(t), cte1.Email, results["email"])
   269  }
   270  
   271  type AllFieldTypes struct {
   272  	dosaRenamed.Entity `dosa:"primaryKey=ID"`
   273  	ID                 int64
   274  	BoolType           bool
   275  	Int32Type          int32
   276  	Int64Type          int64
   277  	DoubleType         float64
   278  	StringType         string
   279  	BlobType           []byte
   280  	TimeType           time.Time
   281  	UUIDType           dosaRenamed.UUID
   282  	NullBoolType       *bool
   283  	NullInt32Type      *int32
   284  	NullInt64Type      *int64
   285  	NullDoubleType     *float64
   286  	NullStringType     *string
   287  	NullTimeType       *time.Time
   288  	NullUUIDType       *dosaRenamed.UUID
   289  }
   290  
   291  func TestClient_Read_pointer(t *testing.T) {
   292  	allTypes := &AllFieldTypes{ID: int64(3212)}
   293  	reg1, err := dosaRenamed.NewRegistrar(scope, namePrefix, allTypes)
   294  	assert.NoError(t, err)
   295  	results := map[string]dosaRenamed.FieldValue{
   296  		"id":             int64(3212),
   297  		"booltype":       true,
   298  		"int32type":      int32(1),
   299  		"int64type":      int64(2),
   300  		"doubletype":     float64(8.9),
   301  		"stringtype":     "faa@email.com",
   302  		"blobtype":       []byte("hello world"),
   303  		"timetype":       time.Now(),
   304  		"uuidtype":       dosaRenamed.NewUUID(),
   305  		"nullbooltype":   testutil.TestBoolPtr(true),
   306  		"nullint32type":  testutil.TestInt32Ptr(int32(123)),
   307  		"nullint64type":  testutil.TestInt64Ptr(int64(2)),
   308  		"nulldoubletype": testutil.TestFloat64Ptr(float64(8.9)),
   309  		"nullstringtype": testutil.TestStringPtr("bar@email.com"),
   310  		"nulltimetype":   testutil.TestTimePtr(time.Now()),
   311  		"nulluuidtype":   testutil.TestUUIDPtr(dosaRenamed.NewUUID()),
   312  	}
   313  
   314  	// uninitialized
   315  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   316  	assert.Error(t, c1.Read(ctx, dosaRenamed.All(), allTypes))
   317  
   318  	// happy path, mock connector
   319  	ctrl := gomock.NewController(t)
   320  	defer ctrl.Finish()
   321  	mockConn := mocks.NewMockConnector(ctrl)
   322  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   323  	mockConn.EXPECT().Read(ctx, gomock.Any(), gomock.Any(), gomock.Any()).
   324  		Do(func(_ context.Context, _ *dosaRenamed.EntityInfo, columnValues map[string]dosaRenamed.FieldValue, columnsToRead []string) {
   325  			assert.Equal(t, columnValues["id"], allTypes.ID)
   326  		}).Return(results, nil).MinTimes(1)
   327  	c3 := dosaRenamed.NewClient(reg1, mockConn)
   328  	assert.NoError(t, c3.Initialize(ctx))
   329  	assert.NoError(t, c3.Read(ctx, dosaRenamed.All(), allTypes))
   330  	assert.Equal(t, allTypes.ID, results["id"])
   331  	assert.Equal(t, allTypes.BoolType, results["booltype"])
   332  	assert.Equal(t, allTypes.Int32Type, results["int32type"])
   333  	assert.Equal(t, allTypes.Int64Type, results["int64type"])
   334  	assert.Equal(t, allTypes.DoubleType, results["doubletype"])
   335  	assert.Equal(t, allTypes.StringType, results["stringtype"])
   336  	assert.Equal(t, allTypes.BlobType, results["blobtype"])
   337  	assert.Equal(t, allTypes.TimeType, results["timetype"])
   338  	assert.Equal(t, allTypes.UUIDType, results["uuidtype"])
   339  	testutil.AssertEqForPointer(testAssert(t), *allTypes.NullBoolType, results["nullbooltype"])
   340  	testutil.AssertEqForPointer(testAssert(t), *allTypes.NullInt32Type, results["nullint32type"])
   341  	testutil.AssertEqForPointer(testAssert(t), *allTypes.NullInt64Type, results["nullint64type"])
   342  	testutil.AssertEqForPointer(testAssert(t), *allTypes.NullDoubleType, results["nulldoubletype"])
   343  	testutil.AssertEqForPointer(testAssert(t), *allTypes.NullStringType, results["nullstringtype"])
   344  	testutil.AssertEqForPointer(testAssert(t), *allTypes.NullTimeType, results["nulltimetype"])
   345  	testutil.AssertEqForPointer(testAssert(t), *allTypes.NullUUIDType, results["nulluuidtype"])
   346  }
   347  
   348  func TestClient_Read_Errors(t *testing.T) {
   349  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   350  	ctrl := gomock.NewController(t)
   351  	defer ctrl.Finish()
   352  	readError := errors.New("oops")
   353  	mockConn := mocks.NewMockConnector(ctrl)
   354  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   355  	mockConn.EXPECT().Read(ctx, gomock.Any(), gomock.Any(), gomock.Any()).
   356  		Do(func(_ context.Context, _ *dosaRenamed.EntityInfo, columnValues map[string]dosaRenamed.FieldValue, columnsToRead []string) {
   357  			assert.Equal(t, columnValues["id"], cte1.ID)
   358  			assert.NotEmpty(t, columnsToRead)
   359  		}).Return(nil, readError)
   360  
   361  	c1 := dosaRenamed.NewClient(reg1, mockConn)
   362  	assert.NoError(t, c1.Initialize(ctx))
   363  	err := c1.Read(ctx, dosaRenamed.All(), cte1)
   364  	assert.Error(t, err)
   365  	assert.Equal(t, err, readError)
   366  	err = c1.Read(ctx, []string{"badcol"}, cte1)
   367  	assert.Error(t, err)
   368  	assert.Contains(t, err.Error(), "badcol")
   369  }
   370  
   371  func TestClient_Upsert(t *testing.T) {
   372  	reg1, _ := dosaRenamed.NewRegistrar("test", "team.service", cte1)
   373  	reg2, _ := dosaRenamed.NewRegistrar("test", "team.service", cte1, cte2)
   374  	fieldsToUpdate := []string{"Email"}
   375  	updatedEmail := "bar@email.com"
   376  
   377  	// uninitialized
   378  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   379  	assert.Error(t, c1.Upsert(ctx, fieldsToUpdate, cte1))
   380  
   381  	// unregistered object error
   382  	c2 := dosaRenamed.NewClient(reg1, nullConnector)
   383  	c2.Initialize(ctx)
   384  	assert.Error(t, c2.Upsert(ctx, fieldsToUpdate, cte2))
   385  
   386  	// happy path, mock connector
   387  	ctrl := gomock.NewController(t)
   388  	defer ctrl.Finish()
   389  	mockConn := mocks.NewMockConnector(ctrl)
   390  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   391  	mockConn.EXPECT().Upsert(ctx, gomock.Any(), gomock.Any()).
   392  		Do(func(_ context.Context, _ *dosaRenamed.EntityInfo, columnValues map[string]dosaRenamed.FieldValue) {
   393  			assert.Equal(t, columnValues["id"], cte1.ID)
   394  			assert.Equal(t, columnValues["email"], cte1.Email)
   395  			cte1.Email = updatedEmail
   396  		}).
   397  		Return(nil).MinTimes(1)
   398  	c3 := dosaRenamed.NewClient(reg2, mockConn)
   399  	assert.NoError(t, c3.Initialize(ctx))
   400  	assert.NoError(t, c3.Upsert(ctx, fieldsToUpdate, cte1))
   401  	assert.Equal(t, cte1.Email, updatedEmail)
   402  }
   403  func TestClient_CreateIfNotExists(t *testing.T) {
   404  	reg1, _ := dosaRenamed.NewRegistrar("test", "team.service", cte1)
   405  	reg2, _ := dosaRenamed.NewRegistrar("test", "team.service", cte1, cte2)
   406  	updatedEmail := "bar@email.com"
   407  
   408  	// uninitialized
   409  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   410  	assert.Error(t, c1.CreateIfNotExists(ctx, cte1))
   411  
   412  	// unregistered object error
   413  	c2 := dosaRenamed.NewClient(reg1, nullConnector)
   414  	c2.Initialize(ctx)
   415  	assert.Error(t, c2.CreateIfNotExists(ctx, cte2))
   416  
   417  	// happy path, mock connector
   418  	ctrl := gomock.NewController(t)
   419  	defer ctrl.Finish()
   420  	mockConn := mocks.NewMockConnector(ctrl)
   421  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   422  	mockConn.EXPECT().CreateIfNotExists(ctx, gomock.Any(), gomock.Any()).
   423  		Do(func(_ context.Context, _ *dosaRenamed.EntityInfo, columnValues map[string]dosaRenamed.FieldValue) {
   424  			assert.Equal(t, columnValues["id"], cte1.ID)
   425  			assert.Equal(t, columnValues["email"], cte1.Email)
   426  			cte1.Email = updatedEmail
   427  		}).
   428  		Return(nil).MinTimes(1)
   429  	c3 := dosaRenamed.NewClient(reg2, mockConn)
   430  	assert.NoError(t, c3.Initialize(ctx))
   431  	assert.NoError(t, c3.CreateIfNotExists(ctx, cte1))
   432  	assert.Equal(t, cte1.Email, updatedEmail)
   433  }
   434  
   435  func TestClient_Upsert_Errors(t *testing.T) {
   436  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   437  	ctrl := gomock.NewController(t)
   438  	defer ctrl.Finish()
   439  	readError := errors.New("oops")
   440  	mockConn := mocks.NewMockConnector(ctrl)
   441  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   442  
   443  	c1 := dosaRenamed.NewClient(reg1, mockConn)
   444  	assert.NoError(t, c1.Initialize(ctx))
   445  	mockConn.EXPECT().Upsert(ctx, gomock.Any(), gomock.Not(dosaRenamed.All())).Return(nil)
   446  	err := c1.Upsert(ctx, dosaRenamed.All(), cte1)
   447  	assert.NoError(t, err)
   448  
   449  	mockConn.EXPECT().Upsert(ctx, gomock.Any(), map[string]dosaRenamed.FieldValue{"id": dosaRenamed.FieldValue(int64(2))}).Return(readError)
   450  	err = c1.Upsert(ctx, []string{"ID"}, cte1)
   451  	assert.Error(t, err)
   452  	assert.Equal(t, err, readError)
   453  	err = c1.Upsert(ctx, []string{"badcol"}, cte1)
   454  	assert.Error(t, err)
   455  	assert.Contains(t, err.Error(), "badcol")
   456  }
   457  
   458  func TestClient_RemoveRange(t *testing.T) {
   459  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   460  
   461  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   462  	rop := dosaRenamed.NewRemoveRangeOp(cte1).Eq("ID", "123")
   463  	err := c1.RemoveRange(ctx, rop)
   464  	assert.True(t, dosaRenamed.ErrorIsNotInitialized(err))
   465  
   466  	c1.Initialize(ctx)
   467  
   468  	//bad entity
   469  	rop = dosaRenamed.NewRemoveRangeOp(cte2)
   470  	err = c1.RemoveRange(ctx, rop)
   471  	assert.Error(t, err)
   472  	assert.Contains(t, err.Error(), "ClientTestEntity2")
   473  
   474  	// bad column in range
   475  	rop = dosaRenamed.NewRemoveRangeOp(cte1).Eq("borkborkbork", int64(1))
   476  	err = c1.RemoveRange(ctx, rop)
   477  	assert.Error(t, err)
   478  	assert.Contains(t, err.Error(), "ClientTestEntity1")
   479  	assert.Contains(t, err.Error(), "borkborkbork")
   480  
   481  	// success case
   482  	ctrl := gomock.NewController(t)
   483  	defer ctrl.Finish()
   484  	mockConn := mocks.NewMockConnector(ctrl)
   485  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   486  	mockConn.EXPECT().RemoveRange(ctx, gomock.Any(), gomock.Any()).Return(nil)
   487  	c2 := dosaRenamed.NewClient(reg1, mockConn)
   488  	c2.Initialize(ctx)
   489  	rop = dosaRenamed.NewRemoveRangeOp(cte1)
   490  	err = c2.RemoveRange(ctx, rop)
   491  	assert.NoError(t, err)
   492  }
   493  
   494  func TestClient_Range(t *testing.T) {
   495  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   496  	fieldsToRead := []string{"ID", "Email"}
   497  	resultRow := map[string]dosaRenamed.FieldValue{
   498  		"id":    int64(2),
   499  		"name":  "bar",
   500  		"email": "bar@email.com",
   501  	}
   502  
   503  	// uninitialized
   504  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   505  	rop := dosaRenamed.NewRangeOp(cte1).Fields(fieldsToRead).Eq("ID", "123").Offset("tokeytoketoke")
   506  	_, _, err := c1.Range(ctx, rop)
   507  	assert.True(t, dosaRenamed.ErrorIsNotInitialized(err))
   508  
   509  	c1.Initialize(ctx)
   510  
   511  	// bad entity
   512  	rop = dosaRenamed.NewRangeOp(cte2)
   513  	_, _, err = c1.Range(ctx, rop)
   514  	assert.Error(t, err)
   515  	assert.Contains(t, err.Error(), "ClientTestEntity2")
   516  
   517  	// bad column in range
   518  	// we don't test other failed RangeOpConditions since those are unit tested elsewhere
   519  	rop = dosaRenamed.NewRangeOp(cte1).Eq("borkborkbork", int64(1))
   520  	_, _, err = c1.Range(ctx, rop)
   521  	assert.Error(t, err)
   522  	assert.Contains(t, err.Error(), "ClientTestEntity1")
   523  	assert.Contains(t, err.Error(), "borkborkbork")
   524  
   525  	// bad projected column
   526  	rop = dosaRenamed.NewRangeOp(cte1).Fields([]string{"borkborkbork"})
   527  	_, _, err = c1.Range(ctx, rop)
   528  	assert.Error(t, err)
   529  	assert.Contains(t, err.Error(), "ClientTestEntity1")
   530  	assert.Contains(t, err.Error(), "borkborkbork")
   531  
   532  	// success case
   533  	ctrl := gomock.NewController(t)
   534  	defer ctrl.Finish()
   535  	mockConn := mocks.NewMockConnector(ctrl)
   536  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   537  	mockConn.EXPECT().Range(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   538  		Return([]map[string]dosaRenamed.FieldValue{resultRow}, "continuation-token", nil)
   539  	c2 := dosaRenamed.NewClient(reg1, mockConn)
   540  	c2.Initialize(ctx)
   541  	rop = dosaRenamed.NewRangeOp(cte1)
   542  	rows, token, err := c2.Range(ctx, rop)
   543  	assert.NoError(t, err)
   544  	assert.NotNil(t, rows)
   545  	assert.Equal(t, 1, len(rows))
   546  	for _, obj := range rows {
   547  		assert.Equal(t, resultRow["id"], obj.(*ClientTestEntity1).ID)
   548  		assert.Equal(t, resultRow["name"], obj.(*ClientTestEntity1).Name)
   549  		assert.Equal(t, resultRow["email"], obj.(*ClientTestEntity1).Email)
   550  	}
   551  	assert.Equal(t, "continuation-token", token)
   552  
   553  	// no resulting rows, just use the devnull connector
   554  	rop = dosaRenamed.NewRangeOp(cte1)
   555  	_, _, err = c1.Range(ctx, rop)
   556  	assert.True(t, dosaRenamed.ErrorIsNotFound(err))
   557  }
   558  
   559  func TestClient_WalkRange(t *testing.T) {
   560  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   561  	fieldsToRead := []string{"ID", "Email"}
   562  	resultRow0 := map[string]dosaRenamed.FieldValue{
   563  		"id":    int64(2),
   564  		"name":  "bar",
   565  		"email": "bar@email.com",
   566  	}
   567  	resultRow1 := map[string]dosaRenamed.FieldValue{
   568  		"id":    int64(3),
   569  		"name":  "jeff",
   570  		"email": "jeff@email.com",
   571  	}
   572  
   573  	// uninitialized
   574  	c0 := dosaRenamed.NewClient(reg1, nullConnector)
   575  	rop := dosaRenamed.NewRangeOp(cte1).Fields(fieldsToRead).Eq("ID", "123").Offset("tokeytoketoke")
   576  	err := c0.WalkRange(ctx, rop, func(value dosaRenamed.DomainObject) error {
   577  		return nil
   578  	})
   579  	assert.True(t, dosaRenamed.ErrorIsNotInitialized(err))
   580  
   581  	// success case
   582  	ctrl := gomock.NewController(t)
   583  	defer ctrl.Finish()
   584  	mockConn1 := mocks.NewMockConnector(ctrl)
   585  	mockConn1.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   586  	mockConn1.EXPECT().Range(ctx, gomock.Any(), gomock.Any(), gomock.Any(), "", gomock.Any()).
   587  		Return([]map[string]dosaRenamed.FieldValue{resultRow0}, "token0", nil)
   588  	mockConn1.EXPECT().Range(ctx, gomock.Any(), gomock.Any(), gomock.Any(), "token0", gomock.Any()).
   589  		Return([]map[string]dosaRenamed.FieldValue{resultRow1}, "", nil)
   590  	c1 := dosaRenamed.NewClient(reg1, mockConn1)
   591  	c1.Initialize(ctx)
   592  	rop = dosaRenamed.NewRangeOp(cte1)
   593  
   594  	var fetched []*ClientTestEntity1
   595  	err = c1.WalkRange(ctx, rop, func(value dosaRenamed.DomainObject) error {
   596  		fetched = append(fetched, value.(*ClientTestEntity1))
   597  		return nil
   598  	})
   599  	assert.NoError(t, err)
   600  	assert.NotNil(t, fetched)
   601  	assert.Equal(t, 2, len(fetched))
   602  	assert.Equal(t, resultRow0["id"], fetched[0].ID)
   603  	assert.Equal(t, resultRow0["name"], fetched[0].Name)
   604  	assert.Equal(t, resultRow0["email"], fetched[0].Email)
   605  	assert.Equal(t, resultRow1["id"], fetched[1].ID)
   606  	assert.Equal(t, resultRow1["name"], fetched[1].Name)
   607  	assert.Equal(t, resultRow1["email"], fetched[1].Email)
   608  
   609  	// Range with closure error
   610  	mockConn2 := mocks.NewMockConnector(ctrl)
   611  	mockConn2.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil)
   612  	mockConn2.EXPECT().Range(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   613  		Return([]map[string]dosaRenamed.FieldValue{resultRow0}, "", nil)
   614  	c2 := dosaRenamed.NewClient(reg1, mockConn2)
   615  	c2.Initialize(ctx)
   616  	rop = dosaRenamed.NewRangeOp(cte1)
   617  	err = c2.WalkRange(ctx, rop, func(value dosaRenamed.DomainObject) error {
   618  		return errors.New("woops!")
   619  	})
   620  	assert.EqualError(t, err, "woops!")
   621  }
   622  
   623  func TestClient_ScanEverything(t *testing.T) {
   624  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   625  	fieldsToRead := []string{"ID", "Email"}
   626  	resultRow := map[string]dosaRenamed.FieldValue{
   627  		"id":          int64(2),
   628  		"name":        "bar",
   629  		"email":       "bar@email.com",
   630  		"straycolumn": "this_should_be_discarded",
   631  	}
   632  
   633  	// uninitialized
   634  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   635  	sop := dosaRenamed.NewScanOp(cte1).Fields(fieldsToRead).Offset("tokeytoketoke")
   636  	_, _, err := c1.ScanEverything(ctx, sop)
   637  	assert.True(t, dosaRenamed.ErrorIsNotInitialized(err))
   638  
   639  	c1.Initialize(ctx)
   640  
   641  	// bad entity
   642  	sop = dosaRenamed.NewScanOp(cte2)
   643  	_, _, err = c1.ScanEverything(ctx, sop)
   644  	assert.Error(t, err)
   645  	assert.Contains(t, err.Error(), "ClientTestEntity2")
   646  
   647  	// bad projected column
   648  	sop = dosaRenamed.NewScanOp(cte1).Fields([]string{"borkborkbork"})
   649  	_, _, err = c1.ScanEverything(ctx, sop)
   650  	assert.Error(t, err)
   651  	assert.Contains(t, err.Error(), "ClientTestEntity1")
   652  	assert.Contains(t, err.Error(), "borkborkbork")
   653  
   654  	// success case
   655  	ctrl := gomock.NewController(t)
   656  	defer ctrl.Finish()
   657  	mockConn := mocks.NewMockConnector(ctrl)
   658  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   659  	mockConn.EXPECT().Scan(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
   660  		Return([]map[string]dosaRenamed.FieldValue{resultRow}, "continuation-token", nil)
   661  	c2 := dosaRenamed.NewClient(reg1, mockConn)
   662  	c2.Initialize(ctx)
   663  	sop = dosaRenamed.NewScanOp(cte1)
   664  	rows, token, err := c2.ScanEverything(ctx, sop)
   665  	assert.NoError(t, err)
   666  	assert.NotNil(t, rows)
   667  	assert.Equal(t, 1, len(rows))
   668  	for _, obj := range rows {
   669  		assert.Equal(t, resultRow["id"], obj.(*ClientTestEntity1).ID)
   670  		assert.Equal(t, resultRow["name"], obj.(*ClientTestEntity1).Name)
   671  		assert.Equal(t, resultRow["email"], obj.(*ClientTestEntity1).Email)
   672  	}
   673  	assert.Equal(t, "continuation-token", token)
   674  
   675  	// no resulting rows, just use the devnull connector
   676  	sop = dosaRenamed.NewScanOp(cte1)
   677  	_, _, err = c1.ScanEverything(ctx, sop)
   678  	assert.True(t, dosaRenamed.ErrorIsNotFound(err))
   679  }
   680  
   681  func TestClient_Remove(t *testing.T) {
   682  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   683  
   684  	// uninitialized
   685  	c1 := dosaRenamed.NewClient(reg1, nullConnector)
   686  	err := c1.Remove(ctx, cte1)
   687  	assert.True(t, dosaRenamed.ErrorIsNotInitialized(err))
   688  
   689  	c1.Initialize(ctx)
   690  
   691  	// bad entity
   692  	err = c1.Remove(ctx, cte2)
   693  	assert.Error(t, err)
   694  	assert.Contains(t, err.Error(), "ClientTestEntity2")
   695  	// success case
   696  	ctrl := gomock.NewController(t)
   697  	defer ctrl.Finish()
   698  	mockConn := mocks.NewMockConnector(ctrl)
   699  	mockConn.EXPECT().CheckSchema(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(int32(1), nil).AnyTimes()
   700  	mockConn.EXPECT().Remove(ctx, gomock.Any(), map[string]dosaRenamed.FieldValue{"id": dosaRenamed.FieldValue(int64(123))}).Return(nil)
   701  	c2 := dosaRenamed.NewClient(reg1, mockConn)
   702  	c2.Initialize(ctx)
   703  	err = c2.Remove(ctx, &ClientTestEntity1{ID: int64(123)})
   704  	assert.NoError(t, err)
   705  
   706  }
   707  
   708  /* TODO: Coming in v2.1
   709  func TestClient_Unimplemented(t *testing.T) {
   710  	reg1, _ := dosaRenamed.NewRegistrar(scope, namePrefix, cte1)
   711  
   712  	c := dosaRenamed.NewClient(reg1, nullConnector)
   713  	assert.Panics(t, func() {
   714  		c.MultiRead(ctx, dosaRenamed.All(), &ClientTestEntity1{})
   715  	})
   716  	assert.Panics(t, func() {
   717  		c.MultiUpsert(ctx, dosaRenamed.All(), &ClientTestEntity1{})
   718  	})
   719  	assert.Panics(t, func() {
   720  		c.MultiRemove(ctx, &ClientTestEntity1{})
   721  	})
   722  }
   723  */
   724  
   725  func TestAdminClient_CreateScope(t *testing.T) {
   726  	c := dosaRenamed.NewAdminClient(nullConnector)
   727  	assert.NotNil(t, c)
   728  
   729  	err := c.CreateScope(context.TODO(), scope)
   730  	assert.NoError(t, err)
   731  }
   732  
   733  func TestAdminClient_TruncateScope(t *testing.T) {
   734  	c := dosaRenamed.NewAdminClient(nullConnector)
   735  	assert.NotNil(t, c)
   736  
   737  	err := c.TruncateScope(context.TODO(), scope)
   738  	assert.NoError(t, err)
   739  }
   740  
   741  func TestAdminClient_DropScope(t *testing.T) {
   742  	c := dosaRenamed.NewAdminClient(nullConnector)
   743  	assert.NotNil(t, c)
   744  
   745  	err := c.DropScope(context.TODO(), scope)
   746  	assert.NoError(t, err)
   747  }
   748  
   749  func TestAdminClient_CheckSchema(t *testing.T) {
   750  	// write some entities to disk
   751  	tmpdir := ".testcheckschema"
   752  	os.RemoveAll(tmpdir)
   753  	defer os.RemoveAll(tmpdir)
   754  	content := `
   755  package main
   756  
   757  import "github.com/uber-go/dosa"
   758  
   759  type TestEntityA struct {
   760  	dosa.Entity ` + "`dosa:\"primaryKey=(ID)\"`" + `
   761  	ID int32
   762  }
   763  type TestEntityB struct {
   764  	dosa.Entity ` + "`dosa:\"primaryKey=(ID)\"`" + `
   765  	ID int32
   766  }
   767  `
   768  	assert.NoError(t, os.MkdirAll(tmpdir, 0770))
   769  	assert.NoError(t, ioutil.WriteFile(filepath.Join(tmpdir, "f1.go"), []byte(content), 0700))
   770  
   771  	data := []struct {
   772  		dirs        []string
   773  		excludes    []string
   774  		scope       string
   775  		namePrefix  string
   776  		errContains string
   777  	}{
   778  		// cannot get schema
   779  		{
   780  			dirs:        []string{"/foo/bar/baz"},
   781  			scope:       scope,
   782  			errContains: "/foo/bar/baz",
   783  		},
   784  		// connector error
   785  		{
   786  			dirs:        []string{tmpdir},
   787  			scope:       scope,
   788  			namePrefix:  "error",
   789  			errContains: "connector error",
   790  		},
   791  		// happy path
   792  		{
   793  			dirs:       []string{tmpdir},
   794  			scope:      scope,
   795  			namePrefix: namePrefix,
   796  		},
   797  	}
   798  
   799  	// calls with "error" prefix will fail, rest succeed
   800  	ctrl := gomock.NewController(t)
   801  	defer ctrl.Finish()
   802  	mockConn := mocks.NewMockConnector(ctrl)
   803  	mockConn.EXPECT().CheckSchema(ctx, scope, "error", gomock.Any()).Return(int32(-1), errors.New("connector error")).Times(1)
   804  	mockConn.EXPECT().CheckSchema(ctx, scope, namePrefix, gomock.Any()).Return(int32(1), nil).Times(1)
   805  
   806  	for _, d := range data {
   807  		_, err := dosaRenamed.NewAdminClient(mockConn).
   808  			Directories(d.dirs).
   809  			Scope(d.scope).
   810  			CheckSchema(ctx, d.namePrefix)
   811  		if d.errContains != "" {
   812  			assert.Contains(t, err.Error(), d.errContains)
   813  			continue
   814  		}
   815  		assert.NoError(t, err)
   816  	}
   817  }
   818  
   819  func TestAdminClient_CheckSchemaStatus(t *testing.T) {
   820  	data := []struct {
   821  		version     int32
   822  		scope       string
   823  		namePrefix  string
   824  		errContains string
   825  	}{
   826  		{ // connector error
   827  			version:     int32(1),
   828  			scope:       scope,
   829  			namePrefix:  "error",
   830  			errContains: "connector error",
   831  		},
   832  		// happy path
   833  		{
   834  			version:    int32(1),
   835  			scope:      scope,
   836  			namePrefix: namePrefix,
   837  		},
   838  	}
   839  
   840  	// calls with "error" prefix will fail, rest succeed
   841  	ctrl := gomock.NewController(t)
   842  	defer ctrl.Finish()
   843  	mockConn := mocks.NewMockConnector(ctrl)
   844  	mockConn.EXPECT().CheckSchemaStatus(ctx, scope, "error", int32(1)).Return(nil, errors.New("connector error")).Times(1)
   845  	mockConn.EXPECT().CheckSchemaStatus(ctx, scope, namePrefix, gomock.Any()).Return(&dosaRenamed.SchemaStatus{Version: int32(1)}, nil).Times(1)
   846  
   847  	for _, d := range data {
   848  		status, err := dosaRenamed.NewAdminClient(mockConn).
   849  			Scope(d.scope).
   850  			CheckSchemaStatus(ctx, d.namePrefix, d.version)
   851  		if d.errContains != "" {
   852  			assert.Contains(t, err.Error(), d.errContains)
   853  			continue
   854  		}
   855  		assert.NoError(t, err)
   856  		assert.Equal(t, d.version, status.Version)
   857  	}
   858  }
   859  
   860  func TestAdminClient_UpsertSchema(t *testing.T) {
   861  	// write some entities to disk
   862  	tmpdir := ".testupsertschema"
   863  	os.RemoveAll(tmpdir)
   864  	defer os.RemoveAll(tmpdir)
   865  	content := `
   866  package main
   867  
   868  import "github.com/uber-go/dosa"
   869  
   870  type TestEntityA struct {
   871  	dosa.Entity ` + "`dosa:\"primaryKey=(ID)\"`" + `
   872  	ID int32
   873  }
   874  type TestEntityB struct {
   875  	dosa.Entity ` + "`dosa:\"primaryKey=(ID)\"`" + `
   876  	ID int32
   877  }
   878  `
   879  	assert.NoError(t, os.MkdirAll(tmpdir, 0770))
   880  	assert.NoError(t, ioutil.WriteFile(filepath.Join(tmpdir, "f1.go"), []byte(content), 0700))
   881  
   882  	data := []struct {
   883  		dirs        []string
   884  		scope       string
   885  		namePrefix  string
   886  		errContains string
   887  	}{
   888  		// cannot get schema
   889  		{
   890  			dirs:        []string{"/foo/bar/baz"},
   891  			scope:       scope,
   892  			errContains: "/foo/bar/baz",
   893  		},
   894  		// connector error
   895  		{
   896  			dirs:        []string{tmpdir},
   897  			scope:       scope,
   898  			namePrefix:  "error",
   899  			errContains: "connector error",
   900  		},
   901  		// happy path
   902  		{
   903  			dirs:       []string{tmpdir},
   904  			scope:      scope,
   905  			namePrefix: namePrefix,
   906  		},
   907  	}
   908  
   909  	// calls with "error" prefix will fail, rest succeed
   910  	ctrl := gomock.NewController(t)
   911  	defer ctrl.Finish()
   912  	mockConn := mocks.NewMockConnector(ctrl)
   913  	mockConn.EXPECT().UpsertSchema(ctx, scope, "error", gomock.Any()).Return(nil, errors.New("connector error")).Times(1)
   914  	mockConn.EXPECT().UpsertSchema(ctx, scope, namePrefix, gomock.Any()).Return(&dosaRenamed.SchemaStatus{Version: int32(1)}, nil).Times(1)
   915  
   916  	for _, d := range data {
   917  		_, err := dosaRenamed.NewAdminClient(mockConn).
   918  			Directories(d.dirs).
   919  			Scope(d.scope).
   920  			UpsertSchema(ctx, d.namePrefix)
   921  		if d.errContains != "" {
   922  			assert.Contains(t, err.Error(), d.errContains)
   923  			continue
   924  		}
   925  		assert.NoError(t, err)
   926  	}
   927  }
   928  
   929  func TestAdminClient_GetSchema(t *testing.T) {
   930  	// write some entities to disk
   931  	tmpdir := ".testgetschema"
   932  	os.RemoveAll(tmpdir)
   933  	defer os.RemoveAll(tmpdir)
   934  	path1 := filepath.Join(tmpdir, "f1.go")
   935  	path2 := filepath.Join(tmpdir, "f2.go")
   936  	content := `
   937  package main
   938  
   939  import renamed "github.com/uber-go/dosa"
   940  
   941  type TestEntityA struct {
   942  	renamed.Entity ` + "`dosa:\"primaryKey=(ID)\"`" + `
   943  	ID int32
   944  }
   945  type TestEntityB struct {
   946  	renamed.Entity ` + "`dosa:\"primaryKey=(ID)\"`" + `
   947  	ID renamed.UUID
   948  }
   949  `
   950  	invalid := `
   951  package main
   952  
   953  import "github.com/uber-go/dosa"
   954  
   955  type TestEntityC struct {
   956  	dosa.Entity ` + "`dosa:\"invalidtag\"`" + `
   957  	ID int32
   958  }
   959  `
   960  	assert.NoError(t, os.MkdirAll(tmpdir, 0770))
   961  	assert.NoError(t, ioutil.WriteFile(path1, []byte(content), 0700))
   962  	assert.NoError(t, ioutil.WriteFile(path2, []byte(invalid), 0700))
   963  
   964  	data := []struct {
   965  		dirs        []string
   966  		excludes    []string
   967  		scope       string
   968  		namePrefix  string
   969  		errContains string
   970  	}{
   971  		// invalid scope
   972  		{
   973  			scope:       "***",
   974  			errContains: "invalid scope name",
   975  		},
   976  		// invalid directory
   977  		{
   978  			dirs:        []string{"/foo/bar/baz"},
   979  			scope:       scope,
   980  			errContains: "/foo/bar/baz",
   981  		},
   982  		// no entities found
   983  		{
   984  			dirs:        []string{tmpdir},
   985  			excludes:    []string{"f1.go", "f2.go", "f3.go"},
   986  			scope:       scope,
   987  			errContains: "no entities found",
   988  		},
   989  		// invalid struct tag
   990  		{
   991  			dirs:        []string{tmpdir},
   992  			scope:       scope,
   993  			errContains: "invalidtag",
   994  		},
   995  	}
   996  
   997  	for _, d := range data {
   998  		_, err := dosaRenamed.NewAdminClient(nullConnector).
   999  			Directories(d.dirs).
  1000  			Excludes(d.excludes).
  1001  			Scope(d.scope).
  1002  			UpsertSchema(ctx, d.namePrefix)
  1003  		if d.errContains != "" {
  1004  			assert.Contains(t, err.Error(), d.errContains)
  1005  			continue
  1006  		}
  1007  		assert.NoError(t, err)
  1008  	}
  1009  }
  1010  
  1011  func TestErrorIsNotFound(t *testing.T) {
  1012  	assert.False(t, dosaRenamed.ErrorIsNotFound(errors.New("not a IsNotFound error")))
  1013  	assert.False(t, dosaRenamed.ErrorIsNotFound(&dosaRenamed.ErrNotInitialized{}))
  1014  	assert.True(t, dosaRenamed.ErrorIsNotFound(&dosaRenamed.ErrNotFound{}))
  1015  	assert.True(t, dosaRenamed.ErrorIsNotFound(errors.Wrap(&dosaRenamed.ErrNotFound{}, "wrapped")))
  1016  	assert.Equal(t, (&dosaRenamed.ErrNotFound{}).Error(), "not found")
  1017  }
  1018  
  1019  func TestErrNotInitialized_Error(t *testing.T) {
  1020  	assert.False(t, dosaRenamed.ErrorIsNotInitialized(errors.New("not a IsNotInitializedError")))
  1021  	assert.False(t, dosaRenamed.ErrorIsNotInitialized(&dosaRenamed.ErrNotFound{}))
  1022  	assert.True(t, dosaRenamed.ErrorIsNotInitialized(&dosaRenamed.ErrNotInitialized{}))
  1023  	assert.True(t, dosaRenamed.ErrorIsNotInitialized(errors.Wrap(&dosaRenamed.ErrNotInitialized{}, "wrapped")))
  1024  	assert.Equal(t, (&dosaRenamed.ErrNotInitialized{}).Error(), "client not initialized")
  1025  
  1026  }
  1027  
  1028  func TestErrorIsAlreadyExists(t *testing.T) {
  1029  	assert.False(t, dosaRenamed.ErrorIsAlreadyExists(errors.New("not an already exists error")))
  1030  	assert.False(t, dosaRenamed.ErrorIsAlreadyExists(&dosaRenamed.ErrNotInitialized{}))
  1031  	assert.False(t, dosaRenamed.ErrorIsAlreadyExists(&dosaRenamed.ErrNotFound{}))
  1032  	assert.True(t, dosaRenamed.ErrorIsAlreadyExists(errors.Wrap(&dosaRenamed.ErrAlreadyExists{}, "wrapped")))
  1033  	assert.Equal(t, "already exists", (&dosaRenamed.ErrAlreadyExists{}).Error())
  1034  }