| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package service |
| |
| import ( |
| "context" |
| "fmt" |
| "reflect" |
| "testing" |
| |
| mocks "fuchsia.googlesource.com/infra/infra/tilo/resultstore/service/mocks" |
| "github.com/golang/mock/gomock" |
| "github.com/golang/protobuf/ptypes/timestamp" |
| api "google.golang.org/genproto/googleapis/devtools/resultstore/v2" |
| "google.golang.org/genproto/protobuf/field_mask" |
| ) |
| |
| // Public testing constants. |
| const ( |
| TestLogURI = "http://test.com/log.txt" |
| TestProjectID = "123456789" |
| ) |
| |
| // Public testing values. |
| var ( |
| TestLabels = []string{"test-label"} |
| TestProperties = map[string]string{"test-property": "test-value"} |
| TestUsers = []string{"test-user"} |
| TestUUID = "test-uuid" |
| TestTimestamp = ×tamp.Timestamp{Seconds: 12345678, Nanos: 99999} |
| TestInvocationStatus = InvocationSucceeded |
| TestTargetStatus = TargetSucceeded |
| TestTestStatus = TestPassed |
| TestTestSuite = "test-suite" |
| ) |
| |
| // Test entity keys. |
| var ( |
| TestInvocationKey = &InvocationKey{ |
| EntityID: &api.Invocation_Id{ |
| InvocationId: "test-invocation", |
| }, |
| EntityName: "invocations/test-invocation", |
| } |
| TestConfigurationKey = &ConfigurationKey{ |
| EntityID: &api.Configuration_Id{ |
| InvocationId: TestInvocationKey.ID(), |
| ConfigurationId: "test-configuration", |
| }, |
| EntityName: fmt.Sprintf("invocations/%s/configs/test-configuration", |
| TestInvocationKey.ID()), |
| } |
| TestTargetKey = &TargetKey{ |
| EntityID: &api.Target_Id{ |
| InvocationId: TestInvocationKey.ID(), |
| TargetId: "test-target", |
| }, |
| EntityName: fmt.Sprintf("invocations/%s/targets/test-target", |
| TestInvocationKey.ID()), |
| } |
| TestConfiguredTargetKey = &ConfiguredTargetKey{ |
| EntityID: &api.ConfiguredTarget_Id{ |
| InvocationId: TestInvocationKey.ID(), |
| TargetId: TestTargetKey.ID(), |
| ConfigurationId: TestConfigurationKey.ID(), |
| }, |
| EntityName: fmt.Sprintf("invocations/%s/targets/%s/configuredTargets/%s", |
| TestInvocationKey.ID(), |
| TestTargetKey.ID(), |
| TestConfigurationKey.ID()), |
| } |
| TestActionKey = &ActionKey{ |
| EntityID: &api.Action_Id{ |
| InvocationId: TestInvocationKey.ID(), |
| TargetId: TestTargetKey.ID(), |
| ConfigurationId: TestConfigurationKey.ID(), |
| ActionId: "test-action", |
| }, |
| EntityName: fmt.Sprintf( |
| "invocations/%s/targets/%s/configuredTargets/%s/actions/test-action", |
| TestInvocationKey.ID(), |
| TestTargetKey.ID(), |
| TestConfigurationKey.ID()), |
| } |
| ) |
| |
| // TestBed manages the setup and teardown phases of individual test cases. |
| type TestBed struct { |
| MockRPCClient *mocks.MockResultStoreUploadClient |
| ctrl *gomock.Controller |
| } |
| |
| // Setup creates the service-under-test and should be run before every test case. |
| func (bed *TestBed) Setup(t *testing.T) (*Service, context.Context) { |
| // Cache the mock controller so we can Finish() it during test teardown. |
| bed.ctrl = gomock.NewController(t) |
| bed.MockRPCClient = mocks.NewMockResultStoreUploadClient(bed.ctrl) |
| |
| // Force Service to re-use a fake UUID for testing by embedding the UUID in the |
| // context object. |
| ctx, err := SetTestUUID(context.Background(), TestUUID) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| return New(bed.MockRPCClient, TestUUID), ctx |
| } |
| |
| // Teardown is used to clean up after every test-case. |
| func (bed *TestBed) Teardown() { |
| bed.ctrl.Finish() |
| } |
| |
| // ExpectRPC is used to expect that a specific RPC message is recieved by the test bed. |
| // If an invalid message or no message is received, the test will fail. |
| func (bed *TestBed) ExpectRPC() *mocks.MockResultStoreUploadClientMockRecorder { |
| return bed.MockRPCClient.EXPECT() |
| } |
| |
| func expectEqual(t *testing.T, expected interface{}, actual interface{}) { |
| if !reflect.DeepEqual(expected, actual) { |
| t.Errorf("Objects do not match:\n") |
| t.Errorf("Expected: %+v\n", expected) |
| t.Errorf("Actual: %+v\n", actual) |
| } |
| } |
| |
| func TestService_CreateInvocation(t *testing.T) { |
| t.Run("should return an InvocationKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &Invocation{ |
| ProjectID: TestProjectID, |
| Users: TestUsers, |
| Labels: TestLabels, |
| Properties: TestProperties, |
| LogURL: TestLogURI, |
| StartTime: TestTimestamp, |
| Status: TestInvocationStatus, |
| } |
| |
| expectedOutput := TestInvocationKey |
| |
| testBed.ExpectRPC(). |
| CreateInvocation(ctx, &api.CreateInvocationRequest{ |
| AuthorizationToken: TestUUID, |
| RequestId: TestUUID, |
| InvocationId: TestUUID, |
| Invocation: input.ToResultStoreInvocation(), |
| }). |
| Return(&api.Invocation{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.CreateInvocation(ctx, input) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_UpdateInvocation(t *testing.T) { |
| t.Run("should return an InvocationKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &Invocation{ |
| ID: TestInvocationKey.ID(), |
| Properties: TestProperties, |
| StartTime: TestTimestamp, |
| } |
| |
| expectedOutput := TestInvocationKey |
| |
| testBed.ExpectRPC(). |
| UpdateInvocation(ctx, &api.UpdateInvocationRequest{ |
| AuthorizationToken: TestUUID, |
| Invocation: input.ToResultStoreInvocation(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }). |
| Return(&api.Invocation{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.UpdateInvocation(ctx, input) |
| if err != nil { |
| t.Fatal(err) |
| } |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_FinishInvocation(t *testing.T) { |
| t.Run("should return an InvocationKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| expectedOutput := TestInvocationKey |
| |
| testBed.ExpectRPC(). |
| FinishInvocation(ctx, &api.FinishInvocationRequest{ |
| AuthorizationToken: TestUUID, |
| Name: TestInvocationKey.Name(), |
| }). |
| Return(&api.FinishInvocationResponse{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.FinishInvocation(ctx, TestInvocationKey.Name()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_CreateConfiguration(t *testing.T) { |
| t.Run("should return a ConfigurationKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &Configuration{ |
| ID: TestConfigurationKey.ID(), |
| InvocationID: TestInvocationKey.ID(), |
| Properties: TestProperties, |
| } |
| |
| expectedOutput := TestConfigurationKey |
| |
| testBed.ExpectRPC(). |
| CreateConfiguration(ctx, &api.CreateConfigurationRequest{ |
| RequestId: TestUUID, |
| AuthorizationToken: TestUUID, |
| Parent: TestInvocationKey.Name(), |
| ConfigId: input.ID, |
| Configuration: input.ToResultStoreConfiguration(), |
| }). |
| Return(&api.Configuration{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.CreateConfiguration(ctx, input, TestInvocationKey.Name()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_CreateTarget(t *testing.T) { |
| t.Run("should return a TargetKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &Target{ |
| ID: TestTargetKey.ID(), |
| Properties: TestProperties, |
| StartTime: TestTimestamp, |
| Status: TestTargetStatus, |
| } |
| |
| expectedOutput := TestTargetKey |
| |
| testBed.ExpectRPC(). |
| CreateTarget(ctx, &api.CreateTargetRequest{ |
| RequestId: TestUUID, |
| AuthorizationToken: TestUUID, |
| Parent: TestInvocationKey.Name(), |
| TargetId: input.ID, |
| Target: input.ToResultStoreTarget(), |
| }). |
| Return(&api.Target{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.CreateTarget(ctx, input, TestInvocationKey.Name()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_UpdateTarget(t *testing.T) { |
| t.Run("should return a TargetKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &Target{ |
| ID: TestTargetKey.ID(), |
| InvocationID: TestInvocationKey.ID(), |
| Properties: TestProperties, |
| StartTime: TestTimestamp, |
| } |
| |
| expectedOutput := TestTargetKey |
| |
| testBed.ExpectRPC(). |
| UpdateTarget(ctx, &api.UpdateTargetRequest{ |
| AuthorizationToken: TestUUID, |
| Target: input.ToResultStoreTarget(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }). |
| Return(&api.Target{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.UpdateTarget(ctx, input) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_FinishTarget(t *testing.T) { |
| t.Run("should return a TargetKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| expectedOutput := TestTargetKey |
| |
| testBed.ExpectRPC(). |
| FinishTarget(ctx, &api.FinishTargetRequest{ |
| AuthorizationToken: TestUUID, |
| Name: TestTargetKey.Name(), |
| }). |
| Return(&api.FinishTargetResponse{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.FinishTarget(ctx, TestTargetKey.Name()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_CreateConfiguredTarget(t *testing.T) { |
| t.Run("should return a ConfiguredTargetKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &ConfiguredTarget{ |
| ConfigID: TestConfigurationKey.ID(), |
| Properties: TestProperties, |
| StartTime: TestTimestamp, |
| } |
| |
| expectedOutput := TestConfiguredTargetKey |
| |
| testBed.ExpectRPC(). |
| CreateConfiguredTarget(ctx, &api.CreateConfiguredTargetRequest{ |
| AuthorizationToken: TestUUID, |
| RequestId: TestUUID, |
| Parent: TestTargetKey.Name(), |
| ConfigId: TestConfigurationKey.ID(), |
| ConfiguredTarget: input.ToResultStoreConfiguredTarget(), |
| }). |
| Return(&api.ConfiguredTarget{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.CreateConfiguredTarget(ctx, input, TestTargetKey.Name()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_UpdateConfiguredTarget(t *testing.T) { |
| t.Run("should return a ConfiguredTargetKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &ConfiguredTarget{ |
| ConfigID: TestConfiguredTargetKey.ID(), |
| Properties: TestProperties, |
| Status: TestTargetStatus, |
| StartTime: TestTimestamp, |
| } |
| |
| expectedOutput := TestConfiguredTargetKey |
| |
| testBed.ExpectRPC(). |
| UpdateConfiguredTarget(ctx, &api.UpdateConfiguredTargetRequest{ |
| AuthorizationToken: TestUUID, |
| ConfiguredTarget: input.ToResultStoreConfiguredTarget(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }). |
| Return(&api.ConfiguredTarget{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.UpdateConfiguredTarget(ctx, input) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_FinishConfiguredTarget(t *testing.T) { |
| t.Run("should return a ConfiguredTargetKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| expectedOutput := TestConfiguredTargetKey |
| |
| testBed.ExpectRPC(). |
| FinishConfiguredTarget(ctx, &api.FinishConfiguredTargetRequest{ |
| AuthorizationToken: TestUUID, |
| Name: TestConfiguredTargetKey.Name(), |
| }). |
| Return(&api.FinishConfiguredTargetResponse{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.FinishConfiguredTarget(ctx, expectedOutput.Name()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_CreateTestAction(t *testing.T) { |
| t.Run("should return an ActionKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &TestAction{ |
| ID: TestActionKey.ID(), |
| InvocationID: TestConfiguredTargetKey.InvocationID(), |
| TargetID: TestConfiguredTargetKey.TargetID(), |
| ConfigID: TestConfiguredTargetKey.ConfigurationID(), |
| TestSuite: TestTestSuite, |
| TestLogURI: TestLogURI, |
| StartTime: TestTimestamp, |
| Status: TestTestStatus, |
| } |
| |
| expectedOutput := TestActionKey |
| |
| testBed.ExpectRPC(). |
| CreateAction(ctx, &api.CreateActionRequest{ |
| RequestId: TestUUID, |
| AuthorizationToken: TestUUID, |
| Parent: TestConfiguredTargetKey.Name(), |
| ActionId: input.ID, |
| Action: input.ToResultStoreAction(), |
| }). |
| Return(&api.Action{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.CreateTestAction(ctx, input, TestConfiguredTargetKey.Name()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |
| |
| func TestService_UpdateTestAction(t *testing.T) { |
| t.Run("should return an ActionKey from an RPC response", func(t *testing.T) { |
| testBed := new(TestBed) |
| service, ctx := testBed.Setup(t) |
| defer testBed.Teardown() |
| |
| input := &TestAction{ |
| ID: TestActionKey.ID(), |
| InvocationID: TestConfiguredTargetKey.InvocationID(), |
| TargetID: TestConfiguredTargetKey.TargetID(), |
| ConfigID: TestConfiguredTargetKey.ConfigurationID(), |
| TestSuite: TestTestSuite, |
| TestLogURI: TestLogURI, |
| StartTime: TestTimestamp, |
| } |
| |
| expectedOutput := TestActionKey |
| |
| testBed.ExpectRPC(). |
| UpdateAction(ctx, &api.UpdateActionRequest{ |
| AuthorizationToken: TestUUID, |
| Action: input.ToResultStoreAction(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }). |
| Return(&api.Action{ |
| Name: expectedOutput.EntityName, |
| Id: expectedOutput.EntityID, |
| }, nil) |
| |
| output, err := service.UpdateTestAction(ctx, input) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectEqual(t, expectedOutput, output) |
| }) |
| } |