github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/testutils/serverutils/test_server_shim.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  // This file provides generic interfaces that allow tests to set up test servers
    12  // without importing the server package (avoiding circular dependencies).
    13  // To be used, the binary needs to call
    14  // InitTestServerFactory(server.TestServerFactory), generally from a TestMain()
    15  // in an "foo_test" package (which can import server and is linked together with
    16  // the other tests in package "foo").
    17  
    18  package serverutils
    19  
    20  import (
    21  	"context"
    22  	gosql "database/sql"
    23  	"net/http"
    24  	"net/url"
    25  	"testing"
    26  
    27  	"github.com/cockroachdb/cockroach/pkg/base"
    28  	"github.com/cockroachdb/cockroach/pkg/kv"
    29  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    30  	"github.com/cockroachdb/cockroach/pkg/rpc"
    31  	"github.com/cockroachdb/cockroach/pkg/security"
    32  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    33  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    34  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    35  	"github.com/cockroachdb/cockroach/pkg/util/httputil"
    36  	"github.com/cockroachdb/cockroach/pkg/util/protoutil"
    37  	"github.com/cockroachdb/cockroach/pkg/util/stop"
    38  )
    39  
    40  // TestServerInterface defines test server functionality that tests need; it is
    41  // implemented by server.TestServer.
    42  type TestServerInterface interface {
    43  	Stopper() *stop.Stopper
    44  
    45  	Start(params base.TestServerArgs) error
    46  
    47  	// Node returns the server.Node as an interface{}.
    48  	Node() interface{}
    49  
    50  	// NodeID returns the ID of this node within its cluster.
    51  	NodeID() roachpb.NodeID
    52  
    53  	// ServingRPCAddr returns the server's advertised address.
    54  	ServingRPCAddr() string
    55  
    56  	// ServingSQLAddr returns the server's advertised SQL address.
    57  	ServingSQLAddr() string
    58  
    59  	// HTTPAddr returns the server's http address.
    60  	HTTPAddr() string
    61  
    62  	// RPCAddr returns the server's RPC address.
    63  	// Note: use ServingRPCAddr() instead unless specific reason not to.
    64  	RPCAddr() string
    65  
    66  	// SQLAddr returns the server's SQL address.
    67  	// Note: use ServingSQLAddr() instead unless specific reason not to.
    68  	SQLAddr() string
    69  
    70  	// DB returns a *client.DB instance for talking to this KV server.
    71  	DB() *kv.DB
    72  
    73  	// RPCContext returns the rpc context used by the test server.
    74  	RPCContext() *rpc.Context
    75  
    76  	// LeaseManager() returns the *sql.LeaseManager as an interface{}.
    77  	LeaseManager() interface{}
    78  
    79  	// InternalExecutor returns a *sql.InternalExecutor as an interface{} (which
    80  	// also implements sqlutil.InternalExecutor if the test cannot depend on sql).
    81  	InternalExecutor() interface{}
    82  
    83  	// ExecutorConfig returns a copy of the server's ExecutorConfig.
    84  	// The real return type is sql.ExecutorConfig.
    85  	ExecutorConfig() interface{}
    86  
    87  	// GossipI returns the gossip used by the TestServer.
    88  	// The real return type is *gossip.Gossip.
    89  	GossipI() interface{}
    90  
    91  	// Clock returns the clock used by the TestServer.
    92  	Clock() *hlc.Clock
    93  
    94  	// DistSenderI returns the DistSender used by the TestServer.
    95  	// The real return type is *kv.DistSender.
    96  	DistSenderI() interface{}
    97  
    98  	// SQLServer returns the *sql.Server as an interface{}.
    99  	SQLServer() interface{}
   100  
   101  	// DistSQLServer returns the *distsql.ServerImpl as an interface{}.
   102  	DistSQLServer() interface{}
   103  
   104  	// JobRegistry returns the *jobs.Registry as an interface{}.
   105  	JobRegistry() interface{}
   106  
   107  	// MigrationManager returns the *jobs.Registry as an interface{}.
   108  	MigrationManager() interface{}
   109  
   110  	// SetDistSQLSpanResolver changes the SpanResolver used for DistSQL inside the
   111  	// server's executor. The argument must be a physicalplan.SpanResolver
   112  	// instance.
   113  	//
   114  	// This method exists because we cannot pass the fake span resolver with the
   115  	// server or cluster params: the fake span resolver needs the node IDs and
   116  	// addresses of the servers in a cluster, which are not available before we
   117  	// start the servers.
   118  	//
   119  	// It is the caller's responsibility to make sure no queries are being run
   120  	// with DistSQL at the same time.
   121  	SetDistSQLSpanResolver(spanResolver interface{})
   122  
   123  	// AdminURL returns the URL for the admin UI.
   124  	AdminURL() string
   125  	// GetHTTPClient returns an http client configured with the client TLS
   126  	// config required by the TestServer's configuration.
   127  	GetHTTPClient() (http.Client, error)
   128  	// GetAdminAuthenticatedHTTPClient returns an http client which has been
   129  	// authenticated to access Admin API methods (via a cookie).
   130  	// The user has admin privileges.
   131  	GetAdminAuthenticatedHTTPClient() (http.Client, error)
   132  	// GetAuthenticatedHTTPClient returns an http client which has been
   133  	// authenticated to access Admin API methods (via a cookie).
   134  	GetAuthenticatedHTTPClient(isAdmin bool) (http.Client, error)
   135  
   136  	// MustGetSQLCounter returns the value of a counter metric from the server's
   137  	// SQL Executor. Runs in O(# of metrics) time, which is fine for test code.
   138  	MustGetSQLCounter(name string) int64
   139  	// MustGetSQLNetworkCounter returns the value of a counter metric from the
   140  	// server's SQL server. Runs in O(# of metrics) time, which is fine for test
   141  	// code.
   142  	MustGetSQLNetworkCounter(name string) int64
   143  	// WriteSummaries records summaries of time-series data, which is required for
   144  	// any tests that query server stats.
   145  	WriteSummaries() error
   146  
   147  	// GetFirstStoreID is a utility function returning the StoreID of the first
   148  	// store on this node.
   149  	GetFirstStoreID() roachpb.StoreID
   150  
   151  	// GetStores returns the collection of stores from this TestServer's node.
   152  	// The return value is of type *storage.Stores.
   153  	GetStores() interface{}
   154  
   155  	// ClusterSettings returns the ClusterSettings shared by all components of
   156  	// this server.
   157  	ClusterSettings() *cluster.Settings
   158  
   159  	// SplitRange splits the range containing splitKey.
   160  	SplitRange(
   161  		splitKey roachpb.Key,
   162  	) (left roachpb.RangeDescriptor, right roachpb.RangeDescriptor, err error)
   163  
   164  	// MergeRanges merges the range containing leftKey with the following adjacent
   165  	// range.
   166  	MergeRanges(leftKey roachpb.Key) (merged roachpb.RangeDescriptor, err error)
   167  
   168  	// ExpectedInitialRangeCount returns the expected number of ranges that should
   169  	// be on the server after initial (asynchronous) splits have been completed,
   170  	// assuming no additional information is added outside of the normal bootstrap
   171  	// process.
   172  	ExpectedInitialRangeCount() (int, error)
   173  
   174  	// ForceTableGC sends a GCRequest for the ranges corresponding to a table.
   175  	//
   176  	// An error will be returned if the same table name exists in multiple schemas
   177  	// inside the specified database.
   178  	ForceTableGC(ctx context.Context, database, table string, timestamp hlc.Timestamp) error
   179  
   180  	// CheckForUpdates phones home to check for updates and report usage.
   181  	//
   182  	// When using this for testing, consider setting DiagnosticsReportingEnabled
   183  	// to false so the periodic check doesn't interfere with the test.
   184  	//
   185  	// This can be slow because of cloud detection; use cloudinfo.Disable() in
   186  	// tests to avoid that.
   187  	CheckForUpdates(ctx context.Context)
   188  
   189  	// ReportDiagnostics phones home to report diagnostics.
   190  	//
   191  	// If using this for testing, consider setting DiagnosticsReportingEnabled to
   192  	// false so the periodic reporting doesn't interfere with the test.
   193  	//
   194  	// This can be slow because of cloud detection; use cloudinfo.Disable() in
   195  	// tests to avoid that.
   196  	ReportDiagnostics(ctx context.Context)
   197  
   198  	// StartTenant spawns off tenant process connecting to this TestServer.
   199  	StartTenant(params base.TestTenantArgs) (pgAddr string, _ error)
   200  }
   201  
   202  // TestServerFactory encompasses the actual implementation of the shim
   203  // service.
   204  type TestServerFactory interface {
   205  	// New instantiates a test server.
   206  	New(params base.TestServerArgs) interface{}
   207  }
   208  
   209  var srvFactoryImpl TestServerFactory
   210  
   211  // InitTestServerFactory should be called once to provide the implementation
   212  // of the service. It will be called from a xx_test package that can import the
   213  // server package.
   214  func InitTestServerFactory(impl TestServerFactory) {
   215  	srvFactoryImpl = impl
   216  }
   217  
   218  // StartServer creates a test server and sets up a gosql DB connection.
   219  // The server should be stopped by calling server.Stopper().Stop().
   220  func StartServer(
   221  	t testing.TB, params base.TestServerArgs,
   222  ) (TestServerInterface, *gosql.DB, *kv.DB) {
   223  	server, err := StartServerRaw(params)
   224  	if err != nil {
   225  		t.Fatalf("%+v", err)
   226  	}
   227  
   228  	pgURL, cleanupGoDB := sqlutils.PGUrl(
   229  		t, server.ServingSQLAddr(), "StartServer" /* prefix */, url.User(security.RootUser))
   230  	pgURL.Path = params.UseDatabase
   231  	if params.Insecure {
   232  		pgURL.RawQuery = "sslmode=disable"
   233  	}
   234  	goDB, err := gosql.Open("postgres", pgURL.String())
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	server.Stopper().AddCloser(
   239  		stop.CloserFn(func() {
   240  			_ = goDB.Close()
   241  			cleanupGoDB()
   242  		}))
   243  	return server, goDB, server.DB()
   244  }
   245  
   246  // StartServerRaw creates and starts a TestServer.
   247  // Generally StartServer() should be used. However this function can be used
   248  // directly when opening a connection to the server is not desired.
   249  func StartServerRaw(args base.TestServerArgs) (TestServerInterface, error) {
   250  	if srvFactoryImpl == nil {
   251  		panic("TestServerFactory not initialized. One needs to be injected " +
   252  			"from the package's TestMain()")
   253  	}
   254  	server := srvFactoryImpl.New(args).(TestServerInterface)
   255  	if err := server.Start(args); err != nil {
   256  		return nil, err
   257  	}
   258  	return server, nil
   259  }
   260  
   261  // StartTenant starts a tenant SQL server connecting to the supplied test
   262  // server. It uses the server's stopper to shut down automatically. However,
   263  // the returned DB is for the caller to close.
   264  func StartTenant(t testing.TB, ts TestServerInterface, params base.TestTenantArgs) *gosql.DB {
   265  	pgAddr, err := ts.StartTenant(params)
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	pgURL, cleanupGoDB := sqlutils.PGUrl(
   271  		t, pgAddr, t.Name() /* prefix */, url.User(security.RootUser))
   272  
   273  	db, err := gosql.Open("postgres", pgURL.String())
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  	ts.Stopper().AddCloser(stop.CloserFn(func() {
   278  		cleanupGoDB()
   279  	}))
   280  	return db
   281  }
   282  
   283  // GetJSONProto uses the supplied client to GET the URL specified by the parameters
   284  // and unmarshals the result into response.
   285  func GetJSONProto(ts TestServerInterface, path string, response protoutil.Message) error {
   286  	return GetJSONProtoWithAdminOption(ts, path, response, true)
   287  }
   288  
   289  // GetJSONProtoWithAdminOption is like GetJSONProto but the caller can customize
   290  // whether the request is performed with admin privilege
   291  func GetJSONProtoWithAdminOption(
   292  	ts TestServerInterface, path string, response protoutil.Message, isAdmin bool,
   293  ) error {
   294  	httpClient, err := ts.GetAuthenticatedHTTPClient(isAdmin)
   295  	if err != nil {
   296  		return err
   297  	}
   298  	return httputil.GetJSON(httpClient, ts.AdminURL()+path, response)
   299  }
   300  
   301  // PostJSONProto uses the supplied client to POST the URL specified by the parameters
   302  // and unmarshals the result into response.
   303  func PostJSONProto(ts TestServerInterface, path string, request, response protoutil.Message) error {
   304  	return PostJSONProtoWithAdminOption(ts, path, request, response, true)
   305  }
   306  
   307  // PostJSONProtoWithAdminOption is like PostJSONProto but the caller
   308  // can customize whether the request is performed with admin
   309  // privilege.
   310  func PostJSONProtoWithAdminOption(
   311  	ts TestServerInterface, path string, request, response protoutil.Message, isAdmin bool,
   312  ) error {
   313  	httpClient, err := ts.GetAuthenticatedHTTPClient(isAdmin)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	return httputil.PostJSON(httpClient, ts.AdminURL()+path, request, response)
   318  }