| // 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 resultstore |
| |
| import ( |
| "log" |
| "time" |
| |
| "github.com/golang/protobuf/ptypes" |
| "github.com/golang/protobuf/ptypes/duration" |
| "github.com/golang/protobuf/ptypes/timestamp" |
| api "google.golang.org/genproto/googleapis/devtools/resultstore/v2" |
| ) |
| |
| func timeToProtoTimestamp(input time.Time) *timestamp.Timestamp { |
| output, err := ptypes.TimestampProto(input) |
| if err != nil { |
| // We should never get here. |
| panic(err.Error()) |
| } |
| return output |
| } |
| |
| func protoTimestampToTime(input *timestamp.Timestamp) time.Time { |
| output, err := ptypes.Timestamp(input) |
| if err != nil { |
| // We should never get here. |
| panic(err.Error()) |
| } |
| return output.UTC() |
| } |
| |
| func durationToProtoDuration(input time.Duration) *duration.Duration { |
| return ptypes.DurationProto(input) |
| } |
| |
| func protoDurationToDuration(input *duration.Duration) time.Duration { |
| output, err := ptypes.Duration(input) |
| if err != nil { |
| // We should never get here. |
| panic(err.Error()) |
| } |
| return output |
| } |
| |
| func mapToProperties(input map[string]string) []*api.Property { |
| var props []*api.Property |
| for k, v := range input { |
| props = append(props, &api.Property{Key: k, Value: v}) |
| } |
| return props |
| } |
| |
| func propertiesToMap(input []*api.Property) map[string]string { |
| output := make(map[string]string) |
| for _, property := range input { |
| output[property.Key] = property.Value |
| } |
| return output |
| } |
| |
| func lookupFileURI(files []*api.File, fileID string) string { |
| for _, file := range files { |
| if file.Uid == fileID { |
| return file.Uri |
| } |
| } |
| return "" |
| } |
| |
| // Invocation maps to a ResultStore Invocation. See full docs at: |
| // https://github.com/googleapis/googleapis/blob/master/google/devtools/resultstore/v2/invocation.proto |
| type Invocation struct { |
| // The name of this Invocation as it appears in ResultStore. |
| Name string |
| // The ID of this invocation as it appears in ResultStore. |
| ID string |
| ProjectID string |
| Users []string |
| Labels []string |
| Properties map[string]string |
| LogURL string |
| Status Status |
| StartTime time.Time |
| Duration time.Duration |
| } |
| |
| func (i Invocation) ToResultStoreInvocation() *api.Invocation { |
| return &api.Invocation{ |
| Name: i.Name, |
| Id: &api.Invocation_Id{ |
| InvocationId: i.ID, |
| }, |
| StatusAttributes: &api.StatusAttributes{ |
| Status: i.Status.ToResultStoreStatus(), |
| }, |
| Timing: &api.Timing{ |
| StartTime: timeToProtoTimestamp(i.StartTime), |
| Duration: durationToProtoDuration(i.Duration), |
| }, |
| InvocationAttributes: &api.InvocationAttributes{ |
| ProjectId: i.ProjectID, |
| Users: i.Users, |
| Labels: i.Labels, |
| }, |
| Files: []*api.File{ |
| &api.File{Uid: "invocation.log", Uri: i.LogURL}, |
| }, |
| Properties: mapToProperties(i.Properties), |
| } |
| } |
| |
| func (i *Invocation) FromResultStoreInvocation(input *api.Invocation) { |
| *i = Invocation{ |
| Name: input.GetName(), |
| ID: input.GetId().InvocationId, |
| ProjectID: input.InvocationAttributes.ProjectId, |
| Users: input.InvocationAttributes.Users, |
| Labels: input.InvocationAttributes.Labels, |
| Properties: propertiesToMap(input.Properties), |
| LogURL: lookupFileURI(input.Files, "invocation.log"), |
| Status: statusFromResultStoreStatus(input.StatusAttributes.Status), |
| StartTime: protoTimestampToTime(input.Timing.StartTime), |
| Duration: protoDurationToDuration(input.Timing.Duration), |
| } |
| } |
| |
| // Configuration maps to a ResultStore Configuration. See full docs at: |
| // https://github.com/googleapis/googleapis/blob/master/google/devtools/resultstore/v2/configuration.proto |
| type Configuration struct { |
| // The name of this Configuration as it appears in ResultStore. |
| Name string |
| // The ID of this Configuration as it appears in ResultStore. |
| ID string |
| InvocationID string |
| Properties map[string]string |
| } |
| |
| func (c Configuration) ToResultStoreConfiguration() *api.Configuration { |
| return &api.Configuration{ |
| Name: c.Name, |
| Id: &api.Configuration_Id{ |
| InvocationId: c.InvocationID, |
| ConfigurationId: c.ID, |
| }, |
| Properties: mapToProperties(c.Properties), |
| } |
| } |
| |
| func (c *Configuration) FromResultStoreConfiguration(input *api.Configuration) { |
| *c = Configuration{ |
| Name: input.GetName(), |
| ID: input.GetId().ConfigurationId, |
| InvocationID: input.GetId().InvocationId, |
| Properties: propertiesToMap(input.Properties), |
| } |
| } |
| |
| // Target maps to a ResultStore Target. See full docs at: |
| // https://github.com/googleapis/googleapis/blob/master/google/devtools/resultstore/v2/target.proto |
| type Target struct { |
| Name string |
| ID string |
| InvocationID string |
| Properties map[string]string |
| Status Status |
| StartTime time.Time |
| Duration time.Duration |
| } |
| |
| func (t Target) ToResultStoreTarget() *api.Target { |
| return &api.Target{ |
| Id: &api.Target_Id{ |
| InvocationId: t.InvocationID, |
| TargetId: t.ID, |
| }, |
| Timing: &api.Timing{ |
| StartTime: timeToProtoTimestamp(t.StartTime), |
| Duration: durationToProtoDuration(t.Duration), |
| }, |
| StatusAttributes: &api.StatusAttributes{ |
| Status: t.Status.ToResultStoreStatus(), |
| }, |
| Properties: mapToProperties(t.Properties), |
| Visible: true, |
| } |
| } |
| |
| func (t *Target) FromResultStoreTarget(input *api.Target) { |
| *t = Target{ |
| Name: input.GetName(), |
| ID: input.GetId().TargetId, |
| InvocationID: input.GetId().InvocationId, |
| Properties: propertiesToMap(input.Properties), |
| Status: statusFromResultStoreStatus(input.StatusAttributes.Status), |
| StartTime: protoTimestampToTime(input.Timing.StartTime), |
| Duration: protoDurationToDuration(input.Timing.Duration), |
| } |
| } |
| |
| // ConfiguredTarget maps to a ResultStore ConfiguredTarget. See full docs at: |
| // https://github.com/googleapis/googleapis/blob/master/google/devtools/resultstore/v2/configured_target.proto |
| type ConfiguredTarget struct { |
| Name string |
| ConfigID string |
| InvocationID string |
| TargetID string |
| Properties map[string]string |
| Status Status |
| StartTime time.Time |
| Duration time.Duration |
| } |
| |
| func (t ConfiguredTarget) ToResultStoreConfiguredTarget() *api.ConfiguredTarget { |
| return &api.ConfiguredTarget{ |
| Id: &api.ConfiguredTarget_Id{ |
| InvocationId: t.InvocationID, |
| TargetId: t.TargetID, |
| ConfigurationId: t.ConfigID, |
| }, |
| StatusAttributes: &api.StatusAttributes{ |
| Status: t.Status.ToResultStoreStatus(), |
| }, |
| Timing: &api.Timing{ |
| StartTime: timeToProtoTimestamp(t.StartTime), |
| Duration: durationToProtoDuration(t.Duration), |
| }, |
| Properties: mapToProperties(t.Properties), |
| } |
| } |
| |
| func (t *ConfiguredTarget) FromResultStoreConfiguredTarget(input *api.ConfiguredTarget) { |
| *t = ConfiguredTarget{ |
| Name: input.GetName(), |
| ConfigID: input.GetId().ConfigurationId, |
| InvocationID: input.GetId().InvocationId, |
| TargetID: input.GetId().TargetId, |
| Status: statusFromResultStoreStatus(input.StatusAttributes.Status), |
| Properties: propertiesToMap(input.Properties), |
| StartTime: protoTimestampToTime(input.Timing.StartTime), |
| Duration: protoDurationToDuration(input.Timing.Duration), |
| } |
| } |
| |
| // TestAction maps to a ResultStore Action with a child TestAction. See full docs at: |
| // https://github.com/googleapis/googleapis/blob/master/google/devtools/resultstore/v2/action.proto |
| type TestAction struct { |
| Name string |
| ID string |
| InvocationID string |
| TargetID string |
| ConfigID string |
| TestSuite string |
| TestLogURI string |
| StartTime time.Time |
| Duration time.Duration |
| Status Status |
| } |
| |
| func (a TestAction) ToResultStoreAction() *api.Action { |
| return &api.Action{ |
| Name: a.Name, |
| Id: &api.Action_Id{ |
| InvocationId: a.InvocationID, |
| TargetId: a.TargetID, |
| ConfigurationId: a.ConfigID, |
| ActionId: "test", |
| }, |
| StatusAttributes: &api.StatusAttributes{ |
| Status: a.Status.ToResultStoreStatus(), |
| }, |
| ActionType: &api.Action_TestAction{ |
| TestAction: &api.TestAction{ |
| TestSuite: &api.TestSuite{ |
| SuiteName: a.TestSuite, |
| }, |
| }, |
| }, |
| Files: []*api.File{ |
| &api.File{ |
| Uid: "test.log", |
| Uri: a.TestLogURI, |
| }, |
| }, |
| Timing: &api.Timing{ |
| StartTime: timeToProtoTimestamp(a.StartTime), |
| Duration: durationToProtoDuration(a.Duration), |
| }, |
| } |
| } |
| |
| func (a *TestAction) FromResultStoreAction(input *api.Action) { |
| testAction, ok := input.ActionType.(*api.Action_TestAction) |
| if !ok { |
| panic("action is not a test action") |
| } |
| |
| *a = TestAction{ |
| InvocationID: input.GetId().InvocationId, |
| TargetID: input.GetId().TargetId, |
| ConfigID: input.GetId().ConfigurationId, |
| ID: input.GetId().ActionId, |
| TestSuite: testAction.TestAction.TestSuite.SuiteName, |
| TestLogURI: lookupFileURI(input.Files, "test.log"), |
| Status: statusFromResultStoreStatus(input.StatusAttributes.Status), |
| StartTime: protoTimestampToTime(input.Timing.StartTime), |
| Duration: protoDurationToDuration(input.Timing.Duration), |
| } |
| } |
| |
| type Status string |
| |
| const ( |
| Building = Status("BUILDING") |
| Passed = Status("PASSED") |
| Failed = Status("FAILED") |
| TimedOut = Status("TIMED_OUT") |
| Testing = Status("TESTING") |
| Unknown = Status("Unknown") |
| ) |
| |
| func (r Status) ToResultStoreStatus() api.Status { |
| switch r { |
| case Building: |
| return api.Status_BUILDING |
| case Failed: |
| return api.Status_FAILED |
| case Passed: |
| return api.Status_PASSED |
| case Testing: |
| return api.Status_TESTING |
| case TimedOut: |
| return api.Status_TIMED_OUT |
| default: |
| log.Printf("unknown test status: %v", r) |
| return api.Status_UNKNOWN |
| } |
| } |
| |
| func statusFromResultStoreStatus(input api.Status) Status { |
| switch input { |
| case api.Status_BUILDING: |
| return Building |
| case api.Status_PASSED: |
| return Passed |
| case api.Status_FAILED: |
| return Failed |
| case api.Status_TESTING: |
| return Testing |
| case api.Status_TIMED_OUT: |
| return TimedOut |
| default: |
| return Unknown |
| } |
| } |