vitess.io/vitess@v0.16.2/go/vt/topo/topotests/srv_keyspace_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package topotests
    18  
    19  import (
    20  	"context"
    21  	"reflect"
    22  	"sort"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/require"
    28  	"google.golang.org/protobuf/proto"
    29  
    30  	"vitess.io/vitess/go/json2"
    31  	"vitess.io/vitess/go/vt/key"
    32  	"vitess.io/vitess/go/vt/topo"
    33  	"vitess.io/vitess/go/vt/topo/memorytopo"
    34  
    35  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    36  )
    37  
    38  // waitForInitialSrvKeyspace waits for the initial SrvKeyspace to
    39  // appear, and match the provided srvKeyspace.
    40  func waitForInitialSrvKeyspace(t *testing.T, ts *topo.Server, cell, keyspace string) (current *topo.WatchSrvKeyspaceData, changes <-chan *topo.WatchSrvKeyspaceData, cancel context.CancelFunc) {
    41  	ctx, cancel := context.WithCancel(context.Background())
    42  	start := time.Now()
    43  	var err error
    44  	for {
    45  		current, changes, err = ts.WatchSrvKeyspace(ctx, cell, keyspace)
    46  		switch {
    47  		case topo.IsErrType(err, topo.NoNode):
    48  			// hasn't appeared yet
    49  			if time.Since(start) > 10*time.Second {
    50  				t.Fatalf("time out waiting for file to appear")
    51  			}
    52  			time.Sleep(10 * time.Millisecond)
    53  			continue
    54  		case err == nil:
    55  			return
    56  		default:
    57  			t.Fatalf("watch failed: %v", err)
    58  		}
    59  	}
    60  }
    61  
    62  func TestWatchSrvKeyspaceNoNode(t *testing.T) {
    63  	cell := "cell1"
    64  	keyspace := "ks1"
    65  	ctx := context.Background()
    66  	ts := memorytopo.NewServer(cell)
    67  
    68  	// No SrvKeyspace -> ErrNoNode
    69  	_, _, err := ts.WatchSrvKeyspace(ctx, cell, keyspace)
    70  	if !topo.IsErrType(err, topo.NoNode) {
    71  		t.Errorf("Got invalid result from WatchSrvKeyspace(not there): %v", err)
    72  	}
    73  }
    74  
    75  func TestWatchSrvKeyspace(t *testing.T) {
    76  
    77  	cell := "cell1"
    78  	keyspace := "ks1"
    79  	ctx := context.Background()
    80  	ts := memorytopo.NewServer(cell)
    81  
    82  	// Create initial value
    83  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, &topodatapb.SrvKeyspace{}); err != nil {
    84  		t.Fatalf("Update(/keyspaces/ks1/SrvKeyspace) failed: %v", err)
    85  	}
    86  
    87  	// Starting the watch should now work, and return an empty
    88  	// SrvKeyspace.
    89  	wanted := &topodatapb.SrvKeyspace{}
    90  	current, changes, cancel := waitForInitialSrvKeyspace(t, ts, cell, keyspace)
    91  	if !proto.Equal(current.Value, wanted) {
    92  		t.Fatalf("got bad data: %v expected: %v", current.Value, wanted)
    93  	}
    94  
    95  	// Update the value with bad data, wait until error.
    96  	conn, err := ts.ConnForCell(ctx, cell)
    97  	if err != nil {
    98  		t.Fatalf("ConnForCell failed: %v", err)
    99  	}
   100  	if _, err := conn.Update(ctx, "/keyspaces/"+keyspace+"/SrvKeyspace", []byte("BAD PROTO DATA"), nil); err != nil {
   101  		t.Fatalf("Update(/keyspaces/ks1/SrvKeyspace) failed: %v", err)
   102  	}
   103  	for {
   104  		wd, ok := <-changes
   105  		if !ok {
   106  			t.Fatalf("watch channel unexpectedly closed")
   107  		}
   108  		if wd.Err != nil {
   109  			if strings.Contains(wd.Err.Error(), "error unpacking SrvKeyspace object") {
   110  				break
   111  			}
   112  			t.Fatalf("watch channel unexpectedly got unknown error: %v", wd.Err)
   113  		}
   114  		if !proto.Equal(wd.Value, wanted) {
   115  			t.Fatalf("got bad data: %v expected: %v", wd.Value, wanted)
   116  		}
   117  		t.Log("got duplicate right value, skipping.")
   118  	}
   119  
   120  	// Cancel should still work here, although it does nothing.
   121  	cancel()
   122  
   123  	// Bad data in topo, setting the watch should now fail.
   124  	_, _, err = ts.WatchSrvKeyspace(ctx, cell, keyspace)
   125  	if err == nil || !strings.Contains(err.Error(), "error unpacking initial SrvKeyspace object") {
   126  		t.Fatalf("expected an initial error setting watch on bad content, but got: %v", err)
   127  	}
   128  
   129  	// Update content, wait until Watch works again
   130  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, wanted); err != nil {
   131  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   132  	}
   133  	start := time.Now()
   134  	for {
   135  		current, changes, err = ts.WatchSrvKeyspace(ctx, cell, keyspace)
   136  		if err != nil {
   137  			if strings.Contains(err.Error(), "error unpacking initial SrvKeyspace object") {
   138  				// hasn't changed yet
   139  				if time.Since(start) > 10*time.Second {
   140  					t.Fatalf("time out waiting for file to appear")
   141  				}
   142  				time.Sleep(10 * time.Millisecond)
   143  				continue
   144  			}
   145  			t.Fatalf("got unexpected error while setting watch: %v", err)
   146  		}
   147  		if !proto.Equal(current.Value, wanted) {
   148  			t.Fatalf("got bad data: %v expected: %v", current.Value, wanted)
   149  		}
   150  		break
   151  	}
   152  
   153  	// Delete node, wait for error (skip any duplicate).
   154  	if err := ts.DeleteSrvKeyspace(ctx, cell, keyspace); err != nil {
   155  		t.Fatalf("DeleteSrvKeyspace() failed: %v", err)
   156  	}
   157  	for {
   158  		wd, ok := <-changes
   159  		if !ok {
   160  			t.Fatalf("watch channel unexpectedly closed")
   161  		}
   162  		if topo.IsErrType(wd.Err, topo.NoNode) {
   163  			break
   164  		}
   165  		if wd.Err != nil {
   166  			t.Fatalf("watch channel unexpectedly got unknown error: %v", wd.Err)
   167  		}
   168  		if !proto.Equal(wd.Value, wanted) {
   169  			t.Fatalf("got bad data: %v expected: %v", wd.Value, wanted)
   170  		}
   171  		t.Log("got duplicate right value, skipping.")
   172  	}
   173  }
   174  
   175  func TestWatchSrvKeyspaceCancel(t *testing.T) {
   176  	cell := "cell1"
   177  	keyspace := "ks1"
   178  	ctx := context.Background()
   179  	ts := memorytopo.NewServer(cell)
   180  
   181  	// No SrvKeyspace -> ErrNoNode
   182  	_, _, err := ts.WatchSrvKeyspace(ctx, cell, keyspace)
   183  	if !topo.IsErrType(err, topo.NoNode) {
   184  		t.Errorf("Got invalid result from WatchSrvKeyspace(not there): %v", err)
   185  	}
   186  
   187  	// Create initial value
   188  	wanted := &topodatapb.SrvKeyspace{}
   189  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, wanted); err != nil {
   190  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   191  	}
   192  
   193  	// Starting the watch should now work.
   194  	current, changes, cancel := waitForInitialSrvKeyspace(t, ts, cell, keyspace)
   195  	if !proto.Equal(current.Value, wanted) {
   196  		t.Fatalf("got bad data: %v expected: %v", current.Value, wanted)
   197  	}
   198  
   199  	// Cancel watch, wait for error.
   200  	cancel()
   201  	for {
   202  		wd, ok := <-changes
   203  		if !ok {
   204  			t.Fatalf("watch channel unexpectedly closed")
   205  		}
   206  		if topo.IsErrType(wd.Err, topo.Interrupted) {
   207  			break
   208  		}
   209  		if wd.Err != nil {
   210  			t.Fatalf("watch channel unexpectedly got unknown error: %v", wd.Err)
   211  		}
   212  		if !proto.Equal(wd.Value, wanted) {
   213  			t.Fatalf("got bad data: %v expected: %v", wd.Value, wanted)
   214  		}
   215  		t.Log("got duplicate right value, skipping.")
   216  	}
   217  
   218  	// Cancel should still work here, although it does nothing.
   219  	cancel()
   220  }
   221  
   222  func TestUpdateSrvKeyspacePartitions(t *testing.T) {
   223  	cell := "cell1"
   224  	cell2 := "cell2"
   225  	keyspace := "ks1"
   226  	ctx := context.Background()
   227  	ts := memorytopo.NewServer(cell, cell2)
   228  
   229  	keyRange, err := key.ParseShardingSpec("-")
   230  	if err != nil || len(keyRange) != 1 {
   231  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(keyRange))
   232  	}
   233  	// Create initial value
   234  	initial := &topodatapb.SrvKeyspace{
   235  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   236  			{
   237  				ServedType: topodatapb.TabletType_PRIMARY,
   238  				ShardReferences: []*topodatapb.ShardReference{
   239  					{
   240  						Name:     "-",
   241  						KeyRange: keyRange[0],
   242  					},
   243  				},
   244  			},
   245  		},
   246  	}
   247  
   248  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil {
   249  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   250  	}
   251  
   252  	if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil {
   253  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   254  	}
   255  
   256  	ks := &topodatapb.Keyspace{}
   257  	if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil {
   258  		t.Fatalf("CreateKeyspace() failed: %v", err)
   259  	}
   260  
   261  	leftKeyRange, err := key.ParseShardingSpec("-80")
   262  	if err != nil || len(leftKeyRange) != 1 {
   263  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange))
   264  	}
   265  
   266  	rightKeyRange, err := key.ParseShardingSpec("80-")
   267  	if err != nil || len(leftKeyRange) != 1 {
   268  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange))
   269  	}
   270  
   271  	targetKs := &topodatapb.SrvKeyspace{
   272  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   273  			{
   274  				ServedType: topodatapb.TabletType_PRIMARY,
   275  				ShardReferences: []*topodatapb.ShardReference{
   276  					{
   277  						Name:     "-",
   278  						KeyRange: keyRange[0],
   279  					},
   280  					{
   281  						Name:     "-80",
   282  						KeyRange: leftKeyRange[0],
   283  					},
   284  					{
   285  						Name:     "80-",
   286  						KeyRange: rightKeyRange[0],
   287  					},
   288  				},
   289  			},
   290  		},
   291  	}
   292  
   293  	shards := []*topo.ShardInfo{
   294  		topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil),
   295  		topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil),
   296  	}
   297  
   298  	ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests")
   299  	if err != nil {
   300  		t.Fatalf("LockKeyspace() failed: %v", err)
   301  	}
   302  	defer unlock(&err)
   303  
   304  	if err := ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}); err != nil {
   305  		t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err)
   306  	}
   307  
   308  	srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace)
   309  	if err != nil {
   310  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   311  	}
   312  
   313  	got, err := json2.MarshalPB(srvKeyspace)
   314  	if err != nil {
   315  		t.Fatalf("MarshalPB() failed: %v", err)
   316  	}
   317  
   318  	want, err := json2.MarshalPB(targetKs)
   319  	if err != nil {
   320  		t.Fatalf("MarshalPB() failed: %v", err)
   321  	}
   322  
   323  	if string(got) != string(want) {
   324  		t.Errorf("AddSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want))
   325  	}
   326  
   327  	// removing works
   328  	targetKs = &topodatapb.SrvKeyspace{
   329  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   330  			{
   331  				ServedType: topodatapb.TabletType_PRIMARY,
   332  				ShardReferences: []*topodatapb.ShardReference{
   333  					{
   334  						Name:     "-",
   335  						KeyRange: keyRange[0],
   336  					},
   337  				},
   338  			},
   339  		},
   340  	}
   341  
   342  	if err = ts.DeleteSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}); err != nil {
   343  		t.Fatalf("DeleteSrvKeyspacePartitions() failed: %v", err)
   344  	}
   345  
   346  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace)
   347  	if err != nil {
   348  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   349  	}
   350  
   351  	got, err = json2.MarshalPB(srvKeyspace)
   352  	if err != nil {
   353  		t.Fatalf("MarshalPB() failed: %v", err)
   354  	}
   355  
   356  	want, err = json2.MarshalPB(targetKs)
   357  	if err != nil {
   358  		t.Fatalf("MarshalPB() failed: %v", err)
   359  	}
   360  
   361  	if string(got) != string(want) {
   362  		t.Errorf("DeleteSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want))
   363  	}
   364  
   365  	// You can add to partitions that do not exist
   366  	targetKs = &topodatapb.SrvKeyspace{
   367  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   368  			{
   369  				ServedType: topodatapb.TabletType_PRIMARY,
   370  				ShardReferences: []*topodatapb.ShardReference{
   371  					{
   372  						Name:     "-",
   373  						KeyRange: keyRange[0],
   374  					},
   375  				},
   376  			},
   377  			{
   378  				ServedType: topodatapb.TabletType_REPLICA,
   379  				ShardReferences: []*topodatapb.ShardReference{
   380  					{
   381  						Name:     "-80",
   382  						KeyRange: leftKeyRange[0],
   383  					},
   384  					{
   385  						Name:     "80-",
   386  						KeyRange: rightKeyRange[0],
   387  					},
   388  				},
   389  			},
   390  		},
   391  	}
   392  
   393  	if err = ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, []string{cell}); err != nil {
   394  		t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err)
   395  	}
   396  
   397  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace)
   398  	if err != nil {
   399  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   400  	}
   401  
   402  	got, err = json2.MarshalPB(srvKeyspace)
   403  	if err != nil {
   404  		t.Fatalf("MarshalPB() failed: %v", err)
   405  	}
   406  
   407  	want, err = json2.MarshalPB(targetKs)
   408  	if err != nil {
   409  		t.Fatalf("MarshalPB() failed: %v", err)
   410  	}
   411  
   412  	if string(got) != string(want) {
   413  		t.Errorf("SrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want))
   414  	}
   415  
   416  	// it works in multiple cells
   417  
   418  	if err = ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, nil); err != nil {
   419  		t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err)
   420  	}
   421  
   422  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace)
   423  	if err != nil {
   424  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   425  	}
   426  
   427  	got, err = json2.MarshalPB(srvKeyspace)
   428  	if err != nil {
   429  		t.Fatalf("MarshalPB() failed: %v", err)
   430  	}
   431  
   432  	want, err = json2.MarshalPB(targetKs)
   433  	if err != nil {
   434  		t.Fatalf("MarshalPB() failed: %v", err)
   435  	}
   436  
   437  	if string(got) != string(want) {
   438  		t.Errorf("AddSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want))
   439  	}
   440  
   441  	// Now let's get the srvKeyspace in cell2. Partition should have been added there too.
   442  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace)
   443  	if err != nil {
   444  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   445  	}
   446  
   447  	got, err = json2.MarshalPB(srvKeyspace)
   448  	if err != nil {
   449  		t.Fatalf("MarshalPB() failed: %v", err)
   450  	}
   451  
   452  	want, err = json2.MarshalPB(targetKs)
   453  	if err != nil {
   454  		t.Fatalf("MarshalPB() failed: %v", err)
   455  	}
   456  
   457  	if string(got) != string(want) {
   458  		t.Errorf("GetSrvKeyspace() failure. Got %v, want: %v", string(got), string(want))
   459  	}
   460  
   461  }
   462  
   463  func TestUpdateUpdateDisableQueryService(t *testing.T) {
   464  	cell := "cell1"
   465  	cell2 := "cell2"
   466  	keyspace := "ks1"
   467  	ctx := context.Background()
   468  	ts := memorytopo.NewServer(cell, cell2)
   469  
   470  	leftKeyRange, err := key.ParseShardingSpec("-80")
   471  	if err != nil || len(leftKeyRange) != 1 {
   472  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange))
   473  	}
   474  
   475  	rightKeyRange, err := key.ParseShardingSpec("80-")
   476  	if err != nil || len(rightKeyRange) != 1 {
   477  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange))
   478  	}
   479  	// Create initial value
   480  	initial := &topodatapb.SrvKeyspace{
   481  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   482  			{
   483  				ServedType: topodatapb.TabletType_PRIMARY,
   484  				ShardReferences: []*topodatapb.ShardReference{
   485  					{
   486  						Name:     "-80",
   487  						KeyRange: leftKeyRange[0],
   488  					},
   489  					{
   490  						Name:     "80-",
   491  						KeyRange: rightKeyRange[0],
   492  					},
   493  				},
   494  			},
   495  		},
   496  	}
   497  
   498  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil {
   499  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   500  	}
   501  
   502  	if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil {
   503  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   504  	}
   505  
   506  	ks := &topodatapb.Keyspace{}
   507  	if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil {
   508  		t.Fatalf("CreateKeyspace() failed: %v", err)
   509  	}
   510  
   511  	targetKs := &topodatapb.SrvKeyspace{
   512  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   513  			{
   514  				ServedType: topodatapb.TabletType_PRIMARY,
   515  				ShardReferences: []*topodatapb.ShardReference{
   516  					{
   517  						Name:     "-80",
   518  						KeyRange: leftKeyRange[0],
   519  					},
   520  					{
   521  						Name:     "80-",
   522  						KeyRange: rightKeyRange[0],
   523  					},
   524  				},
   525  				ShardTabletControls: []*topodatapb.ShardTabletControl{
   526  					{
   527  						Name:                 "-80",
   528  						KeyRange:             leftKeyRange[0],
   529  						QueryServiceDisabled: true,
   530  					},
   531  					{
   532  						Name:                 "80-",
   533  						KeyRange:             rightKeyRange[0],
   534  						QueryServiceDisabled: true,
   535  					},
   536  				},
   537  			},
   538  		},
   539  	}
   540  
   541  	shards := []*topo.ShardInfo{
   542  		topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil),
   543  		topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil),
   544  	}
   545  
   546  	ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests")
   547  	if err != nil {
   548  		t.Fatalf("LockKeyspace() failed: %v", err)
   549  	}
   550  	defer unlock(&err)
   551  
   552  	if err := ts.UpdateDisableQueryService(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}, true /* disableQueryService */); err != nil {
   553  		t.Fatalf("UpdateDisableQueryService() failed: %v", err)
   554  	}
   555  
   556  	srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace)
   557  	if err != nil {
   558  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   559  	}
   560  
   561  	got, err := json2.MarshalPB(srvKeyspace)
   562  	if err != nil {
   563  		t.Fatalf("MarshalPB() failed: %v", err)
   564  	}
   565  
   566  	want, err := json2.MarshalPB(targetKs)
   567  	if err != nil {
   568  		t.Fatalf("MarshalPB() failed: %v", err)
   569  	}
   570  
   571  	if string(got) != string(want) {
   572  		t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want))
   573  	}
   574  
   575  	// cell2 is untouched
   576  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace)
   577  	if err != nil {
   578  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   579  	}
   580  
   581  	got, err = json2.MarshalPB(srvKeyspace)
   582  	if err != nil {
   583  		t.Fatalf("MarshalPB() failed: %v", err)
   584  	}
   585  
   586  	want, err = json2.MarshalPB(initial)
   587  	if err != nil {
   588  		t.Fatalf("MarshalPB() failed: %v", err)
   589  	}
   590  
   591  	if string(got) != string(want) {
   592  		t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want))
   593  	}
   594  
   595  	// You can enable query service
   596  	targetKs = &topodatapb.SrvKeyspace{
   597  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   598  			{
   599  				ServedType: topodatapb.TabletType_PRIMARY,
   600  				ShardReferences: []*topodatapb.ShardReference{
   601  					{
   602  						Name:     "-80",
   603  						KeyRange: leftKeyRange[0],
   604  					},
   605  					{
   606  						Name:     "80-",
   607  						KeyRange: rightKeyRange[0],
   608  					},
   609  				},
   610  				ShardTabletControls: []*topodatapb.ShardTabletControl{
   611  					{
   612  						Name:                 "-80",
   613  						KeyRange:             leftKeyRange[0],
   614  						QueryServiceDisabled: false,
   615  					},
   616  					{
   617  						Name:                 "80-",
   618  						KeyRange:             rightKeyRange[0],
   619  						QueryServiceDisabled: false,
   620  					},
   621  				},
   622  			},
   623  		},
   624  	}
   625  
   626  	shards = []*topo.ShardInfo{
   627  		topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil),
   628  		topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil),
   629  	}
   630  
   631  	if err := ts.UpdateDisableQueryService(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}, false /* disableQueryService */); err != nil {
   632  		t.Fatalf("UpdateDisableQueryService() failed: %v", err)
   633  	}
   634  
   635  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace)
   636  	if err != nil {
   637  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
   638  	}
   639  
   640  	got, err = json2.MarshalPB(srvKeyspace)
   641  	if err != nil {
   642  		t.Fatalf("MarshalPB() failed: %v", err)
   643  	}
   644  
   645  	want, err = json2.MarshalPB(targetKs)
   646  	if err != nil {
   647  		t.Fatalf("MarshalPB() failed: %v", err)
   648  	}
   649  
   650  	if string(got) != string(want) {
   651  		t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want))
   652  	}
   653  }
   654  
   655  func TestGetShardServingTypes(t *testing.T) {
   656  	cell := "cell1"
   657  	cell2 := "cell2"
   658  	keyspace := "ks1"
   659  	ctx := context.Background()
   660  	ts := memorytopo.NewServer(cell, cell2)
   661  
   662  	leftKeyRange, err := key.ParseShardingSpec("-80")
   663  	if err != nil || len(leftKeyRange) != 1 {
   664  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange))
   665  	}
   666  
   667  	rightKeyRange, err := key.ParseShardingSpec("80-")
   668  	if err != nil || len(rightKeyRange) != 1 {
   669  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange))
   670  	}
   671  	// Create initial value
   672  	initial := &topodatapb.SrvKeyspace{
   673  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   674  			{
   675  				ServedType: topodatapb.TabletType_PRIMARY,
   676  				ShardReferences: []*topodatapb.ShardReference{
   677  					{
   678  						Name:     "-80",
   679  						KeyRange: leftKeyRange[0],
   680  					},
   681  					{
   682  						Name:     "80-",
   683  						KeyRange: rightKeyRange[0],
   684  					},
   685  				},
   686  			},
   687  			{
   688  				ServedType: topodatapb.TabletType_REPLICA,
   689  				ShardReferences: []*topodatapb.ShardReference{
   690  					{
   691  						Name:     "80-",
   692  						KeyRange: rightKeyRange[0],
   693  					},
   694  				},
   695  			},
   696  			{
   697  				ServedType: topodatapb.TabletType_RDONLY,
   698  				ShardReferences: []*topodatapb.ShardReference{
   699  					{
   700  						Name:     "-80",
   701  						KeyRange: leftKeyRange[0],
   702  					},
   703  				},
   704  			},
   705  		},
   706  	}
   707  
   708  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil {
   709  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   710  	}
   711  
   712  	if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil {
   713  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   714  	}
   715  
   716  	ks := &topodatapb.Keyspace{}
   717  	if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil {
   718  		t.Fatalf("CreateKeyspace() failed: %v", err)
   719  	}
   720  
   721  	shardInfo := topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil)
   722  
   723  	got, err := ts.GetShardServingTypes(ctx, shardInfo)
   724  	if err != nil {
   725  		t.Fatalf("GetShardServingTypes() failed: %v", err)
   726  	}
   727  
   728  	want := []topodatapb.TabletType{topodatapb.TabletType_PRIMARY, topodatapb.TabletType_RDONLY}
   729  
   730  	if !reflect.DeepEqual(got, want) {
   731  		t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want)
   732  	}
   733  
   734  	shardInfo = topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil)
   735  
   736  	got, err = ts.GetShardServingTypes(ctx, shardInfo)
   737  	if err != nil {
   738  		t.Fatalf("GetShardServingTypes() failed: %v", err)
   739  	}
   740  
   741  	want = []topodatapb.TabletType{topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA}
   742  
   743  	if !reflect.DeepEqual(got, want) {
   744  		t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want)
   745  	}
   746  
   747  	keyRange, _ := key.ParseShardingSpec("-")
   748  
   749  	shardInfo = topo.NewShardInfo(keyspace, "-", &topodatapb.Shard{KeyRange: keyRange[0]}, nil)
   750  
   751  	got, err = ts.GetShardServingTypes(ctx, shardInfo)
   752  	if err != nil {
   753  		t.Fatalf("GetShardServingTypes() failed: %v", err)
   754  	}
   755  
   756  	want = []topodatapb.TabletType{}
   757  
   758  	if !reflect.DeepEqual(got, want) {
   759  		t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want)
   760  	}
   761  }
   762  
   763  func TestGetShardServingCells(t *testing.T) {
   764  	cell := "cell1"
   765  	cell2 := "cell2"
   766  	keyspace := "ks1"
   767  	ctx := context.Background()
   768  	ts := memorytopo.NewServer(cell, cell2)
   769  
   770  	leftKeyRange, err := key.ParseShardingSpec("-80")
   771  	if err != nil || len(leftKeyRange) != 1 {
   772  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange))
   773  	}
   774  
   775  	rightKeyRange, err := key.ParseShardingSpec("80-")
   776  	if err != nil || len(rightKeyRange) != 1 {
   777  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange))
   778  	}
   779  	// Create initial value
   780  	initial := &topodatapb.SrvKeyspace{
   781  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   782  			{
   783  				ServedType: topodatapb.TabletType_PRIMARY,
   784  				ShardReferences: []*topodatapb.ShardReference{
   785  					{
   786  						Name:     "-80",
   787  						KeyRange: leftKeyRange[0],
   788  					},
   789  					{
   790  						Name:     "80-",
   791  						KeyRange: rightKeyRange[0],
   792  					},
   793  				},
   794  			},
   795  			{
   796  				ServedType: topodatapb.TabletType_REPLICA,
   797  				ShardReferences: []*topodatapb.ShardReference{
   798  					{
   799  						Name:     "80-",
   800  						KeyRange: rightKeyRange[0],
   801  					},
   802  				},
   803  			},
   804  			{
   805  				ServedType: topodatapb.TabletType_RDONLY,
   806  				ShardReferences: []*topodatapb.ShardReference{
   807  					{
   808  						Name:     "-80",
   809  						KeyRange: leftKeyRange[0],
   810  					},
   811  				},
   812  			},
   813  		},
   814  	}
   815  
   816  	shardInfo := topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil)
   817  
   818  	got, err := ts.GetShardServingCells(ctx, shardInfo)
   819  	if err != nil {
   820  		t.Fatalf("GetShardServingTypes() failed: %v", err)
   821  	}
   822  
   823  	want := []string{}
   824  
   825  	if !reflect.DeepEqual(got, want) {
   826  		t.Errorf("GetShardServingCells() failure. Got %v, want: %v", got, want)
   827  	}
   828  
   829  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil {
   830  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   831  	}
   832  
   833  	ks := &topodatapb.Keyspace{}
   834  	if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil {
   835  		t.Fatalf("CreateKeyspace() failed: %v", err)
   836  	}
   837  
   838  	got, err = ts.GetShardServingCells(ctx, shardInfo)
   839  	if err != nil {
   840  		t.Fatalf("GetShardServingCells() failed: %v", err)
   841  	}
   842  
   843  	want = []string{cell}
   844  
   845  	if !reflect.DeepEqual(got, want) {
   846  		t.Errorf("GetShardServingCells() failure. Got %v, want: %v", got, want)
   847  	}
   848  
   849  	if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil {
   850  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   851  	}
   852  
   853  	got, err = ts.GetShardServingCells(ctx, shardInfo)
   854  	if err != nil {
   855  		t.Fatalf("GetShardServingCells() failed: %v", err)
   856  	}
   857  
   858  	want = []string{cell, cell2}
   859  
   860  	sort.Strings(got)
   861  
   862  	if !reflect.DeepEqual(got, want) {
   863  		t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want)
   864  	}
   865  }
   866  
   867  func TestMasterMigrateServedType(t *testing.T) {
   868  	cell := "cell1"
   869  	cell2 := "cell2"
   870  	keyspace := "ks1"
   871  	ctx := context.Background()
   872  	ts := memorytopo.NewServer(cell, cell2)
   873  
   874  	initialKeyRange, err := key.ParseShardingSpec("-")
   875  	if err != nil || len(initialKeyRange) != 1 {
   876  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(initialKeyRange))
   877  	}
   878  
   879  	leftKeyRange, err := key.ParseShardingSpec("-80")
   880  	if err != nil || len(leftKeyRange) != 1 {
   881  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange))
   882  	}
   883  
   884  	rightKeyRange, err := key.ParseShardingSpec("80-")
   885  	if err != nil || len(rightKeyRange) != 1 {
   886  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange))
   887  	}
   888  	// Create initial value
   889  	initial := &topodatapb.SrvKeyspace{
   890  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   891  			{
   892  				ServedType: topodatapb.TabletType_PRIMARY,
   893  				ShardReferences: []*topodatapb.ShardReference{
   894  					{
   895  						Name:     "-",
   896  						KeyRange: initialKeyRange[0],
   897  					},
   898  				},
   899  				ShardTabletControls: []*topodatapb.ShardTabletControl{
   900  					{
   901  						Name:                 "-",
   902  						KeyRange:             initialKeyRange[0],
   903  						QueryServiceDisabled: true,
   904  					},
   905  				},
   906  			},
   907  			{
   908  				ServedType: topodatapb.TabletType_REPLICA,
   909  				ShardReferences: []*topodatapb.ShardReference{
   910  					{
   911  						Name:     "-",
   912  						KeyRange: initialKeyRange[0],
   913  					},
   914  				},
   915  				ShardTabletControls: []*topodatapb.ShardTabletControl{
   916  					{
   917  						Name:                 "-",
   918  						KeyRange:             initialKeyRange[0],
   919  						QueryServiceDisabled: true,
   920  					},
   921  				},
   922  			},
   923  			{
   924  				ServedType: topodatapb.TabletType_RDONLY,
   925  				ShardReferences: []*topodatapb.ShardReference{
   926  					{
   927  						Name:     "-",
   928  						KeyRange: initialKeyRange[0],
   929  					},
   930  				},
   931  			},
   932  		},
   933  	}
   934  
   935  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil {
   936  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   937  	}
   938  
   939  	if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil {
   940  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
   941  	}
   942  
   943  	sourceShards := []*topo.ShardInfo{
   944  		topo.NewShardInfo(keyspace, "-", &topodatapb.Shard{KeyRange: initialKeyRange[0]}, nil),
   945  	}
   946  
   947  	destinationShards := []*topo.ShardInfo{
   948  		topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil),
   949  		topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil),
   950  	}
   951  
   952  	ks := &topodatapb.Keyspace{}
   953  	if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil {
   954  		t.Fatalf("CreateKeyspace() failed: %v", err)
   955  	}
   956  
   957  	ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests")
   958  	if err != nil {
   959  		t.Fatalf("LockKeyspace() failed: %v", err)
   960  	}
   961  	defer unlock(&err)
   962  
   963  	// You can migrate a single cell at a time
   964  
   965  	err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_RDONLY, []string{cell})
   966  	if err != nil {
   967  		t.Fatalf("MigrateServedType() failed: %v", err)
   968  	}
   969  
   970  	targetKs := &topodatapb.SrvKeyspace{
   971  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
   972  			{
   973  				ServedType: topodatapb.TabletType_PRIMARY,
   974  				ShardReferences: []*topodatapb.ShardReference{
   975  					{
   976  						Name:     "-",
   977  						KeyRange: initialKeyRange[0],
   978  					},
   979  				},
   980  				ShardTabletControls: []*topodatapb.ShardTabletControl{
   981  					{
   982  						Name:                 "-",
   983  						KeyRange:             initialKeyRange[0],
   984  						QueryServiceDisabled: true,
   985  					},
   986  				},
   987  			},
   988  			{
   989  				ServedType: topodatapb.TabletType_REPLICA,
   990  				ShardReferences: []*topodatapb.ShardReference{
   991  					{
   992  						Name:     "-",
   993  						KeyRange: initialKeyRange[0],
   994  					},
   995  				},
   996  				ShardTabletControls: []*topodatapb.ShardTabletControl{
   997  					{
   998  						Name:                 "-",
   999  						KeyRange:             initialKeyRange[0],
  1000  						QueryServiceDisabled: true,
  1001  					},
  1002  				},
  1003  			},
  1004  			{
  1005  				ServedType: topodatapb.TabletType_RDONLY,
  1006  				ShardReferences: []*topodatapb.ShardReference{
  1007  					{
  1008  						Name:     "-80",
  1009  						KeyRange: leftKeyRange[0],
  1010  					},
  1011  					{
  1012  						Name:     "80-",
  1013  						KeyRange: rightKeyRange[0],
  1014  					},
  1015  				},
  1016  			},
  1017  		},
  1018  	}
  1019  
  1020  	srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace)
  1021  	if err != nil {
  1022  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
  1023  	}
  1024  
  1025  	got, err := json2.MarshalPB(srvKeyspace)
  1026  	if err != nil {
  1027  		t.Fatalf("MarshalPB() failed: %v", err)
  1028  	}
  1029  
  1030  	want, err := json2.MarshalPB(targetKs)
  1031  	if err != nil {
  1032  		t.Fatalf("MarshalPB() failed: %v", err)
  1033  	}
  1034  
  1035  	if string(got) != string(want) {
  1036  		t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want))
  1037  	}
  1038  
  1039  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace)
  1040  	if err != nil {
  1041  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
  1042  	}
  1043  
  1044  	got, err = json2.MarshalPB(srvKeyspace)
  1045  	if err != nil {
  1046  		t.Fatalf("MarshalPB() failed: %v", err)
  1047  	}
  1048  
  1049  	want, err = json2.MarshalPB(initial)
  1050  	if err != nil {
  1051  		t.Fatalf("MarshalPB() failed: %v", err)
  1052  	}
  1053  
  1054  	if string(got) != string(want) {
  1055  		t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want))
  1056  	}
  1057  
  1058  	// migrating all cells
  1059  
  1060  	err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_RDONLY, nil)
  1061  	if err != nil {
  1062  		t.Fatalf("MigrateServedType() failed: %v", err)
  1063  	}
  1064  
  1065  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace)
  1066  	if err != nil {
  1067  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
  1068  	}
  1069  
  1070  	got, err = json2.MarshalPB(srvKeyspace)
  1071  	if err != nil {
  1072  		t.Fatalf("MarshalPB() failed: %v", err)
  1073  	}
  1074  
  1075  	want, err = json2.MarshalPB(targetKs)
  1076  	if err != nil {
  1077  		t.Fatalf("MarshalPB() failed: %v", err)
  1078  	}
  1079  
  1080  	if string(got) != string(want) {
  1081  		t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want))
  1082  	}
  1083  
  1084  	// migrating primary type cleans up shard tablet controls records
  1085  
  1086  	targetKs = &topodatapb.SrvKeyspace{
  1087  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
  1088  			{
  1089  				ServedType: topodatapb.TabletType_PRIMARY,
  1090  				ShardReferences: []*topodatapb.ShardReference{
  1091  					{
  1092  						Name:     "-80",
  1093  						KeyRange: leftKeyRange[0],
  1094  					},
  1095  					{
  1096  						Name:     "80-",
  1097  						KeyRange: rightKeyRange[0],
  1098  					},
  1099  				},
  1100  			},
  1101  			{
  1102  				ServedType: topodatapb.TabletType_REPLICA,
  1103  				ShardReferences: []*topodatapb.ShardReference{
  1104  					{
  1105  						Name:     "-",
  1106  						KeyRange: initialKeyRange[0],
  1107  					},
  1108  				},
  1109  			},
  1110  			{
  1111  				ServedType: topodatapb.TabletType_RDONLY,
  1112  				ShardReferences: []*topodatapb.ShardReference{
  1113  					{
  1114  						Name:     "-80",
  1115  						KeyRange: leftKeyRange[0],
  1116  					},
  1117  					{
  1118  						Name:     "80-",
  1119  						KeyRange: rightKeyRange[0],
  1120  					},
  1121  				},
  1122  			},
  1123  		},
  1124  	}
  1125  
  1126  	err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_PRIMARY, nil)
  1127  	if err != nil {
  1128  		t.Fatalf("MigrateServedType() failed: %v", err)
  1129  	}
  1130  
  1131  	srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace)
  1132  	if err != nil {
  1133  		t.Fatalf("GetSrvKeyspace() failed: %v", err)
  1134  	}
  1135  
  1136  	got, err = json2.MarshalPB(srvKeyspace)
  1137  	if err != nil {
  1138  		t.Fatalf("MarshalPB() failed: %v", err)
  1139  	}
  1140  
  1141  	want, err = json2.MarshalPB(targetKs)
  1142  	if err != nil {
  1143  		t.Fatalf("MarshalPB() failed: %v", err)
  1144  	}
  1145  
  1146  	if string(got) != string(want) {
  1147  		t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want))
  1148  	}
  1149  }
  1150  
  1151  func TestValidateSrvKeyspace(t *testing.T) {
  1152  	cell := "cell1"
  1153  	cell2 := "cell2"
  1154  	keyspace := "ks1"
  1155  	ctx := context.Background()
  1156  	ts := memorytopo.NewServer(cell, cell2)
  1157  
  1158  	leftKeyRange, err := key.ParseShardingSpec("-80")
  1159  	if err != nil || len(leftKeyRange) != 1 {
  1160  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange))
  1161  	}
  1162  
  1163  	rightKeyRange, err := key.ParseShardingSpec("80-")
  1164  	if err != nil || len(rightKeyRange) != 1 {
  1165  		t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange))
  1166  	}
  1167  
  1168  	correct := &topodatapb.SrvKeyspace{
  1169  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
  1170  			{
  1171  				ServedType: topodatapb.TabletType_PRIMARY,
  1172  				ShardReferences: []*topodatapb.ShardReference{
  1173  					{
  1174  						Name:     "-80",
  1175  						KeyRange: leftKeyRange[0],
  1176  					},
  1177  					{
  1178  						Name:     "80-",
  1179  						KeyRange: rightKeyRange[0],
  1180  					},
  1181  				},
  1182  			},
  1183  		},
  1184  	}
  1185  
  1186  	incorrect := &topodatapb.SrvKeyspace{
  1187  		Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
  1188  			{
  1189  				ServedType: topodatapb.TabletType_PRIMARY,
  1190  				ShardReferences: []*topodatapb.ShardReference{
  1191  					{
  1192  						Name:     "80-",
  1193  						KeyRange: rightKeyRange[0],
  1194  					},
  1195  				},
  1196  			},
  1197  		},
  1198  	}
  1199  
  1200  	if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, correct); err != nil {
  1201  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
  1202  	}
  1203  
  1204  	if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, incorrect); err != nil {
  1205  		t.Fatalf("UpdateSrvKeyspace() failed: %v", err)
  1206  	}
  1207  	errMsg := "keyspace partition for PRIMARY in cell cell2 does not start with min key"
  1208  	err = ts.ValidateSrvKeyspace(ctx, keyspace, "cell1,cell2")
  1209  	require.EqualError(t, err, errMsg)
  1210  
  1211  	err = ts.ValidateSrvKeyspace(ctx, keyspace, "cell1")
  1212  	require.NoError(t, err)
  1213  	err = ts.ValidateSrvKeyspace(ctx, keyspace, "cell2")
  1214  	require.EqualError(t, err, errMsg)
  1215  	err = ts.ValidateSrvKeyspace(ctx, keyspace, "")
  1216  	require.EqualError(t, err, errMsg)
  1217  }