func TestUploadLogChunksAndCloseSuccessfully(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) ts.ExpectAndRespond("POST", "/buckets/", http.StatusOK, `{"Id": "foo"}`) ts.ExpectAndRespond("POST", "/buckets/foo/artifacts", http.StatusOK, `{"Name": "artifact"}`) b, _ := client.NewBucket("foo", "bar", 32) sa, err := b.NewChunkedArtifact("artifact") require.NotNil(t, sa) require.NoError(t, err) { // Content request might come later, even as late as Flush() ts.ExpectAndRespond("POST", "/buckets/foo/artifacts/artifact", 200, `{}`) err := sa.AppendLog("console contents") require.NoError(t, err) } { // Content request might come later, even as late as Flush() ts.ExpectAndRespond("POST", "/buckets/foo/artifacts/artifact", 200, `{}`) err := sa.AppendLog("more console contents") require.NoError(t, err) } { ts.ExpectAndRespond("POST", "/buckets/foo/artifacts/artifact/close", 200, `{}`) err := sa.Close() require.NoError(t, err) } }
func TestPushLogChunkCancelledContext(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() ctx, cancel := context.WithCancel(context.Background()) client := NewArtifactStoreClientWithContext(ts.URL, 100*time.Millisecond, ctx) ts.ExpectAndRespond("POST", "/buckets/", http.StatusOK, `{"Id": "foo"}`) ts.ExpectAndRespond("POST", "/buckets/foo/artifacts", http.StatusOK, `{"Name": "artifact"}`) b, _ := client.NewBucket("foo", "bar", 32) sa, err := b.NewChunkedArtifact("artifact") require.NotNil(t, sa) require.NoError(t, err) // Cancel the context to prevent any further requests cancel() { err := sa.AppendLog("console contents") require.NoError(t, err) err = sa.Close() require.Error(t, err) require.False(t, err.IsRetriable()) } }
func TestPushLogChunkServerSucceedOnRetry(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) ts.ExpectAndRespond("POST", "/buckets/", http.StatusOK, `{"Id": "foo"}`) ts.ExpectAndRespond("POST", "/buckets/foo/artifacts", http.StatusOK, `{"Name": "artifact"}`) b, _ := client.NewBucket("foo", "bar", 32) sa, err := b.NewChunkedArtifact("artifact") require.NotNil(t, sa) require.NoError(t, err) { // Fail with a retriable error first ts.ExpectAndRespond("POST", "/buckets/foo/artifacts/artifact", 500, `{}`) // Then succeed on retry ts.ExpectAndRespond("POST", "/buckets/foo/artifacts/artifact", 200, `{}`) err := sa.AppendLog("console contents") require.NoError(t, err) } { ts.ExpectAndRespond("POST", "/buckets/foo/artifacts/artifact/close", 200, `{}`) err := sa.Close() require.NoError(t, err) } }
func TestGetBucketSuccessfully(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) ts.ExpectAndRespond("GET", "/buckets/foo", http.StatusOK, `{"Id": "foo"}`) b, err := client.GetBucket("foo") require.NotNil(t, b) require.NoError(t, err) }
func TestGetBucketSuccessStateWithWrongName(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) ts.ExpectAndRespond("GET", "/buckets/foo", http.StatusOK, `{"Id": "1234"}`) b, err := client.GetBucket("foo") require.Nil(t, b) require.Error(t, err) require.False(t, err.IsRetriable(), "Error %s should not be retriable", err) }
func TestNewStreamedArtifactSuccessfully(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) ts.ExpectAndRespond("POST", "/buckets/", http.StatusOK, `{"Id": "foo"}`) ts.ExpectAndRespond("POST", "/buckets/foo/artifacts", http.StatusOK, `{"Name": "artifact"}`) b, _ := client.NewBucket("foo", "bar", 32) sa, err := b.NewStreamedArtifact("artifact", 10) require.NotNil(t, sa) require.NoError(t, err) }
func TestInitTimeout(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() r := &Reporter{deadline: 100 * time.Millisecond} artifactServer = ts.URL ts.ExpectAndHang("POST", "/buckets/") r.Init(&client.Config{JobstepID: "jobstep"}) if !r.isDisabled() { t.Error("Init did not fail with deadline exceeded") } }
func TestShutdownTimeout(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() r := &Reporter{deadline: 100 * time.Millisecond} artifactServer = ts.URL ts.ExpectAndRespond("POST", "/buckets/", 200, `{"Id": "jobstep"}`) r.Init(&client.Config{JobstepID: "jobstep"}) if r.isDisabled() { t.Error("Init should not fail with deadline exceeded") } ts.ExpectAndHang("POST", "/buckets/jobstep/close") r.Shutdown() if !r.isDisabled() { t.Error("Shutdown did not fail with deadline exceeded") } }
func TestPushLogChunkTimeout(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() r := &Reporter{deadline: 150 * time.Millisecond} artifactServer = ts.URL ts.ExpectAndRespond("POST", "/buckets/", 200, `{"Id": "jobstep"}`) r.Init(&client.Config{JobstepID: "jobstep"}) if r.isDisabled() { t.Error("Init should not fail with deadline exceeded") } ts.ExpectAndHang("POST", "/buckets/jobstep/artifacts") r.PushLogChunk("console", []byte("console contents")) if !r.isDisabled() { t.Error("PushLogChunk did not fail with deadline exceeded") } // This call should not even create a new request. If it does, testserver will throw an error // about an unexpected request. r.PushLogChunk("console", []byte("console contents")) }
func TestPushLogChunkServerFailWithTerminalError(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClientWithContext(ts.URL, 100*time.Millisecond, context.Background()) ts.ExpectAndRespond("POST", "/buckets/", http.StatusOK, `{"Id": "foo"}`) ts.ExpectAndRespond("POST", "/buckets/foo/artifacts", http.StatusOK, `{"Name": "artifact"}`) b, _ := client.NewBucket("foo", "bar", 32) sa, err := b.NewChunkedArtifact("artifact") require.NotNil(t, sa) require.NoError(t, err) { // Fail with a terminal error ts.ExpectAndRespond("POST", "/buckets/foo/artifacts/artifact", 400, `{}`) err := sa.AppendLog("console contents") require.NoError(t, err) err = sa.Close() require.Error(t, err) require.False(t, err.IsRetriable()) } }
func TestPublishArtifactsTimeout(t *testing.T) { ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() r := &Reporter{deadline: 100 * time.Millisecond} artifactServer = ts.URL ts.ExpectAndRespond("POST", "/buckets/", 200, `{"Id": "jobstep"}`) r.Init(&client.Config{JobstepID: "jobstep"}) if r.isDisabled() { t.Error("Init should not fail with deadline exceeded") } ma := &mockAdapter{} ts.ExpectAndHang("POST", "/buckets/jobstep/artifacts") l := client.NewLog() go l.Drain() defer l.Close() r.PublishArtifacts(client.ConfigCmd{Artifacts: []string{"*hosts*"}}, ma, l) if !r.isDisabled() { t.Error("PublishArtifacts did not fail with deadline exceeded") } }
func testErrorCombinations(t *testing.T, prerun func(*testserver.TestServer, *ArtifactStoreClient) interface{}, method string, url string, test func(c *ArtifactStoreClient, obj interface{}) (interface{}, *ArtifactsError)) { { ts := testserver.NewTestServer(t) client := NewArtifactStoreClient(ts.URL) obj := prerun(ts, client) ts.CloseAndAssertExpectations() // Server is missing, network error op, err := test(client, obj) require.Nil(t, op) require.Error(t, err) require.True(t, err.IsRetriable(), "Error %s should be retriable", err) } { // Server threw internal error ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) obj := prerun(ts, client) ts.ExpectAndRespond(method, url, http.StatusInternalServerError, `{"error": "Something bad happened"}`) op, err := test(client, obj) require.Nil(t, op) require.Error(t, err) require.True(t, err.IsRetriable(), "Error %s should be retriable", err) } { // Server indicated client error ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) obj := prerun(ts, client) ts.ExpectAndRespond(method, url, http.StatusBadRequest, `{"error": "Bad client"}`) op, err := test(client, obj) require.Nil(t, op) require.Error(t, err) require.False(t, err.IsRetriable(), "Error %s should not be retriable", err) } { // Proxy error - server was unreachable ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) obj := prerun(ts, client) ts.ExpectAndRespond(method, url, http.StatusBadGateway, `<html>Foo</html>`) op, err := test(client, obj) require.Nil(t, op) require.Error(t, err) require.True(t, err.IsRetriable(), "Error %s should be retriable", err) } { // Proxy/server error - mangled output ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClient(ts.URL) obj := prerun(ts, client) ts.ExpectAndRespond(method, url, http.StatusOK, `<html></html>`) op, err := test(client, obj) require.Nil(t, op) require.Error(t, err) require.False(t, err.IsRetriable(), "Error %s should not be retriable", err) } { // Proxy/server hangs and times out ts := testserver.NewTestServer(t) defer ts.CloseAndAssertExpectations() client := NewArtifactStoreClientWithContext(ts.URL, 100*time.Millisecond, context.Background()) obj := prerun(ts, client) ts.ExpectAndHang(method, url) op, err := test(client, obj) require.Nil(t, op) require.Error(t, err) require.True(t, err.IsRetriable(), "Error %s should be retriable", err) } }