blob: 544218481de5f10377a176bc2b94e82f770e0358 [file] [log] [blame]
// 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
}
}