github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sqlmigrations/migrations_test.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sqlmigrations 12 13 import ( 14 "bytes" 15 "context" 16 "fmt" 17 "strings" 18 "testing" 19 "time" 20 21 "github.com/cockroachdb/cockroach/pkg/base" 22 "github.com/cockroachdb/cockroach/pkg/gossip" 23 "github.com/cockroachdb/cockroach/pkg/keys" 24 "github.com/cockroachdb/cockroach/pkg/kv" 25 "github.com/cockroachdb/cockroach/pkg/roachpb" 26 "github.com/cockroachdb/cockroach/pkg/sql" 27 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 28 "github.com/cockroachdb/cockroach/pkg/sqlmigrations/leasemanager" 29 "github.com/cockroachdb/cockroach/pkg/testutils" 30 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 31 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 32 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 33 "github.com/cockroachdb/cockroach/pkg/util/log" 34 "github.com/cockroachdb/cockroach/pkg/util/stop" 35 "github.com/cockroachdb/errors" 36 "github.com/gogo/protobuf/proto" 37 "github.com/stretchr/testify/require" 38 ) 39 40 var ( 41 noopMigration1 = migrationDescriptor{ 42 name: "noop 1", 43 workFn: func(_ context.Context, _ runner) error { return nil }, 44 } 45 noopMigration2 = migrationDescriptor{ 46 name: "noop 2", 47 workFn: func(_ context.Context, _ runner) error { return nil }, 48 } 49 errorMigration = migrationDescriptor{ 50 name: "error", 51 workFn: func(_ context.Context, _ runner) error { return errors.New("errorMigration") }, 52 } 53 panicMigration = migrationDescriptor{ 54 name: "panic", 55 workFn: func(_ context.Context, _ runner) error { panic("panicMigration") }, 56 } 57 ) 58 59 type fakeLeaseManager struct { 60 extendErr error 61 releaseErr error 62 leaseTimeRemaining time.Duration 63 } 64 65 func (f *fakeLeaseManager) AcquireLease( 66 ctx context.Context, key roachpb.Key, 67 ) (*leasemanager.Lease, error) { 68 return &leasemanager.Lease{}, nil 69 } 70 71 func (f *fakeLeaseManager) ExtendLease(ctx context.Context, l *leasemanager.Lease) error { 72 return f.extendErr 73 } 74 75 func (f *fakeLeaseManager) ReleaseLease(ctx context.Context, l *leasemanager.Lease) error { 76 return f.releaseErr 77 } 78 79 func (f *fakeLeaseManager) TimeRemaining(l *leasemanager.Lease) time.Duration { 80 // Default to a reasonable amount of time left if the field wasn't set. 81 if f.leaseTimeRemaining == 0 { 82 return leaseRefreshInterval * 2 83 } 84 return f.leaseTimeRemaining 85 } 86 87 type fakeDB struct { 88 codec keys.SQLCodec 89 kvs map[string][]byte 90 scanErr error 91 putErr error 92 } 93 94 func (f *fakeDB) Scan( 95 ctx context.Context, begin, end interface{}, maxRows int64, 96 ) ([]kv.KeyValue, error) { 97 if f.scanErr != nil { 98 return nil, f.scanErr 99 } 100 min := f.codec.MigrationKeyPrefix() 101 max := min.PrefixEnd() 102 if !bytes.Equal(begin.(roachpb.Key), min) { 103 return nil, errors.Errorf("expected begin key %q, got %q", min, begin) 104 } 105 if !bytes.Equal(end.(roachpb.Key), max) { 106 return nil, errors.Errorf("expected end key %q, got %q", max, end) 107 } 108 var results []kv.KeyValue 109 for k, v := range f.kvs { 110 results = append(results, kv.KeyValue{ 111 Key: []byte(k), 112 Value: &roachpb.Value{RawBytes: v}, 113 }) 114 } 115 return results, nil 116 } 117 118 func (f *fakeDB) Get(ctx context.Context, key interface{}) (kv.KeyValue, error) { 119 return kv.KeyValue{}, errors.New("unimplemented") 120 } 121 122 func (f *fakeDB) Put(ctx context.Context, key, value interface{}) error { 123 if f.putErr != nil { 124 return f.putErr 125 } 126 if f.kvs != nil { 127 f.kvs[string(key.(roachpb.Key))] = []byte(value.(string)) 128 } 129 return nil 130 } 131 132 func (f *fakeDB) Txn(context.Context, func(context.Context, *kv.Txn) error) error { 133 return errors.New("unimplemented") 134 } 135 136 func TestEnsureMigrations(t *testing.T) { 137 defer leaktest.AfterTest(t)() 138 codec := keys.SystemSQLCodec 139 db := &fakeDB{codec: codec} 140 mgr := Manager{ 141 stopper: stop.NewStopper(), 142 leaseManager: &fakeLeaseManager{}, 143 db: db, 144 codec: codec, 145 } 146 defer mgr.stopper.Stop(context.Background()) 147 148 fnGotCalled := false 149 fnGotCalledDescriptor := migrationDescriptor{ 150 name: "got-called-verifier", 151 workFn: func(context.Context, runner) error { 152 fnGotCalled = true 153 return nil 154 }, 155 } 156 testCases := []struct { 157 preCompleted []migrationDescriptor 158 migrations []migrationDescriptor 159 expectedErr string 160 }{ 161 { 162 nil, 163 nil, 164 "", 165 }, 166 { 167 nil, 168 []migrationDescriptor{noopMigration1}, 169 "", 170 }, 171 { 172 []migrationDescriptor{noopMigration1}, 173 []migrationDescriptor{noopMigration1}, 174 "", 175 }, 176 { 177 []migrationDescriptor{}, 178 []migrationDescriptor{noopMigration1, noopMigration2}, 179 "", 180 }, 181 { 182 []migrationDescriptor{noopMigration1}, 183 []migrationDescriptor{noopMigration1, noopMigration2}, 184 "", 185 }, 186 { 187 []migrationDescriptor{noopMigration1, noopMigration2, panicMigration}, 188 []migrationDescriptor{noopMigration1, noopMigration2, panicMigration}, 189 "", 190 }, 191 { 192 []migrationDescriptor{noopMigration1, noopMigration2}, 193 []migrationDescriptor{noopMigration1, noopMigration2, fnGotCalledDescriptor}, 194 "", 195 }, 196 { 197 []migrationDescriptor{noopMigration1, noopMigration2}, 198 []migrationDescriptor{noopMigration1, noopMigration2, errorMigration}, 199 fmt.Sprintf("failed to run migration %q", errorMigration.name), 200 }, 201 } 202 203 defer func(prev []migrationDescriptor) { backwardCompatibleMigrations = prev }(backwardCompatibleMigrations) 204 205 for _, tc := range testCases { 206 t.Run("", func(t *testing.T) { 207 db.kvs = make(map[string][]byte) 208 for _, name := range tc.preCompleted { 209 db.kvs[string(migrationKey(codec, name))] = []byte{} 210 } 211 backwardCompatibleMigrations = tc.migrations 212 213 err := mgr.EnsureMigrations(context.Background(), roachpb.Version{} /* bootstrapVersion */) 214 if !testutils.IsError(err, tc.expectedErr) { 215 t.Errorf("expected error %q, got error %v", tc.expectedErr, err) 216 } 217 if err != nil { 218 return 219 } 220 221 for _, migration := range tc.migrations { 222 if _, ok := db.kvs[string(migrationKey(codec, migration))]; !ok { 223 t.Errorf("expected key %s to be written, but it wasn't", migrationKey(codec, migration)) 224 } 225 } 226 if len(db.kvs) != len(tc.migrations) { 227 t.Errorf("expected %d key to be written, but %d were", 228 len(tc.migrations), len(db.kvs)) 229 } 230 }) 231 } 232 if !fnGotCalled { 233 t.Errorf("expected fnGotCalledDescriptor to be run by the migration coordinator, but it wasn't") 234 } 235 } 236 237 func TestSkipMigrationsIncludedInBootstrap(t *testing.T) { 238 defer leaktest.AfterTest(t)() 239 ctx := context.Background() 240 codec := keys.SystemSQLCodec 241 db := &fakeDB{codec: codec} 242 mgr := Manager{ 243 stopper: stop.NewStopper(), 244 leaseManager: &fakeLeaseManager{}, 245 db: db, 246 codec: codec, 247 } 248 defer mgr.stopper.Stop(ctx) 249 defer func(prev []migrationDescriptor) { 250 backwardCompatibleMigrations = prev 251 }(backwardCompatibleMigrations) 252 253 v := roachpb.MustParseVersion("19.1") 254 fnGotCalled := false 255 backwardCompatibleMigrations = []migrationDescriptor{{ 256 name: "got-called-verifier", 257 includedInBootstrap: v, 258 workFn: func(context.Context, runner) error { 259 fnGotCalled = true 260 return nil 261 }, 262 }} 263 // If the cluster has been bootstrapped at an old version, the migration should run. 264 require.NoError(t, mgr.EnsureMigrations(ctx, roachpb.Version{} /* bootstrapVersion */)) 265 require.True(t, fnGotCalled) 266 fnGotCalled = false 267 // If the cluster has been bootstrapped at a new version, the migration should 268 // not run. 269 require.NoError(t, mgr.EnsureMigrations(ctx, v /* bootstrapVersion */)) 270 require.False(t, fnGotCalled) 271 } 272 273 func TestClusterWideMigrationOnlyRunBySystemTenant(t *testing.T) { 274 defer leaktest.AfterTest(t)() 275 testutils.RunTrueAndFalse(t, "system tenant", func(t *testing.T, systemTenant bool) { 276 var codec keys.SQLCodec 277 if systemTenant { 278 codec = keys.SystemSQLCodec 279 } else { 280 codec = keys.MakeSQLCodec(roachpb.MakeTenantID(5)) 281 } 282 283 ctx := context.Background() 284 db := &fakeDB{codec: codec} 285 mgr := Manager{ 286 stopper: stop.NewStopper(), 287 leaseManager: &fakeLeaseManager{}, 288 db: db, 289 codec: codec, 290 } 291 defer mgr.stopper.Stop(ctx) 292 defer func(prev []migrationDescriptor) { 293 backwardCompatibleMigrations = prev 294 }(backwardCompatibleMigrations) 295 296 fnGotCalled := false 297 backwardCompatibleMigrations = []migrationDescriptor{{ 298 name: "got-called-verifier", 299 clusterWide: true, 300 workFn: func(context.Context, runner) error { 301 fnGotCalled = true 302 return nil 303 }, 304 }} 305 // The migration should only be run by the system tenant. 306 require.NoError(t, mgr.EnsureMigrations(ctx, roachpb.Version{} /* bootstrapVersion */)) 307 require.Equal(t, systemTenant, fnGotCalled) 308 }) 309 } 310 311 func TestDBErrors(t *testing.T) { 312 defer leaktest.AfterTest(t)() 313 codec := keys.SystemSQLCodec 314 db := &fakeDB{codec: codec} 315 mgr := Manager{ 316 stopper: stop.NewStopper(), 317 leaseManager: &fakeLeaseManager{}, 318 db: db, 319 codec: codec, 320 } 321 defer mgr.stopper.Stop(context.Background()) 322 323 migration := noopMigration1 324 defer func(prev []migrationDescriptor) { backwardCompatibleMigrations = prev }(backwardCompatibleMigrations) 325 backwardCompatibleMigrations = []migrationDescriptor{migration} 326 testCases := []struct { 327 scanErr error 328 putErr error 329 expectedErr string 330 }{ 331 { 332 nil, 333 nil, 334 "", 335 }, 336 { 337 fmt.Errorf("context deadline exceeded"), 338 nil, 339 "failed to get list of completed migrations.*context deadline exceeded", 340 }, 341 { 342 nil, 343 fmt.Errorf("context deadline exceeded"), 344 "failed to persist record of completing migration.*context deadline exceeded", 345 }, 346 } 347 for _, tc := range testCases { 348 t.Run("", func(t *testing.T) { 349 db.scanErr = tc.scanErr 350 db.putErr = tc.putErr 351 db.kvs = make(map[string][]byte) 352 err := mgr.EnsureMigrations(context.Background(), roachpb.Version{} /* bootstrapVersion */) 353 if !testutils.IsError(err, tc.expectedErr) { 354 t.Errorf("expected error %q, got error %v", tc.expectedErr, err) 355 } 356 if err != nil { 357 return 358 } 359 if _, ok := db.kvs[string(migrationKey(codec, migration))]; !ok { 360 t.Errorf("expected key %s to be written, but it wasn't", migrationKey(codec, migration)) 361 } 362 if len(db.kvs) != len(backwardCompatibleMigrations) { 363 t.Errorf("expected %d key to be written, but %d were", 364 len(backwardCompatibleMigrations), len(db.kvs)) 365 } 366 }) 367 } 368 } 369 370 // ExtendLease and ReleaseLease errors should not, by themselves, cause the 371 // migration process to fail. Not being able to acquire the lease should, but 372 // we don't test that here due to the added code that would be needed to change 373 // its retry settings to allow for testing it in a reasonable amount of time. 374 func TestLeaseErrors(t *testing.T) { 375 defer leaktest.AfterTest(t)() 376 codec := keys.SystemSQLCodec 377 db := &fakeDB{codec: codec, kvs: make(map[string][]byte)} 378 mgr := Manager{ 379 stopper: stop.NewStopper(), 380 leaseManager: &fakeLeaseManager{ 381 extendErr: fmt.Errorf("context deadline exceeded"), 382 releaseErr: fmt.Errorf("context deadline exceeded"), 383 }, 384 db: db, 385 codec: codec, 386 } 387 defer mgr.stopper.Stop(context.Background()) 388 389 migration := noopMigration1 390 defer func(prev []migrationDescriptor) { backwardCompatibleMigrations = prev }(backwardCompatibleMigrations) 391 backwardCompatibleMigrations = []migrationDescriptor{migration} 392 if err := mgr.EnsureMigrations(context.Background(), roachpb.Version{} /* bootstrapVersion */); err != nil { 393 t.Error(err) 394 } 395 if _, ok := db.kvs[string(migrationKey(codec, migration))]; !ok { 396 t.Errorf("expected key %s to be written, but it wasn't", migrationKey(codec, migration)) 397 } 398 if len(db.kvs) != len(backwardCompatibleMigrations) { 399 t.Errorf("expected %d key to be written, but %d were", 400 len(backwardCompatibleMigrations), len(db.kvs)) 401 } 402 } 403 404 // The lease not having enough time left on it to finish migrations should 405 // cause the process to exit via a call to log.Fatal. 406 func TestLeaseExpiration(t *testing.T) { 407 defer leaktest.AfterTest(t)() 408 codec := keys.SystemSQLCodec 409 db := &fakeDB{codec: codec, kvs: make(map[string][]byte)} 410 mgr := Manager{ 411 stopper: stop.NewStopper(), 412 leaseManager: &fakeLeaseManager{leaseTimeRemaining: time.Nanosecond}, 413 db: db, 414 codec: codec, 415 } 416 defer mgr.stopper.Stop(context.Background()) 417 418 oldLeaseRefreshInterval := leaseRefreshInterval 419 leaseRefreshInterval = time.Microsecond 420 defer func() { leaseRefreshInterval = oldLeaseRefreshInterval }() 421 422 exitCalled := make(chan bool) 423 log.SetExitFunc(true /* hideStack */, func(int) { exitCalled <- true }) 424 defer log.ResetExitFunc() 425 // Disable stack traces to make the test output in teamcity less deceiving. 426 defer log.DisableTracebacks()() 427 428 waitForExitMigration := migrationDescriptor{ 429 name: "wait for exit to be called", 430 workFn: func(context.Context, runner) error { 431 select { 432 case <-exitCalled: 433 return nil 434 case <-time.After(10 * time.Second): 435 return fmt.Errorf("timed out waiting for exit to be called") 436 } 437 }, 438 } 439 defer func(prev []migrationDescriptor) { backwardCompatibleMigrations = prev }(backwardCompatibleMigrations) 440 backwardCompatibleMigrations = []migrationDescriptor{waitForExitMigration} 441 if err := mgr.EnsureMigrations(context.Background(), roachpb.Version{} /* bootstrapVersion */); err != nil { 442 t.Error(err) 443 } 444 } 445 446 // migrationTest assists in testing the effects of a migration. It provides 447 // methods to edit the list of migrations run at server startup, start a test 448 // server, and run an individual migration. The test server's KV and SQL 449 // interfaces are intended to be accessed directly to verify the effect of the 450 // migration. Any mutations to the list of migrations run at server startup are 451 // reverted at the end of the test. 452 type migrationTest struct { 453 oldMigrations []migrationDescriptor 454 server serverutils.TestServerInterface 455 sqlDB *sqlutils.SQLRunner 456 kvDB *kv.DB 457 memMetrics *sql.MemoryMetrics 458 } 459 460 // makeMigrationTest creates a new migrationTest. 461 // 462 // The caller is responsible for calling the test's close method at the end of 463 // the test. 464 func makeMigrationTest(ctx context.Context, t testing.TB) migrationTest { 465 t.Helper() 466 467 oldMigrations := append([]migrationDescriptor(nil), backwardCompatibleMigrations...) 468 memMetrics := sql.MakeMemMetrics("migration-test-internal", time.Minute) 469 return migrationTest{ 470 oldMigrations: oldMigrations, 471 memMetrics: &memMetrics, 472 } 473 } 474 475 // pop removes the migration whose name starts with namePrefix from the list of 476 // migrations run at server startup. It fails the test if the number of 477 // migrations that match namePrefix is not exactly one. 478 // 479 // You must not call pop after calling start. 480 func (mt *migrationTest) pop(t testing.TB, namePrefix string) migrationDescriptor { 481 t.Helper() 482 483 if mt.server != nil { 484 t.Fatal("migrationTest.pop must be called before mt.start") 485 } 486 487 var migration migrationDescriptor 488 var newMigrations []migrationDescriptor 489 for _, m := range backwardCompatibleMigrations { 490 if strings.HasPrefix(m.name, namePrefix) { 491 migration = m 492 continue 493 } 494 newMigrations = append(newMigrations, m) 495 } 496 if n := len(backwardCompatibleMigrations) - len(newMigrations); n != 1 { 497 t.Fatalf("expected prefix %q to match exactly one migration, but matched %d", namePrefix, n) 498 } 499 backwardCompatibleMigrations = newMigrations 500 return migration 501 } 502 503 // start starts a test server with the given serverArgs. 504 func (mt *migrationTest) start(t testing.TB, serverArgs base.TestServerArgs) { 505 server, sqlDB, kvDB := serverutils.StartServer(t, serverArgs) 506 mt.server = server 507 mt.sqlDB = sqlutils.MakeSQLRunner(sqlDB) 508 mt.kvDB = kvDB 509 } 510 511 // runMigration triggers a manual run of migration. It does not mark migration 512 // as completed, so subsequent calls will cause migration to be re-executed. 513 // This is useful for verifying idempotency. 514 // 515 // You must call start before calling runMigration. 516 func (mt *migrationTest) runMigration(ctx context.Context, m migrationDescriptor) error { 517 if m.workFn == nil { 518 // Migration has been baked in. Ignore it. 519 return nil 520 } 521 return m.workFn(ctx, runner{ 522 settings: mt.server.ClusterSettings(), 523 codec: keys.SystemSQLCodec, 524 db: mt.kvDB, 525 sqlExecutor: mt.server.InternalExecutor().(*sql.InternalExecutor), 526 }) 527 } 528 529 // close stops the test server and restores package-global state. 530 func (mt *migrationTest) close(ctx context.Context) { 531 if mt.server != nil { 532 mt.server.Stopper().Stop(ctx) 533 } 534 backwardCompatibleMigrations = mt.oldMigrations 535 } 536 537 func TestCreateSystemTable(t *testing.T) { 538 defer leaktest.AfterTest(t)() 539 ctx := context.Background() 540 541 table := sqlbase.NamespaceTable 542 table.ID = keys.MaxReservedDescID 543 544 prevPrivileges, ok := sqlbase.SystemAllowedPrivileges[table.ID] 545 defer func() { 546 if ok { 547 // Restore value of privileges. 548 sqlbase.SystemAllowedPrivileges[table.ID] = prevPrivileges 549 } else { 550 delete(sqlbase.SystemAllowedPrivileges, table.ID) 551 } 552 }() 553 sqlbase.SystemAllowedPrivileges[table.ID] = sqlbase.SystemAllowedPrivileges[keys.NamespaceTableID] 554 555 table.Name = "dummy" 556 nameKey := sqlbase.NewPublicTableKey(table.ParentID, table.Name).Key(keys.SystemSQLCodec) 557 descKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, table.ID) 558 descVal := sqlbase.WrapDescriptor(&table) 559 560 mt := makeMigrationTest(ctx, t) 561 defer mt.close(ctx) 562 563 mt.start(t, base.TestServerArgs{}) 564 565 // Verify that the keys were not written. 566 if kv, err := mt.kvDB.Get(ctx, nameKey); err != nil { 567 t.Error(err) 568 } else if kv.Exists() { 569 t.Errorf("expected %q not to exist, got %v", nameKey, kv) 570 } 571 if kv, err := mt.kvDB.Get(ctx, descKey); err != nil { 572 t.Error(err) 573 } else if kv.Exists() { 574 t.Errorf("expected %q not to exist, got %v", descKey, kv) 575 } 576 577 migration := migrationDescriptor{ 578 name: "add system.dummy table", 579 workFn: func(ctx context.Context, r runner) error { 580 return createSystemTable(ctx, r, table) 581 }, 582 } 583 if err := mt.runMigration(ctx, migration); err != nil { 584 t.Fatal(err) 585 } 586 587 // Verify that the appropriate keys were written. 588 if kv, err := mt.kvDB.Get(ctx, nameKey); err != nil { 589 t.Error(err) 590 } else if !kv.Exists() { 591 t.Errorf("expected %q to exist, got that it doesn't exist", nameKey) 592 } 593 var descriptor sqlbase.Descriptor 594 if err := mt.kvDB.GetProto(ctx, descKey, &descriptor); err != nil { 595 t.Error(err) 596 } else if !proto.Equal(descVal, &descriptor) { 597 t.Errorf("expected %v for key %q, got %v", descVal, descKey, descriptor) 598 } 599 600 // Verify the idempotency of the migration. 601 if err := mt.runMigration(ctx, migration); err != nil { 602 t.Fatal(err) 603 } 604 } 605 606 func TestAdminUserExists(t *testing.T) { 607 defer leaktest.AfterTest(t)() 608 ctx := context.Background() 609 610 mt := makeMigrationTest(ctx, t) 611 defer mt.close(ctx) 612 613 migration := mt.pop(t, "add system.users isRole column and create admin role") 614 mt.start(t, base.TestServerArgs{}) 615 616 // Create a user named "admin". We have to do a manual insert as "CREATE USER" 617 // knows about "isRole", but the migration hasn't run yet. 618 mt.sqlDB.Exec(t, `INSERT INTO system.users (username, "hashedPassword") VALUES ($1, '')`, 619 sqlbase.AdminRole) 620 621 // The revised migration in v2.1 upserts the admin user, so this should succeed. 622 if err := mt.runMigration(ctx, migration); err != nil { 623 t.Errorf("expected success, got %q", err) 624 } 625 } 626 627 func TestPublicRoleExists(t *testing.T) { 628 defer leaktest.AfterTest(t)() 629 ctx := context.Background() 630 631 mt := makeMigrationTest(ctx, t) 632 defer mt.close(ctx) 633 634 migration := mt.pop(t, "disallow public user or role name") 635 mt.start(t, base.TestServerArgs{}) 636 637 // Create a user (we check for user or role) named "public". 638 // We have to do a manual insert as "CREATE USER" knows to disallow "public". 639 mt.sqlDB.Exec(t, `INSERT INTO system.users (username, "hashedPassword", "isRole") VALUES ($1, '', false)`, 640 sqlbase.PublicRole) 641 642 e := `found a user named public which is now a reserved name.` 643 // The revised migration in v2.1 upserts the admin user, so this should succeed. 644 if err := mt.runMigration(ctx, migration); !testutils.IsError(err, e) { 645 t.Errorf("expected error %q got %q", e, err) 646 } 647 648 // Now try with a role instead of a user. 649 mt.sqlDB.Exec(t, `DELETE FROM system.users WHERE username = $1`, sqlbase.PublicRole) 650 mt.sqlDB.Exec(t, `INSERT INTO system.users (username, "hashedPassword", "isRole") VALUES ($1, '', true)`, 651 sqlbase.PublicRole) 652 653 e = `found a role named public which is now a reserved name.` 654 // The revised migration in v2.1 upserts the admin user, so this should succeed. 655 if err := mt.runMigration(ctx, migration); !testutils.IsError(err, e) { 656 t.Errorf("expected error %q got %q", e, err) 657 } 658 659 // Drop it and try again. 660 mt.sqlDB.Exec(t, `DELETE FROM system.users WHERE username = $1`, sqlbase.PublicRole) 661 if err := mt.runMigration(ctx, migration); err != nil { 662 t.Errorf("expected success, got %q", err) 663 } 664 } 665 666 func TestReplayMigrations(t *testing.T) { 667 defer leaktest.AfterTest(t)() 668 ctx := context.Background() 669 670 mt := makeMigrationTest(ctx, t) 671 defer mt.close(ctx) 672 673 mt.start(t, base.TestServerArgs{}) 674 675 // Test all migrations again. Starting the server did the first round. 676 for _, m := range backwardCompatibleMigrations { 677 if err := mt.runMigration(ctx, m); err != nil { 678 t.Error(err) 679 } 680 } 681 } 682 683 func TestExpectedInitialRangeCount(t *testing.T) { 684 defer leaktest.AfterTest(t)() 685 686 ctx := context.Background() 687 s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 688 defer s.Stopper().Stop(ctx) 689 690 testutils.SucceedsSoon(t, func() error { 691 lastMigration := backwardCompatibleMigrations[len(backwardCompatibleMigrations)-1] 692 if _, err := kvDB.Get(ctx, migrationKey(keys.SystemSQLCodec, lastMigration)); err != nil { 693 return errors.New("last migration has not completed") 694 } 695 696 sysCfg := s.GossipI().(*gossip.Gossip).GetSystemConfig() 697 if sysCfg == nil { 698 return errors.New("gossipped system config not available") 699 } 700 701 rows, err := sqlDB.Query(`SELECT range_id, start_key, end_key FROM crdb_internal.ranges`) 702 if err != nil { 703 return err 704 } 705 defer rows.Close() 706 nranges := 0 707 for rows.Next() { 708 var rangeID int 709 var startKey, endKey []byte 710 if err := rows.Scan(&rangeID, &startKey, &endKey); err != nil { 711 return err 712 } 713 if sysCfg.NeedsSplit(startKey, endKey) { 714 return fmt.Errorf("range %d needs split", rangeID) 715 } 716 nranges++ 717 } 718 if rows.Err() != nil { 719 return err 720 } 721 722 expectedRanges, err := s.ExpectedInitialRangeCount() 723 if err != nil { 724 return err 725 } 726 if expectedRanges != nranges { 727 return fmt.Errorf("expected %d ranges but got %d", expectedRanges, nranges) 728 } 729 730 return nil 731 }) 732 } 733 734 func TestUpdateSystemLocationData(t *testing.T) { 735 defer leaktest.AfterTest(t)() 736 ctx := context.Background() 737 738 mt := makeMigrationTest(ctx, t) 739 defer mt.close(ctx) 740 741 migration := mt.pop(t, "update system.locations with default location data") 742 mt.start(t, base.TestServerArgs{}) 743 744 // Check that we don't have any data in the system.locations table without the migration. 745 var count int 746 mt.sqlDB.QueryRow(t, `SELECT count(*) FROM system.locations`).Scan(&count) 747 if count != 0 { 748 t.Fatalf("Exected to find 0 rows in system.locations. Found %d instead", count) 749 } 750 751 // Run the migration to insert locations. 752 if err := mt.runMigration(ctx, migration); err != nil { 753 t.Errorf("expected success, got %q", err) 754 } 755 756 // Check that we have all of the expected locations. 757 mt.sqlDB.QueryRow(t, `SELECT count(*) FROM system.locations`).Scan(&count) 758 if count != len(roachpb.DefaultLocationInformation) { 759 t.Fatalf("Exected to find 0 rows in system.locations. Found %d instead", count) 760 } 761 } 762 763 func TestMigrateNamespaceTableDescriptors(t *testing.T) { 764 defer leaktest.AfterTest(t)() 765 ctx := context.Background() 766 767 mt := makeMigrationTest(ctx, t) 768 defer mt.close(ctx) 769 770 migration := mt.pop(t, "create new system.namespace table") 771 mt.start(t, base.TestServerArgs{}) 772 773 // Since we're already on 20.1, mimic the beginning state by deleting the 774 // new namespace descriptor. 775 key := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, keys.NamespaceTableID) 776 require.NoError(t, mt.kvDB.Del(ctx, key)) 777 778 deprecatedKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, keys.DeprecatedNamespaceTableID) 779 desc := &sqlbase.Descriptor{} 780 require.NoError(t, mt.kvDB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 781 _, err := txn.GetProtoTs(ctx, deprecatedKey, desc) 782 return err 783 })) 784 785 // Run the migration. 786 require.NoError(t, mt.runMigration(ctx, migration)) 787 788 require.NoError(t, mt.kvDB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 789 // Check that the persisted descriptors now match our in-memory versions, 790 // ignoring create and modification times. 791 { 792 ts, err := txn.GetProtoTs(ctx, key, desc) 793 require.NoError(t, err) 794 table := desc.Table(ts) 795 table.CreateAsOfTime = sqlbase.NamespaceTable.CreateAsOfTime 796 table.ModificationTime = sqlbase.NamespaceTable.ModificationTime 797 require.True(t, table.Equal(sqlbase.NamespaceTable)) 798 } 799 { 800 ts, err := txn.GetProtoTs(ctx, deprecatedKey, desc) 801 require.NoError(t, err) 802 table := desc.Table(ts) 803 table.CreateAsOfTime = sqlbase.DeprecatedNamespaceTable.CreateAsOfTime 804 table.ModificationTime = sqlbase.DeprecatedNamespaceTable.ModificationTime 805 require.True(t, table.Equal(sqlbase.DeprecatedNamespaceTable)) 806 } 807 return nil 808 })) 809 } 810 811 func TestAlterSystemJobsTable(t *testing.T) { 812 defer leaktest.AfterTest(t)() 813 ctx := context.Background() 814 815 // We need to use "old" jobs table descriptor without newly added columns 816 // in order to test migration. 817 // oldJobsTableSchema is system.jobs definition prior to 20.2 818 oldJobsTableSchema := ` 819 CREATE TABLE system.jobs ( 820 id INT8 DEFAULT unique_rowid() PRIMARY KEY, 821 status STRING NOT NULL, 822 created TIMESTAMP NOT NULL DEFAULT now(), 823 payload BYTES NOT NULL, 824 progress BYTES, 825 INDEX (status, created), 826 827 FAMILY (id, status, created, payload), 828 FAMILY progress (progress) 829 ) 830 ` 831 oldJobsTable, err := sql.CreateTestTableDescriptor( 832 context.Background(), 833 keys.SystemDatabaseID, 834 keys.JobsTableID, 835 oldJobsTableSchema, 836 sqlbase.JobsTable.Privileges, 837 ) 838 require.NoError(t, err) 839 840 const primaryFamilyName = "fam_0_id_status_created_payload" 841 oldPrimaryFamilyColumns := []string{"id", "status", "created", "payload"} 842 newPrimaryFamilyColumns := append( 843 oldPrimaryFamilyColumns, "created_by_type", "created_by_id") 844 845 // Sanity check oldJobsTable does not have new columns. 846 require.Equal(t, 5, len(oldJobsTable.Columns)) 847 require.Equal(t, 2, len(oldJobsTable.Families)) 848 require.Equal(t, primaryFamilyName, oldJobsTable.Families[0].Name) 849 require.Equal(t, oldPrimaryFamilyColumns, oldJobsTable.Families[0].ColumnNames) 850 851 jobsTable := sqlbase.JobsTable 852 sqlbase.JobsTable = oldJobsTable 853 defer func() { 854 sqlbase.JobsTable = jobsTable 855 }() 856 857 mt := makeMigrationTest(ctx, t) 858 defer mt.close(ctx) 859 860 migration := mt.pop(t, "add created_by columns to system.jobs") 861 mt.start(t, base.TestServerArgs{}) 862 863 // Run migration and verify we have added columns and renamed column family. 864 require.NoError(t, mt.runMigration(ctx, migration)) 865 866 newJobsTable := sqlbase.GetTableDescriptor( 867 mt.kvDB, keys.SystemSQLCodec, "system", "jobs") 868 require.Equal(t, 7, len(newJobsTable.Columns)) 869 require.Equal(t, "created_by_type", newJobsTable.Columns[5].Name) 870 require.Equal(t, "created_by_id", newJobsTable.Columns[6].Name) 871 require.Equal(t, 2, len(newJobsTable.Families)) 872 // Ensure we keep old family name. 873 require.Equal(t, primaryFamilyName, newJobsTable.Families[0].Name) 874 // Make sure our primary family has new columns added to it. 875 require.Equal(t, newPrimaryFamilyColumns, newJobsTable.Families[0].ColumnNames) 876 877 // Run the migration again -- it should be a no-op. 878 require.NoError(t, mt.runMigration(ctx, migration)) 879 newJobsTableAgain := sqlbase.GetTableDescriptor( 880 mt.kvDB, keys.SystemSQLCodec, "system", "jobs") 881 require.True(t, proto.Equal(newJobsTable, newJobsTableAgain)) 882 }