Example #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 = stop.NewStopper()
	rpcContext := rpc.NewContext(testutils.NewRootTestBaseContext(), 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, nil, 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)
	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(nil); 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)
	}
}
func TestSend(t *testing.T) {
	defer leaktest.AfterTest(t)
	s := server.StartTestServer(t)
	defer s.Stop()
	sender, err := newHTTPSender(s.ServingAddr(), testutils.NewRootTestBaseContext(), defaultRetryOptions)
	if err != nil {
		log.Fatalf("Couldn't create HTTPSender for server:(%s)", s.ServingAddr())
	}
	testCases := []struct {
		req   string
		reply string
	}{
		{"ping", "ping"},
		{"default", "default"},
	}
	for _, test := range testCases {
		request := &sqlwire.Request{Sql: test.req}
		call := sqlwire.Call{Args: request, Reply: &sqlwire.Response{}}
		sender.Send(context.TODO(), call)
		reply := *call.Reply.Results[0].Rows[0].Values[0].StringVal
		if reply != test.reply {
			log.Fatalf("Server sent back reply: %s", reply)
		}
	}
}
Example #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.InitialBackoff = 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.NewRootTestBaseContext(), 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()
	}
}
Example #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.NewRootTestBaseContext(), 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)
	}
}
Example #5
0
// Example_zone shows how to use the admin client to
// get/set/list/delete zone configs.
func Example_zone() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.Zone)

	const yamlConfig = `
replicas:
  - attrs: [dc1, ssd]
  - attrs: [dc2, ssd]
  - attrs: [dc3, ssd]
range_min_bytes: 1048576
range_max_bytes: 67108864
`
	const jsonConfig = `{
	   "replica_attrs": [
	     {
	       "attrs": [
	         "dc1",
	         "ssd"
	       ]
	     },
	     {
	       "attrs": [
	         "dc2",
	         "ssd"
	       ]
	     },
	     {
	       "attrs": [
	         "dc3",
	         "ssd"
	       ]
	     }
	   ],
	   "range_min_bytes": 1048576,
	   "range_max_bytes": 67108864
	 }`

	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.KeyMin, yamlConfig, false},
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON zone config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML zone config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Zone prefixes: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Zone prefixes: %q\n", keys)

	// Output:
	// Set YAML zone config for ""
	// Set YAML zone config for "db1"
	// Set JSON zone config for "db 2"
	// Set JSON zone config for "\xfe"
	// JSON config for "db1":
	// {
	//   "replica_attrs": [
	//     {
	//       "attrs": [
	//         "dc1",
	//         "ssd"
	//       ]
	//     },
	//     {
	//       "attrs": [
	//         "dc2",
	//         "ssd"
	//       ]
	//     },
	//     {
	//       "attrs": [
	//         "dc3",
	//         "ssd"
	//       ]
	//     }
	//   ],
	//   "range_min_bytes": 1048576,
	//   "range_max_bytes": 67108864
	// }
	// YAML config for "db 2":
	// replicas:
	// - attrs: [dc1, ssd]
	// - attrs: [dc2, ssd]
	// - attrs: [dc3, ssd]
	// range_min_bytes: 1048576
	// range_max_bytes: 67108864
	//
	// Zone prefixes: ["" "db 2" "db1" "\xfe"]
	// Zone prefixes: ["" "db1" "\xfe"]
}
Example #6
0
// Example_accounting shows how to use the admin client to
// get/set/list/delete accounting configs.
func Example_accounting() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.Accounting)

	const yamlConfig = `cluster_id: test`
	const jsonConfig = `{
  "cluster_id": "test"
}`
	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.KeyMin, yamlConfig, false},
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON accounting config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML accounting config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Accounting prefixes: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Accounting prefixes: %q\n", keys)

	// Output:
	// Set YAML accounting config for ""
	// Set YAML accounting config for "db1"
	// Set JSON accounting config for "db 2"
	// Set JSON accounting config for "\xfe"
	// JSON config for "db1":
	// {
	//   "cluster_id": "test"
	// }
	// YAML config for "db 2":
	// cluster_id: test
	//
	// Accounting prefixes: ["" "db 2" "db1" "\xfe"]
	// Accounting prefixes: ["" "db1" "\xfe"]
}
Example #7
0
// Example_user shows how to use the admin client to
// get/set/list/delete user configs.
func Example_user() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.User)

	const yamlConfig = `hashed_password:
 - 10
 - 20`
	const jsonConfig = `{
	   "hashed_password": "******"
	 }`
	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Overwriting the default entry fails.
	err := client.SetYAML("", yamlConfig)
	if err == nil {
		log.Fatal("expected error")
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON user config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML user config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Users: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Users: %q\n", keys)

	// Output:
	// Set YAML user config for "db1"
	// Set JSON user config for "db 2"
	// Set JSON user config for "\xfe"
	// JSON config for "db1":
	// {
	//   "hashed_password": "******"
	// }
	// YAML config for "db 2":
	// hashed_password:
	// - 10
	// - 20
	//
	// Users: ["" "db 2" "db1" "\xfe"]
	// Users: ["" "db1" "\xfe"]
}
Example #8
0
// Example_permission shows how to use the admin client to
// get/set/list/delete permission configs.
func Example_permission() {
	s := server.StartTestServer(nil)
	defer s.Stop()

	context := testutils.NewRootTestBaseContext()
	client := client.NewAdminClient(context, s.ServingAddr(), client.Permission)

	// The test server creates a permission config entry for 'server.TestUser'.
	// Delete it first so it does not interfere with our configs.
	err := client.Delete(server.TestUser)
	if err != nil {
		log.Fatal(err)
	}

	const yamlConfig = `
read: [readonly, readwrite]
write: [readwrite, writeonly]
`
	const jsonConfig = `{
	   "read": [
	     "readonly",
	     "readwrite"
	   ],
	   "write": [
	     "readwrite",
	     "writeonly"
	   ]
	 }`

	testData := []struct {
		prefix proto.Key
		cfg    string
		isJSON bool
	}{
		{proto.KeyMin, yamlConfig, false},
		{proto.Key("db1"), yamlConfig, false},
		{proto.Key("db 2"), jsonConfig, true},
		{proto.Key("\xfe"), jsonConfig, true},
	}

	// Write configs.
	for _, test := range testData {
		prefix := string(test.prefix)
		if test.isJSON {
			fmt.Printf("Set JSON permission config for %q\n", prefix)
			if err := client.SetJSON(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		} else {
			fmt.Printf("Set YAML permission config for %q\n", prefix)
			if err := client.SetYAML(prefix, test.cfg); err != nil {
				log.Fatal(err)
			}
		}
	}

	// Get configs in various format.
	body, err := client.GetJSON("db1")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("JSON config for \"db1\":\n%s\n", body)

	body, err = client.GetYAML("db 2")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("YAML config for \"db 2\":\n%s\n", body)

	// List keys.
	keys, err := client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Permission prefixes: %q\n", keys)

	// Remove keys: the default one cannot be removed.
	err = client.Delete("")
	if err == nil {
		log.Fatal("expected error")
	}
	err = client.Delete("db 2")
	if err != nil {
		log.Fatal(err)
	}

	// List keys again.
	keys, err = client.List()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Permission prefixes: %q\n", keys)

	// Output:
	// Set YAML permission config for ""
	// Set YAML permission config for "db1"
	// Set JSON permission config for "db 2"
	// Set JSON permission config for "\xfe"
	// JSON config for "db1":
	// {
	//   "read": [
	//     "readonly",
	//     "readwrite"
	//   ],
	//   "write": [
	//     "readwrite",
	//     "writeonly"
	//   ]
	// }
	// YAML config for "db 2":
	// read:
	// - readonly
	// - readwrite
	// write:
	// - readwrite
	// - writeonly
	//
	// Permission prefixes: ["" "db 2" "db1" "\xfe"]
	// Permission prefixes: ["" "db1" "\xfe"]
}
Example #9
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/sql/sqlwire"
	"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"
	gogoproto "github.com/gogo/protobuf/proto"
)

var testContext = NewTestContext()
var rootTestBaseContext = testutils.NewRootTestBaseContext()
var nodeTestBaseContext = testutils.NewNodeTestBaseContext()

// TestInitEngine tests whether the data directory string is parsed correctly.
func TestInitEngine(t *testing.T) {
	defer leaktest.AfterTest(t)
	tmp := util.CreateNTempDirs(t, "_server_test", 5)
	defer util.CleanupDirs(tmp)

	testCases := []struct {
		key       string           // data directory
		expAttrs  proto.Attributes // attributes for engine
		wantError bool             // do we expect an error from this key?
		isMem     bool             // is the engine in-memory?
	}{
		{"mem=1000", proto.Attributes{Attrs: []string{"mem"}}, false, true},
Example #10
0
// NewRootTestContext returns a rpc.Context for testing.
// It is meant to be used by clients.
func NewRootTestContext(clock *hlc.Clock, stopper *stop.Stopper) *Context {
	if clock == nil {
		clock = hlc.NewClock(hlc.UnixNano)
	}
	return NewContext(testutils.NewRootTestBaseContext(), clock, stopper)
}
Example #11
0
// Verify client certificate enforcement.
func TestSSLEnforcement(t *testing.T) {
	defer leaktest.AfterTest(t)
	s := StartTestServer(t)
	defer s.Stop()

	// HTTPS with client certs.
	certsContext := testutils.NewRootTestBaseContext()
	// HTTPS without client certs.
	noCertsContext := testutils.NewRootTestBaseContext()
	noCertsContext.Certs = ""
	// Plain http.
	insecureContext := testutils.NewRootTestBaseContext()
	insecureContext.Insecure = true

	testCases := []struct {
		method, key string
		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", certsContext, true, http.StatusOK},
		{"GET", "/index.html", noCertsContext, true, http.StatusOK},
		{"GET", "/index.html", insecureContext, false, -1},

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

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

		// /_status/nodes: server.statusServer: no auth.
		{"GET", statusNodeKeyPrefix, certsContext, true, http.StatusOK},
		{"GET", statusNodeKeyPrefix, noCertsContext, true, http.StatusOK},
		{"GET", statusNodeKeyPrefix, insecureContext, false, -1},

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

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

		// /sql/: sql.Server. These are proto reqs, but we can at least get past auth.
		{"GET", driver.Endpoint + "Get", certsContext, true, http.StatusNotFound},
		{"GET", driver.Endpoint + "Get", noCertsContext, true, http.StatusUnauthorized},
		{"GET", driver.Endpoint + "Get", 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.RequestScheme(), s.ServingAddr(), tc.key))
		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)
		}
	}
}
Example #12
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.InitialBackoff = 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.NewRootTestBaseContext(), 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()
	}
}
Example #13
0
// This is a fairly high-level test of CA and node certificates.
// We construct SSL server and clients and use the generated certs.
func TestUseCerts(t *testing.T) {
	defer leaktest.AfterTest(t)
	// Do not mock cert access for this test.
	security.ResetReadFileFn()
	defer ResetTest()
	certsDir := util.CreateTempDir(t, "certs_test")
	defer util.CleanupDir(certsDir)

	err := security.RunCreateCACert(certsDir, 512)
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}

	err = security.RunCreateNodeCert(certsDir, 512, []string{"127.0.0.1"})
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}

	err = security.RunCreateClientCert(certsDir, 512, security.RootUser)
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}

	// Load TLS Configs. This is what TestServer and HTTPClient do internally.
	_, err = security.LoadServerTLSConfig(certsDir, "node")
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}
	_, err = security.LoadClientTLSConfig(certsDir, security.NodeUser)
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}

	// Start a test server and override certs.
	// We use a real context since we want generated certs.
	testCtx := server.NewContext()
	testCtx.Certs = certsDir
	testCtx.User = security.NodeUser
	testCtx.Addr = "127.0.0.1:0"
	s := &server.TestServer{Ctx: testCtx}
	if err := s.Start(); err != nil {
		t.Fatal(err)
	}
	defer s.Stop()

	// Insecure mode.
	clientContext := testutils.NewRootTestBaseContext()
	clientContext.Insecure = true
	httpClient, err := clientContext.GetHTTPClient()
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("GET", "https://"+s.ServingAddr()+"/_admin/health", nil)
	if err != nil {
		t.Fatalf("could not create request: %v", err)
	}
	resp, err := httpClient.Do(req)
	if err == nil {
		resp.Body.Close()
		t.Fatalf("Expected SSL error, got success")
	}

	// Secure mode but no Certs directory: permissive config.
	clientContext = testutils.NewRootTestBaseContext()
	clientContext.Certs = ""
	httpClient, err = clientContext.GetHTTPClient()
	if err != nil {
		t.Fatal(err)
	}
	// Endpoint that does not enforce client auth (see: server/authentication_test.go)
	req, err = http.NewRequest("GET", "https://"+s.ServingAddr()+"/_admin/health", nil)
	if err != nil {
		t.Fatalf("could not create request: %v", err)
	}
	resp, err = httpClient.Do(req)
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}
	resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Expected OK, got: %d", resp.StatusCode)
	}

	// Endpoint that enforces client auth (see: server/authentication_test.go)
	req, err = http.NewRequest("GET", "https://"+s.ServingAddr()+kv.DBPrefix+"Get", nil)
	if err != nil {
		t.Fatalf("could not create request: %v", err)
	}
	resp, err = httpClient.Do(req)
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}
	resp.Body.Close()
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatalf("Expected status code %d, got: %d", http.StatusUnauthorized, resp.StatusCode)
	}

	// New client. With certs this time.
	clientContext = testutils.NewRootTestBaseContext()
	clientContext.Certs = certsDir
	httpClient, err = clientContext.GetHTTPClient()
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}
	req, err = http.NewRequest("GET", "https://"+s.ServingAddr()+"/_admin/health", nil)
	if err != nil {
		t.Fatalf("could not create request: %v", err)
	}
	resp, err = httpClient.Do(req)
	if err != nil {
		t.Fatalf("Expected success, got %v", err)
	}
	resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Expected OK, got: %d", resp.StatusCode)
	}
}