diff --git a/build-index/tagclient/client.go b/build-index/tagclient/client.go index c17f2b19a..92765b553 100644 --- a/build-index/tagclient/client.go +++ b/build-index/tagclient/client.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -38,6 +38,7 @@ var ( // Client wraps tagserver endpoints. type Client interface { + CheckReadiness() error Put(tag string, d core.Digest) error PutAndReplicate(tag string, d core.Digest) error Get(tag string) (core.Digest, error) @@ -70,6 +71,14 @@ func NewSingleClient(addr string, config *tls.Config) Client { return &singleClient{addr, config} } +func (c *singleClient) CheckReadiness() error { + _, err := httputil.Get( + fmt.Sprintf("http://%s/readiness", c.addr), + httputil.SendTimeout(5*time.Second), + httputil.SendTLS(c.tls)) + return err +} + func (c *singleClient) Put(tag string, d core.Digest) error { _, err := httputil.Put( fmt.Sprintf("http://%s/tags/%s/digest/%s", c.addr, url.PathEscape(tag), d.String()), @@ -311,6 +320,33 @@ func (cc *clusterClient) do(request func(c Client) error) error { return err } +// doOnce tries the request on only one randomly chosen client without any retries if it fails. +func (cc *clusterClient) doOnce(request func(c Client) error) error { + addrs := cc.hosts.Resolve().Sample(1) + if len(addrs) == 0 { + return errors.New("cluster client: no hosts could be resolved") + } + // read the only sampled addr + var addr string + for addr = range addrs { + } + err := request(NewSingleClient(addr, cc.tls)) + if httputil.IsNetworkError(err) { + cc.hosts.Failed(addr) + } + return err +} + +func (cc *clusterClient) CheckReadiness() error { + return cc.doOnce(func(c Client) error { + err := c.CheckReadiness() + if err != nil { + return fmt.Errorf("build index not ready: %v", err) + } + return nil + }) +} + func (cc *clusterClient) Put(tag string, d core.Digest) error { return cc.do(func(c Client) error { return c.Put(tag, d) }) } diff --git a/build-index/tagserver/server.go b/build-index/tagserver/server.go index 1dcafcf3e..4dbf04d7d 100644 --- a/build-index/tagserver/server.go +++ b/build-index/tagserver/server.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -108,6 +108,7 @@ func (s *Server) Handler() http.Handler { r.Use(middleware.LatencyTimer(s.stats)) r.Get("/health", handler.Wrap(s.healthHandler)) + r.Get("/readiness", handler.Wrap(s.readinessCheckHandler)) r.Put("/tags/{tag}/digest/{digest}", handler.Wrap(s.putTagHandler)) r.Head("/tags/{tag}", handler.Wrap(s.hasTagHandler)) @@ -145,6 +146,15 @@ func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) error { return nil } +func (s *Server) readinessCheckHandler(w http.ResponseWriter, r *http.Request) error { + err := s.backends.CheckReadiness() + if err != nil { + return handler.Errorf("not ready to serve traffic: %s", err).Status(http.StatusServiceUnavailable) + } + fmt.Fprintln(w, "OK") + return nil +} + func (s *Server) putTagHandler(w http.ResponseWriter, r *http.Request) error { tag, err := httputil.ParseParam(r, "tag") if err != nil { diff --git a/build-index/tagserver/server_test.go b/build-index/tagserver/server_test.go index bce5ed9c5..64f7485a1 100644 --- a/build-index/tagserver/server_test.go +++ b/build-index/tagserver/server_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -14,10 +14,12 @@ package tagserver import ( + "errors" "fmt" "io/ioutil" "net/http" "net/url" + "regexp" "strconv" "testing" "time" @@ -149,6 +151,53 @@ func TestHealth(t *testing.T) { require.Equal("OK\n", string(b)) } +func TestCheckReadiness(t *testing.T) { + for _, tc := range []struct { + name string + mockStatErr error + expectedErrMsgPattern string + }{ + { + name: "success", + mockStatErr: nil, + expectedErrMsgPattern: "", + }, + { + name: "failure, 503 (since Stat fails)", + mockStatErr: errors.New("test error"), + expectedErrMsgPattern: fmt.Sprintf(`build index not ready: GET http://127\.0\.0\.1:\d+/readiness 503: not ready to serve traffic: backend for namespace 'foo-bar/\*' not ready: test error`), + }, + } { + t.Run(tc.name, func(t *testing.T) { + require := require.New(t) + + mocks, cleanup := newServerMocks(t) + defer cleanup() + + addr, stop := testutil.StartServer(mocks.handler()) + defer stop() + + client := newClusterClient(addr) + backendClient := mockbackend.NewMockClient(mocks.ctrl) + require.NoError(mocks.backends.Register("foo-bar/*", backendClient, true)) + + mockStat := &core.BlobInfo{} + if tc.mockStatErr != nil { + mockStat = nil + } + backendClient.EXPECT().Stat(backend.ReadinessCheckNamespace, backend.ReadinessCheckName).Return(mockStat, tc.mockStatErr) + + err := client.CheckReadiness() + if tc.expectedErrMsgPattern == "" { + require.Nil(err) + } else { + r, _ := regexp.Compile(tc.expectedErrMsgPattern) + require.True(r.MatchString(err.Error())) + } + }) + } +} + func TestPut(t *testing.T) { require := require.New(t) diff --git a/core/digest.go b/core/digest.go index 18ef9d6be..92851207f 100644 --- a/core/digest.go +++ b/core/digest.go @@ -23,11 +23,6 @@ import ( "strings" ) -const ( - // DigestEmptyTar is the sha256 digest of an empty tar file. - DigestEmptyTar = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" -) - // DigestList is a list of digests. type DigestList []Digest diff --git a/lib/backend/constants.go b/lib/backend/constants.go index 12db5dfb4..c5d96e26b 100644 --- a/lib/backend/constants.go +++ b/lib/backend/constants.go @@ -30,4 +30,5 @@ const ( var ( ReadinessCheckNamespace string = core.NamespaceFixture() ReadinessCheckName string = core.DigestFixture().Hex() + ReadinessCheckDigest, _ = core.NewSHA256DigestFromHex(ReadinessCheckName) ) diff --git a/lib/backend/manager.go b/lib/backend/manager.go index 2606024d8..35069ab65 100644 --- a/lib/backend/manager.go +++ b/lib/backend/manager.go @@ -143,7 +143,7 @@ func (m *Manager) GetClient(namespace string) (Client, error) { return nil, ErrNamespaceNotFound } -// IsReady returns whether the backends are ready (reachable). +// CheckReadiness returns whether the backends are ready (available). // A backend must be explicitly configured as required for readiness to be checked. func (m *Manager) CheckReadiness() error { for _, b := range m.backends { diff --git a/lib/backend/manager_test.go b/lib/backend/manager_test.go index c27e303c2..960e9a039 100644 --- a/lib/backend/manager_test.go +++ b/lib/backend/manager_test.go @@ -19,7 +19,6 @@ import ( "github.com/uber-go/tally" "github.com/uber/kraken/core" - "github.com/uber/kraken/lib/backend" . "github.com/uber/kraken/lib/backend" "github.com/uber/kraken/lib/backend/backenderrors" "github.com/uber/kraken/lib/backend/namepath" @@ -222,8 +221,8 @@ func TestManagerCheckReadiness(t *testing.T) { mockStat2 = nil } - c1.EXPECT().Stat(backend.ReadinessCheckNamespace, backend.ReadinessCheckName).Return(mockStat1, tc.mockStat1Err).AnyTimes() - c2.EXPECT().Stat(backend.ReadinessCheckNamespace, backend.ReadinessCheckName).Return(mockStat2, tc.mockStat2Err).AnyTimes() + c1.EXPECT().Stat(ReadinessCheckNamespace, ReadinessCheckName).Return(mockStat1, tc.mockStat1Err).AnyTimes() + c2.EXPECT().Stat(ReadinessCheckNamespace, ReadinessCheckName).Return(mockStat2, tc.mockStat2Err).AnyTimes() require.NoError(m.Register(n1, c1, tc.mustReady1)) require.NoError(m.Register(n2, c2, tc.mustReady2)) diff --git a/mocks/build-index/tagclient/client.go b/mocks/build-index/tagclient/client.go index 4a878b7a2..7945e644e 100644 --- a/mocks/build-index/tagclient/client.go +++ b/mocks/build-index/tagclient/client.go @@ -1,160 +1,181 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/uber/kraken/build-index/tagclient (interfaces: Client) +// +// Generated by this command: +// +// mockgen -package mocktagclient . Client +// // Package mocktagclient is a generated GoMock package. package mocktagclient import ( - gomock "github.com/golang/mock/gomock" + reflect "reflect" + time "time" + tagclient "github.com/uber/kraken/build-index/tagclient" tagmodels "github.com/uber/kraken/build-index/tagmodels" core "github.com/uber/kraken/core" - reflect "reflect" - time "time" + gomock "github.com/golang/mock/gomock" ) -// MockClient is a mock of Client interface +// MockClient is a mock of Client interface. type MockClient struct { ctrl *gomock.Controller recorder *MockClientMockRecorder + isgomock struct{} } -// MockClientMockRecorder is the mock recorder for MockClient +// MockClientMockRecorder is the mock recorder for MockClient. type MockClientMockRecorder struct { mock *MockClient } -// NewMockClient creates a new mock instance +// NewMockClient creates a new mock instance. func NewMockClient(ctrl *gomock.Controller) *MockClient { mock := &MockClient{ctrl: ctrl} mock.recorder = &MockClientMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } -// DuplicatePut mocks base method -func (m *MockClient) DuplicatePut(arg0 string, arg1 core.Digest, arg2 time.Duration) error { +// CheckReadiness mocks base method. +func (m *MockClient) CheckReadiness() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckReadiness") + ret0, _ := ret[0].(error) + return ret0 +} + +// CheckReadiness indicates an expected call of CheckReadiness. +func (mr *MockClientMockRecorder) CheckReadiness() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadiness", reflect.TypeOf((*MockClient)(nil).CheckReadiness)) +} + +// DuplicatePut mocks base method. +func (m *MockClient) DuplicatePut(tag string, d core.Digest, delay time.Duration) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DuplicatePut", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "DuplicatePut", tag, d, delay) ret0, _ := ret[0].(error) return ret0 } -// DuplicatePut indicates an expected call of DuplicatePut -func (mr *MockClientMockRecorder) DuplicatePut(arg0, arg1, arg2 interface{}) *gomock.Call { +// DuplicatePut indicates an expected call of DuplicatePut. +func (mr *MockClientMockRecorder) DuplicatePut(tag, d, delay interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DuplicatePut", reflect.TypeOf((*MockClient)(nil).DuplicatePut), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DuplicatePut", reflect.TypeOf((*MockClient)(nil).DuplicatePut), tag, d, delay) } -// DuplicateReplicate mocks base method -func (m *MockClient) DuplicateReplicate(arg0 string, arg1 core.Digest, arg2 core.DigestList, arg3 time.Duration) error { +// DuplicateReplicate mocks base method. +func (m *MockClient) DuplicateReplicate(tag string, d core.Digest, dependencies core.DigestList, delay time.Duration) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DuplicateReplicate", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "DuplicateReplicate", tag, d, dependencies, delay) ret0, _ := ret[0].(error) return ret0 } -// DuplicateReplicate indicates an expected call of DuplicateReplicate -func (mr *MockClientMockRecorder) DuplicateReplicate(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +// DuplicateReplicate indicates an expected call of DuplicateReplicate. +func (mr *MockClientMockRecorder) DuplicateReplicate(tag, d, dependencies, delay interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DuplicateReplicate", reflect.TypeOf((*MockClient)(nil).DuplicateReplicate), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DuplicateReplicate", reflect.TypeOf((*MockClient)(nil).DuplicateReplicate), tag, d, dependencies, delay) } -// Get mocks base method -func (m *MockClient) Get(arg0 string) (core.Digest, error) { +// Get mocks base method. +func (m *MockClient) Get(tag string) (core.Digest, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0) + ret := m.ctrl.Call(m, "Get", tag) ret0, _ := ret[0].(core.Digest) ret1, _ := ret[1].(error) return ret0, ret1 } -// Get indicates an expected call of Get -func (mr *MockClientMockRecorder) Get(arg0 interface{}) *gomock.Call { +// Get indicates an expected call of Get. +func (mr *MockClientMockRecorder) Get(tag interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockClient)(nil).Get), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockClient)(nil).Get), tag) } -// Has mocks base method -func (m *MockClient) Has(arg0 string) (bool, error) { +// Has mocks base method. +func (m *MockClient) Has(tag string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Has", arg0) + ret := m.ctrl.Call(m, "Has", tag) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } -// Has indicates an expected call of Has -func (mr *MockClientMockRecorder) Has(arg0 interface{}) *gomock.Call { +// Has indicates an expected call of Has. +func (mr *MockClientMockRecorder) Has(tag interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockClient)(nil).Has), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockClient)(nil).Has), tag) } -// List mocks base method -func (m *MockClient) List(arg0 string) ([]string, error) { +// List mocks base method. +func (m *MockClient) List(prefix string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "List", arg0) + ret := m.ctrl.Call(m, "List", prefix) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } -// List indicates an expected call of List -func (mr *MockClientMockRecorder) List(arg0 interface{}) *gomock.Call { +// List indicates an expected call of List. +func (mr *MockClientMockRecorder) List(prefix interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClient)(nil).List), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClient)(nil).List), prefix) } -// ListRepository mocks base method -func (m *MockClient) ListRepository(arg0 string) ([]string, error) { +// ListRepository mocks base method. +func (m *MockClient) ListRepository(repo string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListRepository", arg0) + ret := m.ctrl.Call(m, "ListRepository", repo) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } -// ListRepository indicates an expected call of ListRepository -func (mr *MockClientMockRecorder) ListRepository(arg0 interface{}) *gomock.Call { +// ListRepository indicates an expected call of ListRepository. +func (mr *MockClientMockRecorder) ListRepository(repo interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRepository", reflect.TypeOf((*MockClient)(nil).ListRepository), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRepository", reflect.TypeOf((*MockClient)(nil).ListRepository), repo) } -// ListRepositoryWithPagination mocks base method -func (m *MockClient) ListRepositoryWithPagination(arg0 string, arg1 tagclient.ListFilter) (tagmodels.ListResponse, error) { +// ListRepositoryWithPagination mocks base method. +func (m *MockClient) ListRepositoryWithPagination(repo string, filter tagclient.ListFilter) (tagmodels.ListResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListRepositoryWithPagination", arg0, arg1) + ret := m.ctrl.Call(m, "ListRepositoryWithPagination", repo, filter) ret0, _ := ret[0].(tagmodels.ListResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// ListRepositoryWithPagination indicates an expected call of ListRepositoryWithPagination -func (mr *MockClientMockRecorder) ListRepositoryWithPagination(arg0, arg1 interface{}) *gomock.Call { +// ListRepositoryWithPagination indicates an expected call of ListRepositoryWithPagination. +func (mr *MockClientMockRecorder) ListRepositoryWithPagination(repo, filter interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRepositoryWithPagination", reflect.TypeOf((*MockClient)(nil).ListRepositoryWithPagination), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRepositoryWithPagination", reflect.TypeOf((*MockClient)(nil).ListRepositoryWithPagination), repo, filter) } -// ListWithPagination mocks base method -func (m *MockClient) ListWithPagination(arg0 string, arg1 tagclient.ListFilter) (tagmodels.ListResponse, error) { +// ListWithPagination mocks base method. +func (m *MockClient) ListWithPagination(prefix string, filter tagclient.ListFilter) (tagmodels.ListResponse, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListWithPagination", arg0, arg1) + ret := m.ctrl.Call(m, "ListWithPagination", prefix, filter) ret0, _ := ret[0].(tagmodels.ListResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// ListWithPagination indicates an expected call of ListWithPagination -func (mr *MockClientMockRecorder) ListWithPagination(arg0, arg1 interface{}) *gomock.Call { +// ListWithPagination indicates an expected call of ListWithPagination. +func (mr *MockClientMockRecorder) ListWithPagination(prefix, filter interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWithPagination", reflect.TypeOf((*MockClient)(nil).ListWithPagination), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWithPagination", reflect.TypeOf((*MockClient)(nil).ListWithPagination), prefix, filter) } -// Origin mocks base method +// Origin mocks base method. func (m *MockClient) Origin() (string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Origin") @@ -163,50 +184,50 @@ func (m *MockClient) Origin() (string, error) { return ret0, ret1 } -// Origin indicates an expected call of Origin +// Origin indicates an expected call of Origin. func (mr *MockClientMockRecorder) Origin() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Origin", reflect.TypeOf((*MockClient)(nil).Origin)) } -// Put mocks base method -func (m *MockClient) Put(arg0 string, arg1 core.Digest) error { +// Put mocks base method. +func (m *MockClient) Put(tag string, d core.Digest) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Put", arg0, arg1) + ret := m.ctrl.Call(m, "Put", tag, d) ret0, _ := ret[0].(error) return ret0 } -// Put indicates an expected call of Put -func (mr *MockClientMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { +// Put indicates an expected call of Put. +func (mr *MockClientMockRecorder) Put(tag, d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockClient)(nil).Put), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockClient)(nil).Put), tag, d) } -// PutAndReplicate mocks base method -func (m *MockClient) PutAndReplicate(arg0 string, arg1 core.Digest) error { +// PutAndReplicate mocks base method. +func (m *MockClient) PutAndReplicate(tag string, d core.Digest) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PutAndReplicate", arg0, arg1) + ret := m.ctrl.Call(m, "PutAndReplicate", tag, d) ret0, _ := ret[0].(error) return ret0 } -// PutAndReplicate indicates an expected call of PutAndReplicate -func (mr *MockClientMockRecorder) PutAndReplicate(arg0, arg1 interface{}) *gomock.Call { +// PutAndReplicate indicates an expected call of PutAndReplicate. +func (mr *MockClientMockRecorder) PutAndReplicate(tag, d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutAndReplicate", reflect.TypeOf((*MockClient)(nil).PutAndReplicate), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutAndReplicate", reflect.TypeOf((*MockClient)(nil).PutAndReplicate), tag, d) } -// Replicate mocks base method -func (m *MockClient) Replicate(arg0 string) error { +// Replicate mocks base method. +func (m *MockClient) Replicate(tag string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Replicate", arg0) + ret := m.ctrl.Call(m, "Replicate", tag) ret0, _ := ret[0].(error) return ret0 } -// Replicate indicates an expected call of Replicate -func (mr *MockClientMockRecorder) Replicate(arg0 interface{}) *gomock.Call { +// Replicate indicates an expected call of Replicate. +func (mr *MockClientMockRecorder) Replicate(tag interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Replicate", reflect.TypeOf((*MockClient)(nil).Replicate), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Replicate", reflect.TypeOf((*MockClient)(nil).Replicate), tag) } diff --git a/mocks/origin/blobclient/client.go b/mocks/origin/blobclient/client.go index 7c6a182a4..1e11e8f97 100644 --- a/mocks/origin/blobclient/client.go +++ b/mocks/origin/blobclient/client.go @@ -1,41 +1,47 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/uber/kraken/origin/blobclient (interfaces: Client) +// +// Generated by this command: +// +// mockgen -package mockblobclient . Client +// // Package mockblobclient is a generated GoMock package. package mockblobclient import ( gomock "github.com/golang/mock/gomock" - core "github.com/uber/kraken/core" io "io" reflect "reflect" time "time" + core "github.com/uber/kraken/core" ) -// MockClient is a mock of Client interface +// MockClient is a mock of Client interface. type MockClient struct { ctrl *gomock.Controller recorder *MockClientMockRecorder + isgomock struct{} } -// MockClientMockRecorder is the mock recorder for MockClient +// MockClientMockRecorder is the mock recorder for MockClient. type MockClientMockRecorder struct { mock *MockClient } -// NewMockClient creates a new mock instance +// NewMockClient creates a new mock instance. func NewMockClient(ctrl *gomock.Controller) *MockClient { mock := &MockClient{ctrl: ctrl} mock.recorder = &MockClientMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } -// Addr mocks base method +// Addr mocks base method. func (m *MockClient) Addr() string { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Addr") @@ -43,84 +49,98 @@ func (m *MockClient) Addr() string { return ret0 } -// Addr indicates an expected call of Addr +// Addr indicates an expected call of Addr. func (mr *MockClientMockRecorder) Addr() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Addr", reflect.TypeOf((*MockClient)(nil).Addr)) } -// DeleteBlob mocks base method -func (m *MockClient) DeleteBlob(arg0 core.Digest) error { +// CheckReadiness mocks base method. +func (m *MockClient) CheckReadiness() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckReadiness") + ret0, _ := ret[0].(error) + return ret0 +} + +// CheckReadiness indicates an expected call of CheckReadiness. +func (mr *MockClientMockRecorder) CheckReadiness() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadiness", reflect.TypeOf((*MockClient)(nil).CheckReadiness)) +} + +// DeleteBlob mocks base method. +func (m *MockClient) DeleteBlob(d core.Digest) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteBlob", arg0) + ret := m.ctrl.Call(m, "DeleteBlob", d) ret0, _ := ret[0].(error) return ret0 } -// DeleteBlob indicates an expected call of DeleteBlob -func (mr *MockClientMockRecorder) DeleteBlob(arg0 interface{}) *gomock.Call { +// DeleteBlob indicates an expected call of DeleteBlob. +func (mr *MockClientMockRecorder) DeleteBlob(d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBlob", reflect.TypeOf((*MockClient)(nil).DeleteBlob), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBlob", reflect.TypeOf((*MockClient)(nil).DeleteBlob), d) } -// DownloadBlob mocks base method -func (m *MockClient) DownloadBlob(arg0 string, arg1 core.Digest, arg2 io.Writer) error { +// DownloadBlob mocks base method. +func (m *MockClient) DownloadBlob(namespace string, d core.Digest, dst io.Writer) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DownloadBlob", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "DownloadBlob", namespace, d, dst) ret0, _ := ret[0].(error) return ret0 } -// DownloadBlob indicates an expected call of DownloadBlob -func (mr *MockClientMockRecorder) DownloadBlob(arg0, arg1, arg2 interface{}) *gomock.Call { +// DownloadBlob indicates an expected call of DownloadBlob. +func (mr *MockClientMockRecorder) DownloadBlob(namespace, d, dst interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadBlob", reflect.TypeOf((*MockClient)(nil).DownloadBlob), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadBlob", reflect.TypeOf((*MockClient)(nil).DownloadBlob), namespace, d, dst) } -// DuplicateUploadBlob mocks base method -func (m *MockClient) DuplicateUploadBlob(arg0 string, arg1 core.Digest, arg2 io.Reader, arg3 time.Duration) error { +// DuplicateUploadBlob mocks base method. +func (m *MockClient) DuplicateUploadBlob(namespace string, d core.Digest, blob io.Reader, delay time.Duration) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DuplicateUploadBlob", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "DuplicateUploadBlob", namespace, d, blob, delay) ret0, _ := ret[0].(error) return ret0 } -// DuplicateUploadBlob indicates an expected call of DuplicateUploadBlob -func (mr *MockClientMockRecorder) DuplicateUploadBlob(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +// DuplicateUploadBlob indicates an expected call of DuplicateUploadBlob. +func (mr *MockClientMockRecorder) DuplicateUploadBlob(namespace, d, blob, delay interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DuplicateUploadBlob", reflect.TypeOf((*MockClient)(nil).DuplicateUploadBlob), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DuplicateUploadBlob", reflect.TypeOf((*MockClient)(nil).DuplicateUploadBlob), namespace, d, blob, delay) } -// ForceCleanup mocks base method -func (m *MockClient) ForceCleanup(arg0 time.Duration) error { +// ForceCleanup mocks base method. +func (m *MockClient) ForceCleanup(ttl time.Duration) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ForceCleanup", arg0) + ret := m.ctrl.Call(m, "ForceCleanup", ttl) ret0, _ := ret[0].(error) return ret0 } -// ForceCleanup indicates an expected call of ForceCleanup -func (mr *MockClientMockRecorder) ForceCleanup(arg0 interface{}) *gomock.Call { +// ForceCleanup indicates an expected call of ForceCleanup. +func (mr *MockClientMockRecorder) ForceCleanup(ttl interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForceCleanup", reflect.TypeOf((*MockClient)(nil).ForceCleanup), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForceCleanup", reflect.TypeOf((*MockClient)(nil).ForceCleanup), ttl) } -// GetMetaInfo mocks base method -func (m *MockClient) GetMetaInfo(arg0 string, arg1 core.Digest) (*core.MetaInfo, error) { +// GetMetaInfo mocks base method. +func (m *MockClient) GetMetaInfo(namespace string, d core.Digest) (*core.MetaInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetaInfo", arg0, arg1) + ret := m.ctrl.Call(m, "GetMetaInfo", namespace, d) ret0, _ := ret[0].(*core.MetaInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetMetaInfo indicates an expected call of GetMetaInfo -func (mr *MockClientMockRecorder) GetMetaInfo(arg0, arg1 interface{}) *gomock.Call { +// GetMetaInfo indicates an expected call of GetMetaInfo. +func (mr *MockClientMockRecorder) GetMetaInfo(namespace, d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetaInfo", reflect.TypeOf((*MockClient)(nil).GetMetaInfo), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetaInfo", reflect.TypeOf((*MockClient)(nil).GetMetaInfo), namespace, d) } -// GetPeerContext mocks base method +// GetPeerContext mocks base method. func (m *MockClient) GetPeerContext() (core.PeerContext, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPeerContext") @@ -129,109 +149,109 @@ func (m *MockClient) GetPeerContext() (core.PeerContext, error) { return ret0, ret1 } -// GetPeerContext indicates an expected call of GetPeerContext +// GetPeerContext indicates an expected call of GetPeerContext. func (mr *MockClientMockRecorder) GetPeerContext() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPeerContext", reflect.TypeOf((*MockClient)(nil).GetPeerContext)) } -// Locations mocks base method -func (m *MockClient) Locations(arg0 core.Digest) ([]string, error) { +// Locations mocks base method. +func (m *MockClient) Locations(d core.Digest) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Locations", arg0) + ret := m.ctrl.Call(m, "Locations", d) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } -// Locations indicates an expected call of Locations -func (mr *MockClientMockRecorder) Locations(arg0 interface{}) *gomock.Call { +// Locations indicates an expected call of Locations. +func (mr *MockClientMockRecorder) Locations(d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Locations", reflect.TypeOf((*MockClient)(nil).Locations), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Locations", reflect.TypeOf((*MockClient)(nil).Locations), d) } -// OverwriteMetaInfo mocks base method -func (m *MockClient) OverwriteMetaInfo(arg0 core.Digest, arg1 int64) error { +// OverwriteMetaInfo mocks base method. +func (m *MockClient) OverwriteMetaInfo(d core.Digest, pieceLength int64) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OverwriteMetaInfo", arg0, arg1) + ret := m.ctrl.Call(m, "OverwriteMetaInfo", d, pieceLength) ret0, _ := ret[0].(error) return ret0 } -// OverwriteMetaInfo indicates an expected call of OverwriteMetaInfo -func (mr *MockClientMockRecorder) OverwriteMetaInfo(arg0, arg1 interface{}) *gomock.Call { +// OverwriteMetaInfo indicates an expected call of OverwriteMetaInfo. +func (mr *MockClientMockRecorder) OverwriteMetaInfo(d, pieceLength interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OverwriteMetaInfo", reflect.TypeOf((*MockClient)(nil).OverwriteMetaInfo), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OverwriteMetaInfo", reflect.TypeOf((*MockClient)(nil).OverwriteMetaInfo), d, pieceLength) } -// ReplicateToRemote mocks base method -func (m *MockClient) ReplicateToRemote(arg0 string, arg1 core.Digest, arg2 string) error { +// ReplicateToRemote mocks base method. +func (m *MockClient) ReplicateToRemote(namespace string, d core.Digest, remoteDNS string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReplicateToRemote", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ReplicateToRemote", namespace, d, remoteDNS) ret0, _ := ret[0].(error) return ret0 } -// ReplicateToRemote indicates an expected call of ReplicateToRemote -func (mr *MockClientMockRecorder) ReplicateToRemote(arg0, arg1, arg2 interface{}) *gomock.Call { +// ReplicateToRemote indicates an expected call of ReplicateToRemote. +func (mr *MockClientMockRecorder) ReplicateToRemote(namespace, d, remoteDNS interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplicateToRemote", reflect.TypeOf((*MockClient)(nil).ReplicateToRemote), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplicateToRemote", reflect.TypeOf((*MockClient)(nil).ReplicateToRemote), namespace, d, remoteDNS) } -// Stat mocks base method -func (m *MockClient) Stat(arg0 string, arg1 core.Digest) (*core.BlobInfo, error) { +// Stat mocks base method. +func (m *MockClient) Stat(namespace string, d core.Digest) (*core.BlobInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Stat", arg0, arg1) + ret := m.ctrl.Call(m, "Stat", namespace, d) ret0, _ := ret[0].(*core.BlobInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// Stat indicates an expected call of Stat -func (mr *MockClientMockRecorder) Stat(arg0, arg1 interface{}) *gomock.Call { +// Stat indicates an expected call of Stat. +func (mr *MockClientMockRecorder) Stat(namespace, d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockClient)(nil).Stat), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockClient)(nil).Stat), namespace, d) } -// StatLocal mocks base method -func (m *MockClient) StatLocal(arg0 string, arg1 core.Digest) (*core.BlobInfo, error) { +// StatLocal mocks base method. +func (m *MockClient) StatLocal(namespace string, d core.Digest) (*core.BlobInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StatLocal", arg0, arg1) + ret := m.ctrl.Call(m, "StatLocal", namespace, d) ret0, _ := ret[0].(*core.BlobInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// StatLocal indicates an expected call of StatLocal -func (mr *MockClientMockRecorder) StatLocal(arg0, arg1 interface{}) *gomock.Call { +// StatLocal indicates an expected call of StatLocal. +func (mr *MockClientMockRecorder) StatLocal(namespace, d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatLocal", reflect.TypeOf((*MockClient)(nil).StatLocal), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatLocal", reflect.TypeOf((*MockClient)(nil).StatLocal), namespace, d) } -// TransferBlob mocks base method -func (m *MockClient) TransferBlob(arg0 core.Digest, arg1 io.Reader) error { +// TransferBlob mocks base method. +func (m *MockClient) TransferBlob(d core.Digest, blob io.Reader) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TransferBlob", arg0, arg1) + ret := m.ctrl.Call(m, "TransferBlob", d, blob) ret0, _ := ret[0].(error) return ret0 } -// TransferBlob indicates an expected call of TransferBlob -func (mr *MockClientMockRecorder) TransferBlob(arg0, arg1 interface{}) *gomock.Call { +// TransferBlob indicates an expected call of TransferBlob. +func (mr *MockClientMockRecorder) TransferBlob(d, blob interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransferBlob", reflect.TypeOf((*MockClient)(nil).TransferBlob), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransferBlob", reflect.TypeOf((*MockClient)(nil).TransferBlob), d, blob) } -// UploadBlob mocks base method -func (m *MockClient) UploadBlob(arg0 string, arg1 core.Digest, arg2 io.Reader) error { +// UploadBlob mocks base method. +func (m *MockClient) UploadBlob(namespace string, d core.Digest, blob io.Reader) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UploadBlob", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "UploadBlob", namespace, d, blob) ret0, _ := ret[0].(error) return ret0 } -// UploadBlob indicates an expected call of UploadBlob -func (mr *MockClientMockRecorder) UploadBlob(arg0, arg1, arg2 interface{}) *gomock.Call { +// UploadBlob indicates an expected call of UploadBlob. +func (mr *MockClientMockRecorder) UploadBlob(namespace, d, blob interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBlob", reflect.TypeOf((*MockClient)(nil).UploadBlob), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBlob", reflect.TypeOf((*MockClient)(nil).UploadBlob), namespace, d, blob) } diff --git a/mocks/origin/blobclient/clusterclient.go b/mocks/origin/blobclient/clusterclient.go index c97250fd8..f4b2c4c8f 100644 --- a/mocks/origin/blobclient/clusterclient.go +++ b/mocks/origin/blobclient/clusterclient.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/uber/kraken/origin/blobclient (interfaces: ClusterClient) +// +// Generated by this command: +// +// mockgen -package mockblobclient . ClusterClient +// // Package mockblobclient is a generated GoMock package. package mockblobclient @@ -11,126 +16,141 @@ import ( reflect "reflect" ) -// MockClusterClient is a mock of ClusterClient interface +// MockClusterClient is a mock of ClusterClient interface. type MockClusterClient struct { ctrl *gomock.Controller recorder *MockClusterClientMockRecorder + isgomock struct{} } -// MockClusterClientMockRecorder is the mock recorder for MockClusterClient +// MockClusterClientMockRecorder is the mock recorder for MockClusterClient. type MockClusterClientMockRecorder struct { mock *MockClusterClient } -// NewMockClusterClient creates a new mock instance +// NewMockClusterClient creates a new mock instance. func NewMockClusterClient(ctrl *gomock.Controller) *MockClusterClient { mock := &MockClusterClient{ctrl: ctrl} mock.recorder = &MockClusterClientMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockClusterClient) EXPECT() *MockClusterClientMockRecorder { return m.recorder } -// DownloadBlob mocks base method -func (m *MockClusterClient) DownloadBlob(arg0 string, arg1 core.Digest, arg2 io.Writer) error { +// CheckReadiness mocks base method. +func (m *MockClusterClient) CheckReadiness() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DownloadBlob", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CheckReadiness") ret0, _ := ret[0].(error) return ret0 } -// DownloadBlob indicates an expected call of DownloadBlob -func (mr *MockClusterClientMockRecorder) DownloadBlob(arg0, arg1, arg2 interface{}) *gomock.Call { +// CheckReadiness indicates an expected call of CheckReadiness. +func (mr *MockClusterClientMockRecorder) CheckReadiness() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadBlob", reflect.TypeOf((*MockClusterClient)(nil).DownloadBlob), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadiness", reflect.TypeOf((*MockClusterClient)(nil).CheckReadiness)) } -// GetMetaInfo mocks base method -func (m *MockClusterClient) GetMetaInfo(arg0 string, arg1 core.Digest) (*core.MetaInfo, error) { +// DownloadBlob mocks base method. +func (m *MockClusterClient) DownloadBlob(namespace string, d core.Digest, dst io.Writer) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetaInfo", arg0, arg1) + ret := m.ctrl.Call(m, "DownloadBlob", namespace, d, dst) + ret0, _ := ret[0].(error) + return ret0 +} + +// DownloadBlob indicates an expected call of DownloadBlob. +func (mr *MockClusterClientMockRecorder) DownloadBlob(namespace, d, dst interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadBlob", reflect.TypeOf((*MockClusterClient)(nil).DownloadBlob), namespace, d, dst) +} + +// GetMetaInfo mocks base method. +func (m *MockClusterClient) GetMetaInfo(namespace string, d core.Digest) (*core.MetaInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMetaInfo", namespace, d) ret0, _ := ret[0].(*core.MetaInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetMetaInfo indicates an expected call of GetMetaInfo -func (mr *MockClusterClientMockRecorder) GetMetaInfo(arg0, arg1 interface{}) *gomock.Call { +// GetMetaInfo indicates an expected call of GetMetaInfo. +func (mr *MockClusterClientMockRecorder) GetMetaInfo(namespace, d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetaInfo", reflect.TypeOf((*MockClusterClient)(nil).GetMetaInfo), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetaInfo", reflect.TypeOf((*MockClusterClient)(nil).GetMetaInfo), namespace, d) } -// OverwriteMetaInfo mocks base method -func (m *MockClusterClient) OverwriteMetaInfo(arg0 core.Digest, arg1 int64) error { +// OverwriteMetaInfo mocks base method. +func (m *MockClusterClient) OverwriteMetaInfo(d core.Digest, pieceLength int64) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OverwriteMetaInfo", arg0, arg1) + ret := m.ctrl.Call(m, "OverwriteMetaInfo", d, pieceLength) ret0, _ := ret[0].(error) return ret0 } -// OverwriteMetaInfo indicates an expected call of OverwriteMetaInfo -func (mr *MockClusterClientMockRecorder) OverwriteMetaInfo(arg0, arg1 interface{}) *gomock.Call { +// OverwriteMetaInfo indicates an expected call of OverwriteMetaInfo. +func (mr *MockClusterClientMockRecorder) OverwriteMetaInfo(d, pieceLength interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OverwriteMetaInfo", reflect.TypeOf((*MockClusterClient)(nil).OverwriteMetaInfo), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OverwriteMetaInfo", reflect.TypeOf((*MockClusterClient)(nil).OverwriteMetaInfo), d, pieceLength) } -// Owners mocks base method -func (m *MockClusterClient) Owners(arg0 core.Digest) ([]core.PeerContext, error) { +// Owners mocks base method. +func (m *MockClusterClient) Owners(d core.Digest) ([]core.PeerContext, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Owners", arg0) + ret := m.ctrl.Call(m, "Owners", d) ret0, _ := ret[0].([]core.PeerContext) ret1, _ := ret[1].(error) return ret0, ret1 } -// Owners indicates an expected call of Owners -func (mr *MockClusterClientMockRecorder) Owners(arg0 interface{}) *gomock.Call { +// Owners indicates an expected call of Owners. +func (mr *MockClusterClientMockRecorder) Owners(d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Owners", reflect.TypeOf((*MockClusterClient)(nil).Owners), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Owners", reflect.TypeOf((*MockClusterClient)(nil).Owners), d) } -// ReplicateToRemote mocks base method -func (m *MockClusterClient) ReplicateToRemote(arg0 string, arg1 core.Digest, arg2 string) error { +// ReplicateToRemote mocks base method. +func (m *MockClusterClient) ReplicateToRemote(namespace string, d core.Digest, remoteDNS string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReplicateToRemote", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "ReplicateToRemote", namespace, d, remoteDNS) ret0, _ := ret[0].(error) return ret0 } -// ReplicateToRemote indicates an expected call of ReplicateToRemote -func (mr *MockClusterClientMockRecorder) ReplicateToRemote(arg0, arg1, arg2 interface{}) *gomock.Call { +// ReplicateToRemote indicates an expected call of ReplicateToRemote. +func (mr *MockClusterClientMockRecorder) ReplicateToRemote(namespace, d, remoteDNS interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplicateToRemote", reflect.TypeOf((*MockClusterClient)(nil).ReplicateToRemote), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplicateToRemote", reflect.TypeOf((*MockClusterClient)(nil).ReplicateToRemote), namespace, d, remoteDNS) } -// Stat mocks base method -func (m *MockClusterClient) Stat(arg0 string, arg1 core.Digest) (*core.BlobInfo, error) { +// Stat mocks base method. +func (m *MockClusterClient) Stat(namespace string, d core.Digest) (*core.BlobInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Stat", arg0, arg1) + ret := m.ctrl.Call(m, "Stat", namespace, d) ret0, _ := ret[0].(*core.BlobInfo) ret1, _ := ret[1].(error) return ret0, ret1 } -// Stat indicates an expected call of Stat -func (mr *MockClusterClientMockRecorder) Stat(arg0, arg1 interface{}) *gomock.Call { +// Stat indicates an expected call of Stat. +func (mr *MockClusterClientMockRecorder) Stat(namespace, d interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockClusterClient)(nil).Stat), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockClusterClient)(nil).Stat), namespace, d) } -// UploadBlob mocks base method -func (m *MockClusterClient) UploadBlob(arg0 string, arg1 core.Digest, arg2 io.Reader) error { +// UploadBlob mocks base method. +func (m *MockClusterClient) UploadBlob(namespace string, d core.Digest, blob io.Reader) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UploadBlob", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "UploadBlob", namespace, d, blob) ret0, _ := ret[0].(error) return ret0 } -// UploadBlob indicates an expected call of UploadBlob -func (mr *MockClusterClientMockRecorder) UploadBlob(arg0, arg1, arg2 interface{}) *gomock.Call { +// UploadBlob indicates an expected call of UploadBlob. +func (mr *MockClusterClientMockRecorder) UploadBlob(namespace, d, blob interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBlob", reflect.TypeOf((*MockClusterClient)(nil).UploadBlob), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadBlob", reflect.TypeOf((*MockClusterClient)(nil).UploadBlob), namespace, d, blob) } diff --git a/mocks/tracker/announceclient/client.go b/mocks/tracker/announceclient/client.go index aa1fe9787..825233147 100644 --- a/mocks/tracker/announceclient/client.go +++ b/mocks/tracker/announceclient/client.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/uber/kraken/tracker/announceclient (interfaces: Client) +// +// Generated by this command: +// +// mockgen -typed -package mockannounceclient . Client +// // Package mockannounceclient is a generated GoMock package. package mockannounceclient @@ -11,41 +16,104 @@ import ( time "time" ) -// MockClient is a mock of Client interface +// MockClient is a mock of Client interface. type MockClient struct { ctrl *gomock.Controller recorder *MockClientMockRecorder + isgomock struct{} } -// MockClientMockRecorder is the mock recorder for MockClient +// MockClientMockRecorder is the mock recorder for MockClient. type MockClientMockRecorder struct { mock *MockClient } -// NewMockClient creates a new mock instance +// NewMockClient creates a new mock instance. func NewMockClient(ctrl *gomock.Controller) *MockClient { mock := &MockClient{ctrl: ctrl} mock.recorder = &MockClientMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } -// Announce mocks base method -func (m *MockClient) Announce(arg0 core.Digest, arg1 core.InfoHash, arg2 bool, arg3 int) ([]*core.PeerInfo, time.Duration, error) { +// Announce mocks base method. +func (m *MockClient) Announce(d core.Digest, h core.InfoHash, complete bool, version int) ([]*core.PeerInfo, time.Duration, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Announce", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "Announce", d, h, complete, version) ret0, _ := ret[0].([]*core.PeerInfo) ret1, _ := ret[1].(time.Duration) ret2, _ := ret[2].(error) return ret0, ret1, ret2 } -// Announce indicates an expected call of Announce -func (mr *MockClientMockRecorder) Announce(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +// Announce indicates an expected call of Announce. +func (mr *MockClientMockRecorder) Announce(d, h, complete, version interface{}) *MockClientAnnounceCall { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Announce", reflect.TypeOf((*MockClient)(nil).Announce), arg0, arg1, arg2, arg3) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Announce", reflect.TypeOf((*MockClient)(nil).Announce), d, h, complete, version) + return &MockClientAnnounceCall{Call: call} +} + +// MockClientAnnounceCall wrap *gomock.Call +type MockClientAnnounceCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockClientAnnounceCall) Return(arg0 []*core.PeerInfo, arg1 time.Duration, arg2 error) *MockClientAnnounceCall { + c.Call = c.Call.Return(arg0, arg1, arg2) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockClientAnnounceCall) Do(f func(core.Digest, core.InfoHash, bool, int) ([]*core.PeerInfo, time.Duration, error)) *MockClientAnnounceCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockClientAnnounceCall) DoAndReturn(f func(core.Digest, core.InfoHash, bool, int) ([]*core.PeerInfo, time.Duration, error)) *MockClientAnnounceCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CheckHealth mocks base method. +func (m *MockClient) CheckHealth() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckHealth") + ret0, _ := ret[0].(error) + return ret0 +} + +// CheckHealth indicates an expected call of CheckHealth. +func (mr *MockClientMockRecorder) CheckHealth() *MockClientCheckHealthCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckHealth", reflect.TypeOf((*MockClient)(nil).CheckHealth)) + return &MockClientCheckHealthCall{Call: call} +} + +// MockClientCheckHealthCall wrap *gomock.Call +type MockClientCheckHealthCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockClientCheckHealthCall) Return(arg0 error) *MockClientCheckHealthCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockClientCheckHealthCall) Do(f func() error) *MockClientCheckHealthCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockClientCheckHealthCall) DoAndReturn(f func() error) *MockClientCheckHealthCall { + c.Call = c.Call.DoAndReturn(f) + return c } diff --git a/origin/blobclient/client.go b/origin/blobclient/client.go index a3c2bee54..08bfafffe 100644 --- a/origin/blobclient/client.go +++ b/origin/blobclient/client.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -36,6 +36,7 @@ import ( type Client interface { Addr() string + CheckReadiness() error Locations(d core.Digest) ([]string, error) DeleteBlob(d core.Digest) error TransferBlob(d core.Digest, blob io.Reader) error @@ -95,6 +96,17 @@ func (c *HTTPClient) Addr() string { return c.addr } +func (c *HTTPClient) CheckReadiness() error { + _, err := httputil.Get( + fmt.Sprintf("http://%s/readiness", c.addr), + httputil.SendTimeout(5*time.Second), + httputil.SendTLS(c.tls)) + if err != nil { + return fmt.Errorf("origin not ready: %v", err) + } + return nil +} + // Locations returns the origin server addresses which d is sharded on. func (c *HTTPClient) Locations(d core.Digest) ([]string, error) { r, err := httputil.Get( diff --git a/origin/blobclient/cluster_client.go b/origin/blobclient/cluster_client.go index 7d18a0477..431d9c878 100644 --- a/origin/blobclient/cluster_client.go +++ b/origin/blobclient/cluster_client.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -25,6 +25,7 @@ import ( "github.com/cenkalti/backoff" "github.com/uber/kraken/core" + "github.com/uber/kraken/lib/backend" "github.com/uber/kraken/lib/hostlist" "github.com/uber/kraken/utils/errutil" "github.com/uber/kraken/utils/httputil" @@ -49,7 +50,7 @@ func Locations(p Provider, cluster hostlist.List, d core.Digest) (locs []string, // ClientResolver resolves digests into Clients of origins. type ClientResolver interface { - // Resolve must return an ordered, stable list of Clients for origins owning d. + // Resolve must return an ordered, stable, non-empty list of Clients for origins owning d. Resolve(d core.Digest) ([]Client, error) } @@ -78,6 +79,7 @@ func (r *clientResolver) Resolve(d core.Digest) ([]Client, error) { // ClusterClient defines a top-level origin cluster client which handles blob // location resolution and retries. type ClusterClient interface { + CheckReadiness() error UploadBlob(namespace string, d core.Digest, blob io.Reader) error DownloadBlob(namespace string, d core.Digest, dst io.Writer) error GetMetaInfo(namespace string, d core.Digest) (*core.MetaInfo, error) @@ -108,6 +110,15 @@ func (c *clusterClient) defaultPollBackOff() backoff.BackOff { } } +func (c *clusterClient) CheckReadiness() error { + clients, err := c.resolver.Resolve(backend.ReadinessCheckDigest) + if err != nil { + return fmt.Errorf("resolve clients: %s", err) + } + shuffle(clients) + return clients[0].CheckReadiness() +} + // UploadBlob uploads blob to origin cluster. See Client.UploadBlob for more details. func (c *clusterClient) UploadBlob(namespace string, d core.Digest, blob io.Reader) (err error) { clients, err := c.resolver.Resolve(d) diff --git a/origin/blobserver/server.go b/origin/blobserver/server.go index 03c22aa53..c905a3e55 100644 --- a/origin/blobserver/server.go +++ b/origin/blobserver/server.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -130,6 +130,7 @@ func (s *Server) Handler() http.Handler { // Public endpoints: r.Get("/health", handler.Wrap(s.healthCheckHandler)) + r.Get("/readiness", handler.Wrap(s.readinessCheckHandler)) r.Get("/blobs/{digest}/locations", handler.Wrap(s.getLocationsHandler)) @@ -179,6 +180,15 @@ func (s *Server) healthCheckHandler(w http.ResponseWriter, r *http.Request) erro return nil } +func (s *Server) readinessCheckHandler(w http.ResponseWriter, r *http.Request) error { + err := s.backends.CheckReadiness() + if err != nil { + return handler.Errorf("not ready to serve traffic: %s", err).Status(http.StatusServiceUnavailable) + } + fmt.Fprintln(w, "OK") + return nil +} + // statHandler returns blob info if it exists. func (s *Server) statHandler(w http.ResponseWriter, r *http.Request) error { checkLocal, err := strconv.ParseBool(httputil.GetQueryArg(r, "local", "false")) diff --git a/origin/blobserver/server_test.go b/origin/blobserver/server_test.go index 08ee08cb0..4ed7ab357 100644 --- a/origin/blobserver/server_test.go +++ b/origin/blobserver/server_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -19,6 +19,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" "testing" "time" @@ -26,6 +27,7 @@ import ( "github.com/stretchr/testify/require" "github.com/uber/kraken/core" + "github.com/uber/kraken/lib/backend" "github.com/uber/kraken/lib/backend/backenderrors" "github.com/uber/kraken/lib/persistedretry" "github.com/uber/kraken/lib/persistedretry/writeback" @@ -53,6 +55,49 @@ func TestHealth(t *testing.T) { require.Equal("OK\n", string(b)) } +func TestReadiness(t *testing.T) { + for _, tc := range []struct { + name string + mockStatErr error + expectedErrMsg string + }{ + { + name: "success", + mockStatErr: nil, + expectedErrMsg: "", + }, + { + name: "503 is returned (since stat fails)", + mockStatErr: errors.New("test error"), + expectedErrMsg: fmt.Sprintf("503: not ready to serve traffic: backend for namespace '%s' not ready: test error", backend.ReadinessCheckNamespace), + }, + } { + t.Run(tc.name, func(t *testing.T) { + require := require.New(t) + + cp := newTestClientProvider() + + s := newTestServer(t, master1, hashRingMaxReplica(), cp) + defer s.cleanup() + + backendClient := s.backendClient(backend.ReadinessCheckNamespace, true) + + mockStat := &core.BlobInfo{} + if tc.mockStatErr != nil { + mockStat = nil + } + backendClient.EXPECT().Stat(backend.ReadinessCheckNamespace, backend.ReadinessCheckName).Return(mockStat, tc.mockStatErr) + + err := cp.Provide(master1).CheckReadiness() + if tc.expectedErrMsg == "" { + require.Nil(err) + } else { + require.True(strings.Contains(err.Error(), tc.expectedErrMsg)) + } + }) + } +} + func TestStatHandlerLocalNotFound(t *testing.T) { require := require.New(t) @@ -117,7 +162,7 @@ func TestStatHandlerNotFound(t *testing.T) { d := core.DigestFixture() namespace := core.TagFixture() - backendClient := s.backendClient(namespace) + backendClient := s.backendClient(namespace, false) backendClient.EXPECT().Stat(namespace, d.Hex()).Return(nil, backenderrors.ErrBlobNotFound) @@ -192,7 +237,7 @@ func TestDownloadBlobNotFound(t *testing.T) { d := core.DigestFixture() namespace := core.TagFixture() - backendClient := s.backendClient(namespace) + backendClient := s.backendClient(namespace, false) backendClient.EXPECT().Stat(namespace, d.Hex()).Return(nil, backenderrors.ErrBlobNotFound) err := cp.Provide(master1).DownloadBlob(namespace, d, ioutil.Discard) @@ -280,7 +325,7 @@ func TestGetMetaInfoDownloadsBlobAndReplicates(t *testing.T) { blob := computeBlobForHosts(ring, s1.host, s2.host) - backendClient := s1.backendClient(namespace) + backendClient := s1.backendClient(namespace, false) backendClient.EXPECT().Stat(namespace, blob.Digest.Hex()).Return(core.NewBlobInfo(int64(len(blob.Content))), nil).AnyTimes() backendClient.EXPECT().Download(namespace, blob.Digest.Hex(), mockutil.MatchWriter(blob.Content)).Return(nil) @@ -317,7 +362,7 @@ func TestGetMetaInfoBlobNotFound(t *testing.T) { d := core.DigestFixture() namespace := core.TagFixture() - backendClient := s.backendClient(namespace) + backendClient := s.backendClient(namespace, false) backendClient.EXPECT().Stat(namespace, d.Hex()).Return(nil, backenderrors.ErrBlobNotFound) mi, err := cp.Provide(master1).GetMetaInfo(namespace, d) @@ -582,7 +627,7 @@ func TestReplicateToRemoteWhenBlobInStorageBackend(t *testing.T) { blob := core.NewBlobFixture() namespace := core.TagFixture() - backendClient := s.backendClient(namespace) + backendClient := s.backendClient(namespace, false) backendClient.EXPECT().Stat(namespace, blob.Digest.Hex()).Return(core.NewBlobInfo(int64(len(blob.Content))), nil).AnyTimes() backendClient.EXPECT().Download(namespace, blob.Digest.Hex(), mockutil.MatchWriter(blob.Content)).Return(nil) diff --git a/origin/blobserver/testutils_test.go b/origin/blobserver/testutils_test.go index 9bed11b32..593328e71 100644 --- a/origin/blobserver/testutils_test.go +++ b/origin/blobserver/testutils_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -158,9 +158,9 @@ func newTestServer( } } -func (s *testServer) backendClient(namespace string) *mockbackend.MockClient { +func (s *testServer) backendClient(namespace string, mustReady bool) *mockbackend.MockClient { client := mockbackend.NewMockClient(s.ctrl) - if err := s.backendManager.Register(namespace, client, false); err != nil { + if err := s.backendManager.Register(namespace, client, mustReady); err != nil { panic(err) } return client diff --git a/tracker/announceclient/client.go b/tracker/announceclient/client.go index 1085a29e8..50b871432 100644 --- a/tracker/announceclient/client.go +++ b/tracker/announceclient/client.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -23,6 +23,7 @@ import ( "time" "github.com/uber/kraken/core" + "github.com/uber/kraken/lib/backend" "github.com/uber/kraken/lib/hashring" "github.com/uber/kraken/utils/httputil" ) @@ -58,6 +59,8 @@ type Response struct { // Client defines a client for announcing and getting peers. type Client interface { + // CheckHealth calls a tracker's health endpoint. + CheckHealth() error Announce( d core.Digest, h core.InfoHash, @@ -89,6 +92,18 @@ func getEndpoint(version int, addr string, h core.InfoHash) (method, url string) return "POST", fmt.Sprintf("http://%s/announce/%s", addr, h.String()) } +func (c *client) CheckHealth() error { + addr := c.ring.Locations(backend.ReadinessCheckDigest)[0] + _, err := httputil.Get( + fmt.Sprintf("http://%s/health", addr), + httputil.SendTimeout(2*time.Second), + httputil.SendTLS(c.tls)) + if err != nil { + return fmt.Errorf("tracker not ready: %v", err) + } + return nil +} + // Announce announces the torrent identified by (d, h) with the number of // downloaded bytes. Returns a list of all other peers announcing for said torrent, // sorted by priority, and the interval for the next announce. @@ -142,6 +157,10 @@ func Disabled() Client { return DisabledClient{} } +func (c DisabledClient) CheckHealth() error { + return nil +} + // Announce always returns error. func (c DisabledClient) Announce( d core.Digest, h core.InfoHash, complete bool, version int) ([]*core.PeerInfo, time.Duration, error) { diff --git a/tracker/trackerserver/announce_test.go b/tracker/trackerserver/announce_test.go index cc78f0cd3..01752ddd0 100644 --- a/tracker/trackerserver/announce_test.go +++ b/tracker/trackerserver/announce_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package trackerserver import ( "errors" "fmt" + "regexp" "testing" "time" @@ -33,6 +34,50 @@ func newAnnounceClient(pctx core.PeerContext, addr string) announceclient.Client return announceclient.New(pctx, hashring.NoopPassiveRing(hostlist.Fixture(addr)), nil) } +func TestCheckHealth(t *testing.T) { + for _, tc := range []struct { + name string + serverIsUp bool + expectedErrMsgRegex string + }{ + { + name: "success", + serverIsUp: true, + expectedErrMsgRegex: "", + }, + { + name: "failure", + serverIsUp: false, + expectedErrMsgRegex: `tracker not ready: network error: Get "http://127\.0\.0\.1:\d+/health": dial tcp 127\.0\.0\.1:\d+: connect: connection refused`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + require := require.New(t) + + mocks, cleanup := newServerMocks(t, Config{}) + defer cleanup() + + addr, stop := testutil.StartServer(mocks.handler()) + if tc.serverIsUp { + defer stop() + } else { + stop() + } + + pctx := core.PeerContextFixture() + client := newAnnounceClient(pctx, addr) + + err := client.CheckHealth() + if tc.expectedErrMsgRegex == "" { + require.NoError(err) + } else { + r, _ := regexp.Compile(tc.expectedErrMsgRegex) + require.True(r.MatchString(err.Error())) + } + }) + } +} + func TestAnnounceSinglePeerResponse(t *testing.T) { for _, version := range []int{announceclient.V1, announceclient.V2} { t.Run(fmt.Sprintf("V%d", version), func(t *testing.T) {