Ejemplo n.º 1
0
// Start starts the test cluster by bootstrapping an in-memory store
// (defaults to maximum of 50M). The server is started, launching the
// node RPC server and all HTTP endpoints. Use the value of
// TestServer.Addr after Start() for client connections. Use Stop()
// to shutdown the server after the test completes.
func (ltc *LocalTestCluster) Start(t util.Tester) {
	ltc.Manual = hlc.NewManualClock(0)
	ltc.Clock = hlc.NewClock(ltc.Manual.UnixNano)
	ltc.Stopper = util.NewStopper()
	rpcContext := rpc.NewContext(testutils.NewTestBaseContext(), ltc.Clock, ltc.Stopper)
	ltc.Gossip = gossip.New(rpcContext, gossip.TestInterval, gossip.TestBootstrap)
	ltc.Eng = engine.NewInMem(proto.Attributes{}, 50<<20)
	ltc.lSender = newRetryableLocalSender(NewLocalSender())
	ltc.Sender = NewTxnCoordSender(ltc.lSender, ltc.Clock, false, ltc.Stopper)
	var err error
	if ltc.DB, err = client.Open("//root@", client.SenderOpt(ltc.Sender)); err != nil {
		t.Fatal(err)
	}
	transport := multiraft.NewLocalRPCTransport()
	ltc.Stopper.AddCloser(transport)
	ctx := storage.TestStoreContext
	ctx.Clock = ltc.Clock
	ctx.DB = ltc.DB
	ctx.Gossip = ltc.Gossip
	ctx.Transport = transport
	ltc.Store = storage.NewStore(ctx, ltc.Eng, &proto.NodeDescriptor{NodeID: 1})
	if err := ltc.Store.Bootstrap(proto.StoreIdent{NodeID: 1, StoreID: 1}, ltc.Stopper); err != nil {
		t.Fatalf("unable to start local test cluster: %s", err)
	}
	ltc.lSender.AddStore(ltc.Store)
	if err := ltc.Store.BootstrapRange(); err != nil {
		t.Fatalf("unable to start local test cluster: %s", err)
	}
	if err := ltc.Store.Start(ltc.Stopper); err != nil {
		t.Fatalf("unable to start local test cluster: %s", err)
	}
}
Ejemplo n.º 2
0
// getText fetches the HTTP response body as text in the form of a
// byte slice from the specified URL.
func getText(url string) ([]byte, error) {
	// There are no particular permissions on admin endpoints, TestUser is fine.
	client, err := testutils.NewTestBaseContext(TestUser).GetHTTPClient()
	if err != nil {
		return nil, err
	}
	resp, err := client.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}
Ejemplo n.º 3
0
// TestHTTPSenderRetryHTTPSendError verifies that send is retried
// on all errors sending HTTP requests.
func TestHTTPSenderRetryHTTPSendError(t *testing.T) {
	defer leaktest.AfterTest(t)
	retryOptions := defaultRetryOptions
	retryOptions.Backoff = 1 * time.Millisecond

	testCases := []func(*httptest.Server, http.ResponseWriter){
		// Send back an unparseable response but a success code on first try.
		func(s *httptest.Server, w http.ResponseWriter) {
			fmt.Fprintf(w, "\xff\xfe\x23\x44")
		},
		// Close the client connection.
		func(s *httptest.Server, w http.ResponseWriter) {
			s.CloseClientConnections()
		},
	}

	for i, testFunc := range testCases {
		count := 0
		var s *httptest.Server
		server, addr := startTestHTTPServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			count++
			if count == 1 {
				// On first retry, invoke the error function.
				testFunc(s, w)
				return
			}
			// Success on second try.
			body, contentType, err := util.MarshalResponse(r, testPutResp, util.AllEncodings)
			if err != nil {
				t.Errorf("%d: failed to marshal response: %s", i, err)
			}
			w.Header().Set(util.ContentTypeHeader, contentType)
			w.Write(body)
		}))

		s = server
		sender, err := newHTTPSender(addr, testutils.NewTestBaseContext(), retryOptions)
		if err != nil {
			t.Fatal(err)
		}
		reply := &proto.PutResponse{}
		sender.Send(context.Background(), proto.Call{Args: testPutReq, Reply: reply})
		if reply.GoError() != nil {
			t.Errorf("%d: expected success; got %s", i, reply.GoError())
		}
		if count != 2 {
			t.Errorf("%d: expected retry", i)
		}
		server.Close()
	}
}
Ejemplo n.º 4
0
// TestHTTPSenderSend verifies sending posts.
func TestHTTPSenderSend(t *testing.T) {
	defer leaktest.AfterTest(t)
	server, addr := startTestHTTPServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			t.Errorf("expected method POST; got %s", r.Method)
		}
		if r.URL.Path != KVDBEndpoint+"Put" {
			t.Errorf("expected url %s; got %s", KVDBEndpoint+"Put", r.URL.Path)
		}
		// Unmarshal the request.
		reqBody, err := ioutil.ReadAll(r.Body)
		if err != nil {
			t.Errorf("unexpected error reading body: %s", err)
		}
		args := &proto.PutRequest{}
		if err := util.UnmarshalRequest(r, reqBody, args, util.AllEncodings); err != nil {
			t.Errorf("unexpected error unmarshalling request: %s", err)
		}
		if !args.Key.Equal(testPutReq.Key) || !args.Timestamp.Equal(testPutReq.Timestamp) {
			t.Errorf("expected parsed %+v to equal %+v", args, testPutReq)
		}
		body, contentType, err := util.MarshalResponse(r, testPutResp, util.AllEncodings)
		if err != nil {
			t.Errorf("failed to marshal response: %s", err)
		}
		w.Header().Set(util.ContentTypeHeader, contentType)
		w.Write(body)
	}))
	defer server.Close()

	sender, err := newHTTPSender(addr, testutils.NewTestBaseContext(), defaultRetryOptions)
	if err != nil {
		t.Fatal(err)
	}
	reply := &proto.PutResponse{}
	sender.Send(context.Background(), proto.Call{Args: testPutReq, Reply: reply})
	if reply.GoError() != nil {
		t.Errorf("expected success; got %s", reply.GoError())
	}
	if !reply.Timestamp.Equal(testPutResp.Timestamp) {
		t.Errorf("expected received %+v to equal %+v", reply, testPutResp)
	}
}
Ejemplo n.º 5
0
// TestAdminDebugRedirect verifies that the /debug/ endpoint is redirected to on
// incorrect /debug/ paths.
func TestAdminDebugRedirect(t *testing.T) {
	defer leaktest.AfterTest(t)()
	s := StartTestServer(t)
	defer s.Stop()

	expURL := debugURL(s)
	origURL := expURL + "incorrect"

	// There are no particular permissions on admin endpoints, TestUser is fine.
	client, err := testutils.NewTestBaseContext(TestUser).GetHTTPClient()
	if err != nil {
		t.Fatal(err)
	}

	// Don't follow redirects automatically.
	redirectAttemptedError := errors.New("redirect")
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return redirectAttemptedError
	}

	resp, err := client.Get(origURL)
	if urlError, ok := err.(*url.Error); ok && urlError.Err == redirectAttemptedError {
		// Ignore the redirectAttemptedError.
		err = nil
	}
	if err != nil {
		t.Fatal(err)
	} else {
		resp.Body.Close()
		if resp.StatusCode != http.StatusMovedPermanently {
			t.Errorf("expected status code %d; got %d", http.StatusMovedPermanently, resp.StatusCode)
		}
		if redirectURL, err := resp.Location(); err != nil {
			t.Error(err)
		} else if foundURL := redirectURL.String(); foundURL != expURL {
			t.Errorf("expected location %s; got %s", expURL, foundURL)
		}
	}
}
Ejemplo n.º 6
0
	"golang.org/x/net/context"

	snappy "github.com/cockroachdb/c-snappy"
	"github.com/cockroachdb/cockroach/kv"
	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/storage"
	"github.com/cockroachdb/cockroach/storage/engine"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/log"
)

var testContext = NewTestContext()
var testBaseContext = testutils.NewTestBaseContext()
var serverTestBaseContext = testutils.NewServerTestBaseContext()

// createTestConfigFile creates a temporary file and writes the
// testConfig yaml data to it. The caller is responsible for
// removing it. Returns the filename for a subsequent call to
// os.Remove().
func createTestConfigFile(body string) string {
	f, err := ioutil.TempFile("", "test-config")
	if err != nil {
		log.Fatalf("failed to open temporary file: %v", err)
	}
	defer f.Close()
	if _, err = f.Write([]byte(body)); err != nil {
		log.Fatalf("failed to write to temporary file: %v", err)
	}
Ejemplo n.º 7
0
// Verify client certificate enforcement and user whitelisting.
func TestSSLEnforcement(t *testing.T) {
	defer leaktest.AfterTest(t)()
	s, _, _ := serverutils.StartServer(t, base.TestServerArgs{})
	defer s.Stopper().Stop()

	// HTTPS with client certs for security.RootUser.
	rootCertsContext := testutils.NewTestBaseContext(security.RootUser)
	// HTTPS with client certs for security.NodeUser.
	nodeCertsContext := testutils.NewNodeTestBaseContext()
	// HTTPS with client certs for TestUser.
	testCertsContext := testutils.NewTestBaseContext(TestUser)
	// HTTPS without client certs. The user does not matter.
	noCertsContext := testutils.NewTestBaseContext(TestUser)
	noCertsContext.SSLCert = ""
	// Plain http.
	insecureContext := testutils.NewTestBaseContext(TestUser)
	insecureContext.Insecure = true

	kvGet := &roachpb.GetRequest{}
	kvGet.Key = roachpb.Key("/")

	testCases := []struct {
		method, path string
		body         proto.Message
		ctx          *base.Context
		success      bool // request sent successfully (may be non-200)
		code         int  // http response code
	}{
		// /ui/: basic file server: no auth.
		{"GET", "/index.html", nil, rootCertsContext, true, http.StatusOK},
		{"GET", "/index.html", nil, nodeCertsContext, true, http.StatusOK},
		{"GET", "/index.html", nil, testCertsContext, true, http.StatusOK},
		{"GET", "/index.html", nil, noCertsContext, true, http.StatusOK},
		// TODO(tamird): s/308/http.StatusPermanentRedirect/ when it exists.
		{"GET", "/index.html", nil, insecureContext, true, 308},

		// /_admin/: server.adminServer: no auth.
		{"GET", healthPath, nil, rootCertsContext, true, http.StatusOK},
		{"GET", healthPath, nil, nodeCertsContext, true, http.StatusOK},
		{"GET", healthPath, nil, testCertsContext, true, http.StatusOK},
		{"GET", healthPath, nil, noCertsContext, true, http.StatusOK},
		// TODO(tamird): s/308/http.StatusPermanentRedirect/ when it exists.
		{"GET", healthPath, nil, insecureContext, true, 308},

		// /debug/: server.adminServer: no auth.
		{"GET", debugEndpoint + "vars", nil, rootCertsContext, true, http.StatusOK},
		{"GET", debugEndpoint + "vars", nil, nodeCertsContext, true, http.StatusOK},
		{"GET", debugEndpoint + "vars", nil, testCertsContext, true, http.StatusOK},
		{"GET", debugEndpoint + "vars", nil, noCertsContext, true, http.StatusOK},
		// TODO(tamird): s/308/http.StatusPermanentRedirect/ when it exists.
		{"GET", debugEndpoint + "vars", nil, insecureContext, true, 308},

		// /_status/nodes: server.statusServer: no auth.
		{"GET", statusNodesPrefix, nil, rootCertsContext, true, http.StatusOK},
		{"GET", statusNodesPrefix, nil, nodeCertsContext, true, http.StatusOK},
		{"GET", statusNodesPrefix, nil, testCertsContext, true, http.StatusOK},
		{"GET", statusNodesPrefix, nil, noCertsContext, true, http.StatusOK},
		// TODO(tamird): s/308/http.StatusPermanentRedirect/ when it exists.
		{"GET", statusNodesPrefix, nil, insecureContext, true, 308},

		// /ts/: ts.Server: no auth.
		{"GET", ts.URLPrefix, nil, rootCertsContext, true, http.StatusNotFound},
		{"GET", ts.URLPrefix, nil, nodeCertsContext, true, http.StatusNotFound},
		{"GET", ts.URLPrefix, nil, testCertsContext, true, http.StatusNotFound},
		{"GET", ts.URLPrefix, nil, noCertsContext, true, http.StatusNotFound},
		// TODO(tamird): s/308/http.StatusPermanentRedirect/ when it exists.
		{"GET", ts.URLPrefix, nil, insecureContext, true, 308},
	}

	for tcNum, tc := range testCases {
		client, err := tc.ctx.GetHTTPClient()
		if err != nil {
			t.Fatalf("[%d]: failed to get http client: %v", tcNum, err)
		}
		url := fmt.Sprintf(
			"%s://%s%s", tc.ctx.HTTPRequestScheme(),
			s.(*TestServer).Ctx.HTTPAddr, tc.path)
		resp, err := doHTTPReq(t, client, tc.method, url, tc.body)
		if (err == nil) != tc.success {
			t.Errorf("[%d]: expected success=%t, got err=%v", tcNum, tc.success, err)
		}
		if err != nil {
			continue
		}

		defer resp.Body.Close()
		if resp.StatusCode != tc.code {
			t.Errorf("[%d]: expected status code %d, got %d", tcNum, tc.code, resp.StatusCode)
		}
	}
}
Ejemplo n.º 8
0
// Verify client certificate enforcement and user whitelisting.
func TestSSLEnforcement(t *testing.T) {
	defer leaktest.AfterTest(t)
	s := StartTestServer(t)
	defer s.Stop()

	// HTTPS with client certs for "root".
	rootCertsContext := testutils.NewTestBaseContext(security.RootUser)
	// HTTPS with client certs for "node".
	nodeCertsContext := testutils.NewNodeTestBaseContext()
	// HTTPS with client certs for testuser.
	testCertsContext := testutils.NewTestBaseContext(TestUser)
	// HTTPS without client certs. The user does not matter.
	noCertsContext := testutils.NewTestBaseContext(TestUser)
	noCertsContext.Certs = ""
	// Plain http.
	insecureContext := testutils.NewTestBaseContext(TestUser)
	insecureContext.Insecure = true

	kvGet := &roachpb.GetRequest{}
	kvGet.Key = roachpb.Key("/")

	testCases := []struct {
		method, key string
		body        proto.Message
		ctx         *base.Context
		success     bool // request sent successfully (may be non-200)
		code        int  // http response code
	}{
		// /ui/: basic file server: no auth.
		{"GET", "/index.html", nil, rootCertsContext, true, http.StatusOK},
		{"GET", "/index.html", nil, nodeCertsContext, true, http.StatusOK},
		{"GET", "/index.html", nil, testCertsContext, true, http.StatusOK},
		{"GET", "/index.html", nil, noCertsContext, true, http.StatusOK},
		{"GET", "/index.html", nil, insecureContext, false, -1},

		// /_admin/: server.adminServer: no auth.
		{"GET", healthPath, nil, rootCertsContext, true, http.StatusOK},
		{"GET", healthPath, nil, nodeCertsContext, true, http.StatusOK},
		{"GET", healthPath, nil, testCertsContext, true, http.StatusOK},
		{"GET", healthPath, nil, noCertsContext, true, http.StatusOK},
		{"GET", healthPath, nil, insecureContext, false, -1},

		// /debug/: server.adminServer: no auth.
		{"GET", debugEndpoint + "vars", nil, rootCertsContext, true, http.StatusOK},
		{"GET", debugEndpoint + "vars", nil, nodeCertsContext, true, http.StatusOK},
		{"GET", debugEndpoint + "vars", nil, testCertsContext, true, http.StatusOK},
		{"GET", debugEndpoint + "vars", nil, noCertsContext, true, http.StatusOK},
		{"GET", debugEndpoint + "vars", nil, insecureContext, false, -1},

		// /_status/nodes: server.statusServer: no auth.
		{"GET", statusNodesPrefix, nil, rootCertsContext, true, http.StatusOK},
		{"GET", statusNodesPrefix, nil, nodeCertsContext, true, http.StatusOK},
		{"GET", statusNodesPrefix, nil, testCertsContext, true, http.StatusOK},
		{"GET", statusNodesPrefix, nil, noCertsContext, true, http.StatusOK},
		{"GET", statusNodesPrefix, nil, insecureContext, false, -1},

		// /ts/: ts.Server: no auth.
		{"GET", ts.URLPrefix, nil, rootCertsContext, true, http.StatusNotFound},
		{"GET", ts.URLPrefix, nil, nodeCertsContext, true, http.StatusNotFound},
		{"GET", ts.URLPrefix, nil, testCertsContext, true, http.StatusNotFound},
		{"GET", ts.URLPrefix, nil, noCertsContext, true, http.StatusNotFound},
		{"GET", ts.URLPrefix, nil, insecureContext, false, -1},

		// /sql/: sql.Server. These are proto reqs. The important field is header.User.
		{"POST", driver.Endpoint + driver.Execute.String(), sqlForUser(rootCertsContext),
			rootCertsContext, true, http.StatusOK},
		{"POST", driver.Endpoint + driver.Execute.String(), sqlForUser(nodeCertsContext),
			nodeCertsContext, true, http.StatusOK},
		{"POST", driver.Endpoint + driver.Execute.String(), sqlForUser(testCertsContext),
			testCertsContext, true, http.StatusOK},
		{"POST", driver.Endpoint + driver.Execute.String(), sqlForUser(noCertsContext),
			noCertsContext, true, http.StatusUnauthorized},
		{"POST", driver.Endpoint + driver.Execute.String(), sqlForUser(insecureContext),
			insecureContext, false, -1},
	}

	for tcNum, tc := range testCases {
		client, err := tc.ctx.GetHTTPClient()
		if err != nil {
			t.Fatalf("[%d]: failed to get http client: %v", tcNum, err)
		}
		resp, err := doHTTPReq(t, client, tc.method,
			fmt.Sprintf("%s://%s%s", tc.ctx.HTTPRequestScheme(), s.ServingAddr(), tc.key),
			tc.body)
		if (err == nil) != tc.success {
			t.Fatalf("[%d]: expected success=%t, got err=%v", tcNum, tc.success, err)
		}
		if err != nil {
			continue
		}

		defer resp.Body.Close()
		if resp.StatusCode != tc.code {
			t.Errorf("[%d]: expected status code %d, got %d", tcNum, tc.code, resp.StatusCode)
		}
	}
}
Ejemplo n.º 9
0
// Verify client certificate enforcement.
func TestSSLEnforcement(t *testing.T) {
	defer leaktest.AfterTest(t)
	s := StartTestServer(t)
	defer s.Stop()
	testCases := []struct {
		method, key   string
		certsStatus   int // Status code for https with client certs.
		noCertsStatus int // Status code for https without client certs.
	}{
		// /ui/: basic file server: no auth.
		{"GET", "/index.html", http.StatusOK, http.StatusOK},

		// /_admin/: server.adminServer: no auth.
		{"GET", healthPath, http.StatusOK, http.StatusOK},

		// /debug/: server.adminServer: no auth.
		{"GET", debugEndpoint + "vars", http.StatusOK, http.StatusOK},

		// /_status/nodes: server.statusServer: no auth.
		{"GET", statusNodeKeyPrefix, http.StatusOK, http.StatusOK},

		// /kv/db/: kv.DBServer. These are proto reqs, but we can at least get past auth.
		{"GET", kv.DBPrefix + "Get", http.StatusBadRequest, http.StatusUnauthorized},

		// /ts/: ts.Server.
		{"GET", ts.URLPrefix, http.StatusNotFound, http.StatusUnauthorized},
	}

	// HTTPS with client certs.
	certsContext := testutils.NewTestBaseContext()
	client, err := certsContext.GetHTTPClient()
	if err != nil {
		t.Fatalf("error initializing http client: %s", err)
	}
	for tcNum, tc := range testCases {
		resp, err := doHTTPReq(t, client, tc.method,
			fmt.Sprintf("%s://%s%s", certsContext.RequestScheme(), s.ServingAddr(), tc.key))
		if err != nil {
			t.Fatalf("[%d]: error issuing request: %s", tcNum, err)
		}

		defer resp.Body.Close()
		if resp.StatusCode != tc.certsStatus {
			t.Errorf("[%d]: expected status code %d, got %d", tcNum, tc.certsStatus, resp.StatusCode)
		}
	}

	// HTTPS without client certs.
	noCertsContext := testutils.NewTestBaseContext()
	noCertsContext.Certs = ""
	client, err = noCertsContext.GetHTTPClient()
	if err != nil {
		t.Fatalf("error initializing http client: %s", err)
	}
	for tcNum, tc := range testCases {
		resp, err := doHTTPReq(t, client, tc.method,
			fmt.Sprintf("%s://%s%s", noCertsContext.RequestScheme(), s.ServingAddr(), tc.key))
		if err != nil {
			t.Fatalf("[%d]: error issuing request: %s", tcNum, err)
		}

		defer resp.Body.Close()
		if resp.StatusCode != tc.noCertsStatus {
			t.Errorf("[%d]: expected status code %d, got %d", tcNum, tc.noCertsStatus, resp.StatusCode)
		}
	}

	// Plain http.
	insecureContext := testutils.NewTestBaseContext()
	insecureContext.Insecure = true
	client, err = insecureContext.GetHTTPClient()
	if err != nil {
		t.Fatalf("error initializing http client: %s", err)
	}
	for tcNum, tc := range testCases {
		resp, err := doHTTPReq(t, client, tc.method,
			fmt.Sprintf("%s://%s%s", insecureContext.RequestScheme(), s.ServingAddr(), tc.key))
		// We're talking http to a https server. We don't even make it to a response.
		if err == nil {
			defer resp.Body.Close()
			t.Errorf("[%d]: unexpected success", tcNum)
		}
	}
}
Ejemplo n.º 10
0
// TestHTTPSenderRetryResponseCodes verifies that send is retried
// on some HTTP response codes but not on others.
func TestHTTPSenderRetryResponseCodes(t *testing.T) {
	defer leaktest.AfterTest(t)
	retryOptions := defaultRetryOptions
	retryOptions.Backoff = 1 * time.Millisecond

	testCases := []struct {
		code  int
		retry bool
	}{
		{http.StatusServiceUnavailable, true},
		{http.StatusGatewayTimeout, true},
		{StatusTooManyRequests, true},
		{http.StatusRequestTimeout, false},
		{http.StatusBadRequest, false},
		{http.StatusNotFound, false},
		{http.StatusUnauthorized, false},
		{http.StatusForbidden, false},
		{http.StatusMethodNotAllowed, false},
		{http.StatusNotAcceptable, false},
		{http.StatusInternalServerError, false},
		{http.StatusNotImplemented, false},
	}
	for i, test := range testCases {
		count := 0
		server, addr := startTestHTTPServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			count++
			if count == 1 {
				http.Error(w, "manufactured error", test.code)
				return
			}
			if !test.retry {
				t.Errorf("%d: didn't expect retry on code %d", i, test.code)
			}
			body, contentType, err := util.MarshalResponse(r, testPutResp, util.AllEncodings)
			if err != nil {
				t.Errorf("%d: failed to marshal response: %s", i, err)
			}
			w.Header().Set(util.ContentTypeHeader, contentType)
			w.Write(body)
		}))

		sender, err := newHTTPSender(addr, testutils.NewTestBaseContext(), retryOptions)
		if err != nil {
			t.Fatal(err)
		}
		reply := &proto.PutResponse{}
		sender.Send(context.Background(), proto.Call{Args: testPutReq, Reply: reply})
		if test.retry {
			if count != 2 {
				t.Errorf("%d: expected retry", i)
			}
			if reply.GoError() != nil {
				t.Errorf("%d: expected success after retry; got %s", i, reply.GoError())
			}
		} else {
			if count != 1 {
				t.Errorf("%d; expected no retry; got %d", i, count)
			}
			if reply.GoError() == nil {
				t.Errorf("%d: expected error", i)
			}
		}
		server.Close()
	}
}