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  }