github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/server/server_test.go (about) 1 // Copyright 2014 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 server 12 13 import ( 14 "bytes" 15 "compress/gzip" 16 "context" 17 "fmt" 18 "io" 19 "io/ioutil" 20 "net/http" 21 "net/url" 22 "os" 23 "path/filepath" 24 "reflect" 25 "strings" 26 "testing" 27 "time" 28 29 "github.com/cockroachdb/cockroach/pkg/base" 30 "github.com/cockroachdb/cockroach/pkg/build" 31 "github.com/cockroachdb/cockroach/pkg/config" 32 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 33 "github.com/cockroachdb/cockroach/pkg/keys" 34 "github.com/cockroachdb/cockroach/pkg/kv" 35 "github.com/cockroachdb/cockroach/pkg/kv/kvserver" 36 "github.com/cockroachdb/cockroach/pkg/roachpb" 37 "github.com/cockroachdb/cockroach/pkg/server/serverpb" 38 "github.com/cockroachdb/cockroach/pkg/server/status/statuspb" 39 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 40 "github.com/cockroachdb/cockroach/pkg/storage" 41 "github.com/cockroachdb/cockroach/pkg/testutils" 42 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 43 "github.com/cockroachdb/cockroach/pkg/ui" 44 "github.com/cockroachdb/cockroach/pkg/util/hlc" 45 "github.com/cockroachdb/cockroach/pkg/util/httputil" 46 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 47 "github.com/cockroachdb/cockroach/pkg/util/log" 48 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 49 "github.com/cockroachdb/cockroach/pkg/util/uuid" 50 "github.com/cockroachdb/errors" 51 "github.com/gogo/protobuf/jsonpb" 52 "github.com/gogo/protobuf/proto" 53 "github.com/stretchr/testify/assert" 54 "github.com/stretchr/testify/require" 55 ) 56 57 // TestSelfBootstrap verifies operation when no bootstrap hosts have 58 // been specified. 59 func TestSelfBootstrap(t *testing.T) { 60 defer leaktest.AfterTest(t)() 61 s, err := serverutils.StartServerRaw(base.TestServerArgs{}) 62 if err != nil { 63 t.Fatal(err) 64 } 65 defer s.Stopper().Stop(context.Background()) 66 67 if s.RPCContext().ClusterID.Get() == uuid.Nil { 68 t.Error("cluster ID failed to be set on the RPC context") 69 } 70 } 71 72 // TestHealthCheck runs a basic sanity check on the health checker. 73 func TestHealthCheck(t *testing.T) { 74 defer leaktest.AfterTest(t)() 75 76 cfg := zonepb.DefaultZoneConfig() 77 cfg.NumReplicas = proto.Int32(1) 78 s, err := serverutils.StartServerRaw(base.TestServerArgs{ 79 Knobs: base.TestingKnobs{ 80 Server: &TestingKnobs{ 81 DefaultZoneConfigOverride: &cfg, 82 }, 83 }, 84 }) 85 86 if err != nil { 87 t.Fatal(err) 88 } 89 defer s.Stopper().Stop(context.Background()) 90 91 ctx := context.Background() 92 93 recorder := s.(*TestServer).Server.recorder 94 95 { 96 summary := *recorder.GenerateNodeStatus(ctx) 97 result := recorder.CheckHealth(ctx, summary) 98 if len(result.Alerts) != 0 { 99 t.Fatal(result) 100 } 101 } 102 103 store, err := s.(*TestServer).Server.node.stores.GetStore(1) 104 if err != nil { 105 t.Fatal(err) 106 } 107 108 store.Metrics().UnavailableRangeCount.Inc(100) 109 110 { 111 summary := *recorder.GenerateNodeStatus(ctx) 112 result := recorder.CheckHealth(ctx, summary) 113 expAlerts := []statuspb.HealthAlert{ 114 {StoreID: 1, Category: statuspb.HealthAlert_METRICS, Description: "ranges.unavailable", Value: 100.0}, 115 } 116 if !reflect.DeepEqual(expAlerts, result.Alerts) { 117 t.Fatalf("expected %+v, got %+v", expAlerts, result.Alerts) 118 } 119 } 120 } 121 122 // TestEngineTelemetry tests that the server increments a telemetry counter on 123 // start that denotes engine type. 124 func TestEngineTelemetry(t *testing.T) { 125 defer leaktest.AfterTest(t)() 126 s, db, _ := serverutils.StartServer(t, base.TestServerArgs{}) 127 defer s.Stopper().Stop(context.Background()) 128 129 rows, err := db.Query("SELECT * FROM crdb_internal.feature_usage WHERE feature_name LIKE 'storage.engine.%' AND usage_count > 0;") 130 defer func() { 131 if err := rows.Close(); err != nil { 132 t.Fatal(err) 133 } 134 }() 135 if err != nil { 136 t.Fatal(err) 137 } 138 count := 0 139 for rows.Next() { 140 count++ 141 } 142 if count < 1 { 143 t.Fatal("expected engine type telemetry counter to be emiitted") 144 } 145 } 146 147 // TestServerStartClock tests that a server's clock is not pushed out of thin 148 // air. This used to happen - the simple act of starting was causing a server's 149 // clock to be pushed because we were introducing bogus future timestamps into 150 // our system. 151 func TestServerStartClock(t *testing.T) { 152 defer leaktest.AfterTest(t)() 153 154 // Set a high max-offset so that, if the server's clock is pushed by 155 // MaxOffset, we don't hide that under the latency of the Start operation 156 // which would allow the physical clock to catch up to the pushed one. 157 params := base.TestServerArgs{ 158 Knobs: base.TestingKnobs{ 159 Store: &kvserver.StoreTestingKnobs{ 160 MaxOffset: time.Second, 161 }, 162 }, 163 } 164 s, _, _ := serverutils.StartServer(t, params) 165 defer s.Stopper().Stop(context.Background()) 166 167 // Run a command so that we are sure to touch the timestamp cache. This is 168 // actually not needed because other commands run during server 169 // initialization, but we cannot guarantee that's going to stay that way. 170 get := &roachpb.GetRequest{ 171 RequestHeader: roachpb.RequestHeader{Key: roachpb.Key("a")}, 172 } 173 if _, err := kv.SendWrapped( 174 context.Background(), s.DB().NonTransactionalSender(), get, 175 ); err != nil { 176 t.Fatal(err) 177 } 178 179 now := s.Clock().Now() 180 physicalNow := s.Clock().PhysicalNow() 181 serverClockWasPushed := now.WallTime > physicalNow 182 if serverClockWasPushed { 183 t.Fatalf("time: server %s vs actual %d", now, physicalNow) 184 } 185 } 186 187 // TestPlainHTTPServer verifies that we can serve plain http and talk to it. 188 // This is controlled by -cert="" 189 func TestPlainHTTPServer(t *testing.T) { 190 defer leaktest.AfterTest(t)() 191 s, _, _ := serverutils.StartServer(t, base.TestServerArgs{ 192 // The default context uses embedded certs. 193 Insecure: true, 194 }) 195 defer s.Stopper().Stop(context.Background()) 196 197 // First, make sure that the TestServer's built-in client interface 198 // still works in insecure mode. 199 var data serverpb.JSONResponse 200 testutils.SucceedsSoon(t, func() error { 201 return getStatusJSONProto(s, "metrics/local", &data) 202 }) 203 204 // Now make a couple of direct requests using both http and https. 205 // They won't succeed because we're not jumping through 206 // authentication hoops, but they verify that the server is using 207 // the correct protocol. 208 url := s.AdminURL() 209 if !strings.HasPrefix(url, "http://") { 210 t.Fatalf("expected insecure admin url to start with http://, but got %s", url) 211 } 212 if resp, err := httputil.Get(context.Background(), url); err != nil { 213 t.Error(err) 214 } else { 215 if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil { 216 t.Error(err) 217 } 218 if err := resp.Body.Close(); err != nil { 219 t.Error(err) 220 } 221 } 222 223 // Attempting to connect to the insecure server with HTTPS doesn't work. 224 secureURL := strings.Replace(url, "http://", "https://", 1) 225 if _, err := httputil.Get(context.Background(), secureURL); !testutils.IsError(err, "http: server gave HTTP response to HTTPS client") { 226 t.Error(err) 227 } 228 } 229 230 func TestSecureHTTPRedirect(t *testing.T) { 231 defer leaktest.AfterTest(t)() 232 s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) 233 defer s.Stopper().Stop(context.Background()) 234 ts := s.(*TestServer) 235 236 httpClient, err := s.GetHTTPClient() 237 if err != nil { 238 t.Fatal(err) 239 } 240 // Avoid automatically following redirects. 241 httpClient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error { 242 return http.ErrUseLastResponse 243 } 244 245 origURL := "http://" + ts.Cfg.HTTPAddr 246 expURL := url.URL{Scheme: "https", Host: ts.Cfg.HTTPAddr, Path: "/"} 247 248 if resp, err := httpClient.Get(origURL); err != nil { 249 t.Fatal(err) 250 } else { 251 resp.Body.Close() 252 if resp.StatusCode != http.StatusTemporaryRedirect { 253 t.Errorf("expected status code %d; got %d", http.StatusTemporaryRedirect, resp.StatusCode) 254 } 255 if redirectURL, err := resp.Location(); err != nil { 256 t.Error(err) 257 } else if a, e := redirectURL.String(), expURL.String(); a != e { 258 t.Errorf("expected location %s; got %s", e, a) 259 } 260 } 261 262 if resp, err := httpClient.Post(origURL, "text/plain; charset=utf-8", nil); err != nil { 263 t.Fatal(err) 264 } else { 265 resp.Body.Close() 266 if resp.StatusCode != http.StatusTemporaryRedirect { 267 t.Errorf("expected status code %d; got %d", http.StatusTemporaryRedirect, resp.StatusCode) 268 } 269 if redirectURL, err := resp.Location(); err != nil { 270 t.Error(err) 271 } else if a, e := redirectURL.String(), expURL.String(); a != e { 272 t.Errorf("expected location %s; got %s", e, a) 273 } 274 } 275 } 276 277 // TestAcceptEncoding hits the server while explicitly disabling 278 // decompression on a custom client's Transport and setting it 279 // conditionally via the request's Accept-Encoding headers. 280 func TestAcceptEncoding(t *testing.T) { 281 defer leaktest.AfterTest(t)() 282 s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) 283 defer s.Stopper().Stop(context.Background()) 284 client, err := s.GetAdminAuthenticatedHTTPClient() 285 if err != nil { 286 t.Fatal(err) 287 } 288 289 testData := []struct { 290 acceptEncoding string 291 newReader func(io.Reader) io.Reader 292 }{ 293 {"", 294 func(b io.Reader) io.Reader { 295 return b 296 }, 297 }, 298 {httputil.GzipEncoding, 299 func(b io.Reader) io.Reader { 300 r, err := gzip.NewReader(b) 301 if err != nil { 302 t.Fatalf("could not create new gzip reader: %s", err) 303 } 304 return r 305 }, 306 }, 307 } 308 for _, d := range testData { 309 req, err := http.NewRequest("GET", s.AdminURL()+statusPrefix+"metrics/local", nil) 310 if err != nil { 311 t.Fatalf("could not create request: %s", err) 312 } 313 if d.acceptEncoding != "" { 314 req.Header.Set(httputil.AcceptEncodingHeader, d.acceptEncoding) 315 } 316 resp, err := client.Do(req) 317 if err != nil { 318 t.Fatalf("could not make request to %s: %s", req.URL, err) 319 } 320 defer resp.Body.Close() 321 if ce := resp.Header.Get(httputil.ContentEncodingHeader); ce != d.acceptEncoding { 322 t.Fatalf("unexpected content encoding: '%s' != '%s'", ce, d.acceptEncoding) 323 } 324 r := d.newReader(resp.Body) 325 var data serverpb.JSONResponse 326 if err := jsonpb.Unmarshal(r, &data); err != nil { 327 t.Error(err) 328 } 329 } 330 } 331 332 // TestMultiRangeScanDeleteRange tests that commands which access multiple 333 // ranges are carried out properly. 334 func TestMultiRangeScanDeleteRange(t *testing.T) { 335 defer leaktest.AfterTest(t)() 336 ctx := context.Background() 337 338 s, _, db := serverutils.StartServer(t, base.TestServerArgs{}) 339 defer s.Stopper().Stop(ctx) 340 ts := s.(*TestServer) 341 tds := db.NonTransactionalSender() 342 343 if err := ts.node.storeCfg.DB.AdminSplit(ctx, "m", "m", hlc.MaxTimestamp /* expirationTime */); err != nil { 344 t.Fatal(err) 345 } 346 writes := []roachpb.Key{roachpb.Key("a"), roachpb.Key("z")} 347 get := &roachpb.GetRequest{ 348 RequestHeader: roachpb.RequestHeader{Key: writes[0]}, 349 } 350 get.EndKey = writes[len(writes)-1] 351 if _, err := kv.SendWrapped(ctx, tds, get); err == nil { 352 t.Errorf("able to call Get with a key range: %v", get) 353 } 354 var delTS hlc.Timestamp 355 for i, k := range writes { 356 put := roachpb.NewPut(k, roachpb.MakeValueFromBytes(k)) 357 if _, err := kv.SendWrapped(ctx, tds, put); err != nil { 358 t.Fatal(err) 359 } 360 scan := roachpb.NewScan(writes[0], writes[len(writes)-1].Next(), false) 361 reply, err := kv.SendWrapped(ctx, tds, scan) 362 if err != nil { 363 t.Fatal(err) 364 } 365 sr := reply.(*roachpb.ScanResponse) 366 if sr.Txn != nil { 367 // This was the other way around at some point in the past. 368 // Same below for Delete, etc. 369 t.Errorf("expected no transaction in response header") 370 } 371 if rows := sr.Rows; len(rows) != i+1 { 372 t.Fatalf("expected %d rows, but got %d", i+1, len(rows)) 373 } 374 } 375 376 del := &roachpb.DeleteRangeRequest{ 377 RequestHeader: roachpb.RequestHeader{ 378 Key: writes[0], 379 EndKey: writes[len(writes)-1].Next(), 380 }, 381 ReturnKeys: true, 382 } 383 reply, err := kv.SendWrappedWith(ctx, tds, roachpb.Header{Timestamp: delTS}, del) 384 if err != nil { 385 t.Fatal(err) 386 } 387 dr := reply.(*roachpb.DeleteRangeResponse) 388 if dr.Txn != nil { 389 t.Errorf("expected no transaction in response header") 390 } 391 if !reflect.DeepEqual(dr.Keys, writes) { 392 t.Errorf("expected %d keys to be deleted, but got %d instead", writes, dr.Keys) 393 } 394 395 now := s.Clock().Now() 396 txnProto := roachpb.MakeTransaction("MyTxn", nil, 0, now, 0) 397 txn := kv.NewTxnFromProto(ctx, db, s.NodeID(), now, kv.RootTxn, &txnProto) 398 399 scan := roachpb.NewScan(writes[0], writes[len(writes)-1].Next(), false) 400 ba := roachpb.BatchRequest{} 401 ba.Header = roachpb.Header{Txn: &txnProto} 402 ba.Add(scan) 403 br, pErr := txn.Send(ctx, ba) 404 if pErr != nil { 405 t.Fatal(err) 406 } 407 replyTxn := br.Txn 408 if replyTxn == nil || replyTxn.Name != "MyTxn" { 409 t.Errorf("wanted Txn to persist, but it changed to %v", txn) 410 } 411 sr := br.Responses[0].GetInner().(*roachpb.ScanResponse) 412 if rows := sr.Rows; len(rows) > 0 { 413 t.Fatalf("scan after delete returned rows: %v", rows) 414 } 415 } 416 417 // TestMultiRangeScanWithPagination tests that specifying MaxSpanResultKeys 418 // and/or TargetBytes to break up result sets works properly, even across 419 // ranges. 420 func TestMultiRangeScanWithPagination(t *testing.T) { 421 defer leaktest.AfterTest(t)() 422 testCases := []struct { 423 splitKeys []roachpb.Key 424 keys []roachpb.Key 425 }{ 426 {[]roachpb.Key{roachpb.Key("m")}, 427 []roachpb.Key{roachpb.Key("a"), roachpb.Key("z")}}, 428 {[]roachpb.Key{roachpb.Key("h"), roachpb.Key("q")}, 429 []roachpb.Key{roachpb.Key("b"), roachpb.Key("f"), roachpb.Key("k"), 430 roachpb.Key("r"), roachpb.Key("w"), roachpb.Key("y")}}, 431 } 432 433 for _, tc := range testCases { 434 t.Run("", func(t *testing.T) { 435 ctx := context.Background() 436 s, _, db := serverutils.StartServer(t, base.TestServerArgs{}) 437 defer s.Stopper().Stop(ctx) 438 ts := s.(*TestServer) 439 tds := db.NonTransactionalSender() 440 441 for _, sk := range tc.splitKeys { 442 if err := ts.node.storeCfg.DB.AdminSplit(ctx, sk, sk, hlc.MaxTimestamp /* expirationTime */); err != nil { 443 t.Fatal(err) 444 } 445 } 446 447 for _, k := range tc.keys { 448 put := roachpb.NewPut(k, roachpb.MakeValueFromBytes(k)) 449 if _, err := kv.SendWrapped(ctx, tds, put); err != nil { 450 t.Fatal(err) 451 } 452 } 453 454 // The maximum TargetBytes to use in this test. We use the bytes in 455 // all kvs in this test case as a ceiling. Nothing interesting 456 // happens above this. 457 var maxTargetBytes int64 458 { 459 scan := roachpb.NewScan(tc.keys[0], tc.keys[len(tc.keys)-1].Next(), false) 460 resp, pErr := kv.SendWrapped(ctx, tds, scan) 461 require.Nil(t, pErr) 462 maxTargetBytes = resp.Header().NumBytes 463 } 464 465 testutils.RunTrueAndFalse(t, "reverse", func(t *testing.T, reverse bool) { 466 // Iterate through MaxSpanRequestKeys=1..n and TargetBytes=1..m 467 // and (where n and m are chosen to reveal the full result set 468 // in one page). At each(*) combination, paginate both the 469 // forward and reverse scan and make sure we get the right 470 // result. 471 // 472 // (*) we don't increase the limits when there's only one page, 473 // but short circuit to something more interesting instead. 474 msrq := int64(1) 475 for targetBytes := int64(1); ; targetBytes++ { 476 var numPages int 477 t.Run(fmt.Sprintf("targetBytes=%d,maxSpanRequestKeys=%d", targetBytes, msrq), func(t *testing.T) { 478 req := func(span roachpb.Span) roachpb.Request { 479 if reverse { 480 return roachpb.NewReverseScan(span.Key, span.EndKey, false) 481 } 482 return roachpb.NewScan(span.Key, span.EndKey, false) 483 } 484 // Paginate. 485 resumeSpan := &roachpb.Span{Key: tc.keys[0], EndKey: tc.keys[len(tc.keys)-1].Next()} 486 var keys []roachpb.Key 487 for { 488 numPages++ 489 scan := req(*resumeSpan) 490 var ba roachpb.BatchRequest 491 ba.Add(scan) 492 ba.Header.TargetBytes = targetBytes 493 ba.Header.MaxSpanRequestKeys = msrq 494 br, pErr := tds.Send(ctx, ba) 495 require.Nil(t, pErr) 496 var rows []roachpb.KeyValue 497 if reverse { 498 rows = br.Responses[0].GetReverseScan().Rows 499 } else { 500 rows = br.Responses[0].GetScan().Rows 501 } 502 for _, kv := range rows { 503 keys = append(keys, kv.Key) 504 } 505 resumeSpan = br.Responses[0].GetInner().Header().ResumeSpan 506 t.Logf("page #%d: scan %v -> keys (after) %v resume %v", scan.Header().Span(), numPages, keys, resumeSpan) 507 if resumeSpan == nil { 508 // Done with this pagination. 509 break 510 } 511 } 512 if reverse { 513 for i, n := 0, len(keys); i < n-i-1; i++ { 514 keys[i], keys[n-i-1] = keys[n-i-1], keys[i] 515 } 516 } 517 require.Equal(t, tc.keys, keys) 518 if targetBytes == 1 || msrq < int64(len(tc.keys)) { 519 // Definitely more than one page in this case. 520 require.Less(t, 1, numPages) 521 } 522 if targetBytes >= maxTargetBytes && msrq >= int64(len(tc.keys)) { 523 // Definitely one page if limits are larger than result set. 524 require.Equal(t, 1, numPages) 525 } 526 }) 527 if targetBytes >= maxTargetBytes || numPages == 1 { 528 if msrq >= int64(len(tc.keys)) { 529 return 530 } 531 targetBytes = 0 532 msrq++ 533 } 534 } 535 }) 536 }) 537 } 538 } 539 540 func TestSystemConfigGossip(t *testing.T) { 541 defer leaktest.AfterTest(t)() 542 543 ctx := context.Background() 544 s, _, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 545 defer s.Stopper().Stop(ctx) 546 ts := s.(*TestServer) 547 548 key := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, keys.MaxReservedDescID) 549 valAt := func(i int) *sqlbase.Descriptor { 550 return sqlbase.WrapDescriptor(&sqlbase.DatabaseDescriptor{ 551 ID: sqlbase.ID(i), 552 Name: "foo", 553 }) 554 } 555 556 // Register a callback for gossip updates. 557 resultChan := ts.Gossip().RegisterSystemConfigChannel() 558 559 // The span gets gossiped when it first shows up. 560 select { 561 case <-resultChan: 562 563 case <-time.After(500 * time.Millisecond): 564 t.Fatal("did not receive gossip message") 565 } 566 567 // Write a system key with the transaction marked as having a Gossip trigger. 568 if err := kvDB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 569 if err := txn.SetSystemConfigTrigger(); err != nil { 570 return err 571 } 572 return txn.Put(ctx, key, valAt(2)) 573 }); err != nil { 574 t.Fatal(err) 575 } 576 577 // This has to be wrapped in a SucceedSoon because system migrations on the 578 // testserver's startup can trigger system config updates without the key we 579 // wrote. 580 testutils.SucceedsSoon(t, func() error { 581 // New system config received. 582 var systemConfig *config.SystemConfig 583 select { 584 case <-resultChan: 585 systemConfig = ts.gossip.GetSystemConfig() 586 587 case <-time.After(500 * time.Millisecond): 588 return errors.Errorf("did not receive gossip message") 589 } 590 591 // Now check the new config. 592 var val *roachpb.Value 593 for _, kv := range systemConfig.Values { 594 if bytes.Equal(key, kv.Key) { 595 val = &kv.Value 596 break 597 } 598 } 599 if val == nil { 600 return errors.Errorf("key not found in gossiped info") 601 } 602 603 // Make sure the returned value is valAt(2). 604 var got sqlbase.Descriptor 605 if err := val.GetProto(&got); err != nil { 606 return err 607 } 608 609 expected := valAt(2).GetDatabase() 610 db := got.GetDatabase() 611 if db == nil { 612 panic(errors.Errorf("found nil database: %v", got)) 613 } 614 if !reflect.DeepEqual(*db, *expected) { 615 panic(errors.Errorf("mismatch: expected %+v, got %+v", *expected, *db)) 616 } 617 return nil 618 }) 619 } 620 621 func TestListenerFileCreation(t *testing.T) { 622 defer leaktest.AfterTest(t)() 623 624 dir, cleanupFn := testutils.TempDir(t) 625 defer cleanupFn() 626 627 s, err := serverutils.StartServerRaw(base.TestServerArgs{ 628 StoreSpecs: []base.StoreSpec{{ 629 Path: dir, 630 }}, 631 }) 632 if err != nil { 633 t.Fatal(err) 634 } 635 defer s.Stopper().Stop(context.Background()) 636 637 files, err := filepath.Glob(filepath.Join(dir, "cockroach.*")) 638 if err != nil { 639 t.Fatal(err) 640 } 641 642 li := listenerInfo{ 643 advertiseRPC: s.ServingRPCAddr(), 644 listenHTTP: s.HTTPAddr(), 645 listenRPC: s.RPCAddr(), 646 listenSQL: s.SQLAddr(), 647 advertiseSQL: s.ServingSQLAddr(), 648 } 649 expectedFiles := li.Iter() 650 651 for _, file := range files { 652 base := filepath.Base(file) 653 expVal, ok := expectedFiles[base] 654 if !ok { 655 t.Fatalf("unexpected file %s", file) 656 } 657 delete(expectedFiles, base) 658 659 data, err := ioutil.ReadFile(file) 660 if err != nil { 661 t.Fatal(err) 662 } 663 addr := string(data) 664 665 if addr != expVal { 666 t.Fatalf("expected %s %s to match host %s", base, addr, expVal) 667 } 668 } 669 670 for f := range expectedFiles { 671 t.Errorf("never saw expected file %s", f) 672 } 673 } 674 675 func TestClusterIDMismatch(t *testing.T) { 676 defer leaktest.AfterTest(t)() 677 678 engines := make([]storage.Engine, 2) 679 for i := range engines { 680 e := storage.NewDefaultInMem() 681 defer e.Close() 682 683 sIdent := roachpb.StoreIdent{ 684 ClusterID: uuid.MakeV4(), 685 NodeID: 1, 686 StoreID: roachpb.StoreID(i + 1), 687 } 688 if err := storage.MVCCPutProto( 689 context.Background(), e, nil, keys.StoreIdentKey(), hlc.Timestamp{}, nil, &sIdent); err != nil { 690 691 t.Fatal(err) 692 } 693 engines[i] = e 694 } 695 696 _, err := inspectEngines( 697 context.Background(), engines, roachpb.Version{}, roachpb.Version{}) 698 expected := "conflicting store ClusterIDs" 699 if !testutils.IsError(err, expected) { 700 t.Fatalf("expected %s error, got %v", expected, err) 701 } 702 } 703 704 func TestEnsureInitialWallTimeMonotonicity(t *testing.T) { 705 defer leaktest.AfterTest(t)() 706 707 testCases := []struct { 708 name string 709 prevHLCUpperBound int64 710 clockStartTime int64 711 checkPersist bool 712 }{ 713 { 714 name: "lower upper bound time", 715 prevHLCUpperBound: 100, 716 clockStartTime: 1000, 717 checkPersist: true, 718 }, 719 { 720 name: "higher upper bound time", 721 prevHLCUpperBound: 10000, 722 clockStartTime: 1000, 723 checkPersist: true, 724 }, 725 { 726 name: "significantly higher upper bound time", 727 prevHLCUpperBound: int64(3 * time.Hour), 728 clockStartTime: int64(1 * time.Hour), 729 checkPersist: true, 730 }, 731 { 732 name: "equal upper bound time", 733 prevHLCUpperBound: int64(time.Hour), 734 clockStartTime: int64(time.Hour), 735 checkPersist: true, 736 }, 737 } 738 739 for _, test := range testCases { 740 t.Run(test.name, func(t *testing.T) { 741 a := assert.New(t) 742 743 const maxOffset = 500 * time.Millisecond 744 m := hlc.NewManualClock(test.clockStartTime) 745 c := hlc.NewClock(m.UnixNano, maxOffset) 746 747 sleepUntilFn := func(until int64, currentTime func() int64) { 748 delta := until - currentTime() 749 if delta > 0 { 750 m.Increment(delta) 751 } 752 } 753 754 wallTime1 := c.Now().WallTime 755 if test.clockStartTime < test.prevHLCUpperBound { 756 a.True( 757 wallTime1 < test.prevHLCUpperBound, 758 fmt.Sprintf( 759 "expected wall time %d < prev upper bound %d", 760 wallTime1, 761 test.prevHLCUpperBound, 762 ), 763 ) 764 } 765 766 ensureClockMonotonicity( 767 context.Background(), 768 c, 769 c.PhysicalTime(), 770 test.prevHLCUpperBound, 771 sleepUntilFn, 772 ) 773 774 wallTime2 := c.Now().WallTime 775 // After ensuring monotonicity, wall time should be greater than 776 // persisted upper bound 777 a.True( 778 wallTime2 > test.prevHLCUpperBound, 779 fmt.Sprintf( 780 "expected wall time %d > prev upper bound %d", 781 wallTime2, 782 test.prevHLCUpperBound, 783 ), 784 ) 785 }) 786 } 787 } 788 789 func TestPersistHLCUpperBound(t *testing.T) { 790 defer leaktest.AfterTest(t)() 791 792 var fatal bool 793 defer log.ResetExitFunc() 794 log.SetExitFunc(true /* hideStack */, func(r int) { 795 defer log.Flush() 796 if r != 0 { 797 fatal = true 798 } 799 }) 800 801 testCases := []struct { 802 name string 803 persistInterval time.Duration 804 }{ 805 { 806 name: "persist default delta", 807 persistInterval: 200 * time.Millisecond, 808 }, 809 { 810 name: "persist 100ms delta", 811 persistInterval: 50 * time.Millisecond, 812 }, 813 } 814 815 for _, test := range testCases { 816 t.Run(test.name, func(t *testing.T) { 817 a := assert.New(t) 818 m := hlc.NewManualClock(int64(1)) 819 c := hlc.NewClock(m.UnixNano, time.Nanosecond) 820 821 var persistErr error 822 var persistedUpperBound int64 823 var tickerDur time.Duration 824 persistUpperBoundFn := func(i int64) error { 825 if persistErr != nil { 826 return persistErr 827 } 828 persistedUpperBound = i 829 return nil 830 } 831 832 tickerCh := make(chan time.Time) 833 tickProcessedCh := make(chan struct{}) 834 persistHLCUpperBoundIntervalCh := make(chan time.Duration, 1) 835 stopCh := make(chan struct{}, 1) 836 defer close(persistHLCUpperBoundIntervalCh) 837 838 go periodicallyPersistHLCUpperBound( 839 c, 840 persistHLCUpperBoundIntervalCh, 841 persistUpperBoundFn, 842 func(d time.Duration) *time.Ticker { 843 ticker := time.NewTicker(d) 844 ticker.Stop() 845 ticker.C = tickerCh 846 tickerDur = d 847 return ticker 848 }, 849 stopCh, 850 func() { 851 tickProcessedCh <- struct{}{} 852 }, 853 ) 854 855 fatal = false 856 // persist an upper bound 857 m.Increment(100) 858 wallTime3 := c.Now().WallTime 859 persistHLCUpperBoundIntervalCh <- test.persistInterval 860 <-tickProcessedCh 861 862 a.True( 863 test.persistInterval == tickerDur, 864 fmt.Sprintf( 865 "expected persist interval %d = ticker duration %d", 866 test.persistInterval, 867 tickerDur, 868 ), 869 ) 870 871 // Updating persistInterval should have triggered a persist 872 firstPersist := persistedUpperBound 873 a.True( 874 persistedUpperBound > wallTime3, 875 fmt.Sprintf( 876 "expected persisted wall time %d > wall time %d", 877 persistedUpperBound, 878 wallTime3, 879 ), 880 ) 881 // ensure that in memory value and persisted value are same 882 a.Equal(c.WallTimeUpperBound(), persistedUpperBound) 883 884 // Increment clock by 100 and tick the timer. 885 // A persist should have happened 886 m.Increment(100) 887 tickerCh <- timeutil.Now() 888 <-tickProcessedCh 889 secondPersist := persistedUpperBound 890 a.True( 891 secondPersist == firstPersist+100, 892 fmt.Sprintf( 893 "expected persisted wall time %d to be 100 more than earlier persisted value %d", 894 secondPersist, 895 firstPersist, 896 ), 897 ) 898 a.Equal(c.WallTimeUpperBound(), persistedUpperBound) 899 a.False(fatal) 900 fatal = false 901 902 // After disabling persistHLCUpperBound, a value of 0 should be persisted 903 persistHLCUpperBoundIntervalCh <- 0 904 <-tickProcessedCh 905 a.Equal( 906 int64(0), 907 c.WallTimeUpperBound(), 908 ) 909 a.Equal(int64(0), persistedUpperBound) 910 a.Equal(int64(0), c.WallTimeUpperBound()) 911 a.False(fatal) 912 fatal = false 913 914 persistHLCUpperBoundIntervalCh <- test.persistInterval 915 <-tickProcessedCh 916 m.Increment(100) 917 tickerCh <- timeutil.Now() 918 <-tickProcessedCh 919 // If persisting fails, a fatal error is expected 920 persistErr = errors.New("test err") 921 fatal = false 922 tickerCh <- timeutil.Now() 923 <-tickProcessedCh 924 a.True(fatal) 925 }) 926 } 927 } 928 929 func TestServeIndexHTML(t *testing.T) { 930 defer leaktest.AfterTest(t)() 931 932 const htmlTemplate = `<!DOCTYPE html> 933 <html> 934 <head> 935 <title>Cockroach Console</title> 936 <meta charset="UTF-8"> 937 <link href="favicon.ico" rel="shortcut icon"> 938 </head> 939 <body> 940 <div id="react-layout"></div> 941 942 <script> 943 window.dataFromServer = %s; 944 </script> 945 946 <script src="protos.dll.js" type="text/javascript"></script> 947 <script src="vendor.dll.js" type="text/javascript"></script> 948 <script src="bundle.js" type="text/javascript"></script> 949 </body> 950 </html> 951 ` 952 953 linkInFakeUI := func() { 954 ui.Asset = func(string) (_ []byte, _ error) { return } 955 ui.AssetDir = func(name string) (_ []string, _ error) { return } 956 ui.AssetInfo = func(name string) (_ os.FileInfo, _ error) { return } 957 } 958 unlinkFakeUI := func() { 959 ui.Asset = nil 960 ui.AssetDir = nil 961 ui.AssetInfo = nil 962 } 963 964 t.Run("Insecure mode", func(t *testing.T) { 965 s, _, _ := serverutils.StartServer(t, base.TestServerArgs{ 966 Insecure: true, 967 // This test server argument has the same effect as setting the environment variable 968 // `COCKROACH_EXPERIMENTAL_REQUIRE_WEB_SESSION` to false, or not setting it. 969 // In test servers, web sessions are required by default. 970 DisableWebSessionAuthentication: true, 971 }) 972 defer s.Stopper().Stop(context.Background()) 973 tsrv := s.(*TestServer) 974 975 client, err := tsrv.GetHTTPClient() 976 if err != nil { 977 t.Fatal(err) 978 } 979 980 t.Run("short build", func(t *testing.T) { 981 resp, err := client.Get(s.AdminURL()) 982 if err != nil { 983 t.Fatal(err) 984 } 985 if resp.StatusCode != 200 { 986 t.Fatalf("expected status code 200; got %d", resp.StatusCode) 987 } 988 respBytes, err := ioutil.ReadAll(resp.Body) 989 if err != nil { 990 t.Fatal(err) 991 } 992 respString := string(respBytes) 993 expected := fmt.Sprintf(`<!DOCTYPE html> 994 <title>CockroachDB</title> 995 Binary built without web UI. 996 <hr> 997 <em>%s</em>`, 998 build.GetInfo().Short()) 999 if respString != expected { 1000 t.Fatalf("expected %s; got %s", expected, respString) 1001 } 1002 }) 1003 1004 t.Run("non-short build", func(t *testing.T) { 1005 linkInFakeUI() 1006 defer unlinkFakeUI() 1007 resp, err := client.Get(s.AdminURL()) 1008 if err != nil { 1009 t.Fatal(err) 1010 } 1011 if resp.StatusCode != 200 { 1012 t.Fatalf("expected status code 200; got %d", resp.StatusCode) 1013 } 1014 respBytes, err := ioutil.ReadAll(resp.Body) 1015 if err != nil { 1016 t.Fatal(err) 1017 } 1018 respString := string(respBytes) 1019 expected := fmt.Sprintf( 1020 htmlTemplate, 1021 fmt.Sprintf( 1022 `{"ExperimentalUseLogin":false,"LoginEnabled":false,"LoggedInUser":null,"Tag":"%s","Version":"%s","NodeID":"%d"}`, 1023 build.GetInfo().Tag, 1024 build.VersionPrefix(), 1025 1, 1026 ), 1027 ) 1028 if respString != expected { 1029 t.Fatalf("expected %s; got %s", expected, respString) 1030 } 1031 }) 1032 }) 1033 1034 t.Run("Secure mode", func(t *testing.T) { 1035 linkInFakeUI() 1036 defer unlinkFakeUI() 1037 s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) 1038 defer s.Stopper().Stop(context.Background()) 1039 tsrv := s.(*TestServer) 1040 1041 loggedInClient, err := tsrv.GetAdminAuthenticatedHTTPClient() 1042 if err != nil { 1043 t.Fatal(err) 1044 } 1045 loggedOutClient, err := tsrv.GetHTTPClient() 1046 if err != nil { 1047 t.Fatal(err) 1048 } 1049 1050 cases := []struct { 1051 client http.Client 1052 json string 1053 }{ 1054 { 1055 loggedInClient, 1056 fmt.Sprintf( 1057 `{"ExperimentalUseLogin":true,"LoginEnabled":true,"LoggedInUser":"authentic_user","Tag":"%s","Version":"%s","NodeID":"%d"}`, 1058 build.GetInfo().Tag, 1059 build.VersionPrefix(), 1060 1, 1061 ), 1062 }, 1063 { 1064 loggedOutClient, 1065 fmt.Sprintf( 1066 `{"ExperimentalUseLogin":true,"LoginEnabled":true,"LoggedInUser":null,"Tag":"%s","Version":"%s","NodeID":"%d"}`, 1067 build.GetInfo().Tag, 1068 build.VersionPrefix(), 1069 1, 1070 ), 1071 }, 1072 } 1073 1074 for _, testCase := range cases { 1075 resp, err := testCase.client.Get(s.AdminURL()) 1076 if err != nil { 1077 t.Fatal(err) 1078 } 1079 if resp.StatusCode != 200 { 1080 t.Fatalf("expected status code 200; got %d", resp.StatusCode) 1081 } 1082 respBytes, err := ioutil.ReadAll(resp.Body) 1083 if err != nil { 1084 t.Fatal(err) 1085 } 1086 respString := string(respBytes) 1087 expected := fmt.Sprintf(htmlTemplate, testCase.json) 1088 if respString != expected { 1089 t.Fatalf("expected %s; got %s", expected, respString) 1090 } 1091 } 1092 }) 1093 }