| // 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" |
| "log" |
| |
| "github.com/google/uuid" |
| api "google.golang.org/genproto/googleapis/devtools/resultstore/v2" |
| "google.golang.org/genproto/protobuf/field_mask" |
| ) |
| |
| // Service implements the ResultStore Upload API. See |
| // https://github.com/googleapis/googleapis/tree/master/google/devtools/resultstore/v2 for |
| // more details on the proto and gRPC libraries. |
| // |
| // Service methods generate UUIDs for certain proto.Message fields. If the provided |
| // Context contains a non-empty string value for TestUUIDContextKey, that value will be |
| // used instead. |
| // |
| // Service methods require an Invocation's auth token to be set in the provided Context. |
| // This can be done by calling: `SetAuthToken(ctx, "auth-token")`. |
| type Service interface { |
| // CreateInvocation creates an Invocation in ResultStore. This must be called before |
| // any other "Create" methods, since all resources belong to an Invocation. |
| CreateInvocation(context.Context, *Invocation) (*Invocation, error) |
| |
| // CreateConfiguration creates a new Configuration. Configurations typically represent |
| // build or test environments. |
| CreateConfiguration(context.Context, *Configuration, string) (*Configuration, error) |
| |
| // CreateTarget creates a new build or test target for the Invocation with the given |
| // name. |
| CreateTarget(context.Context, *Target, string) (*Target, error) |
| |
| // CreateConfiguredTarget creates a new ConfiguredTarget for the Target with the given |
| // name. ConfiguredTargets represent targets executing with a specific Configuration. |
| CreateConfiguredTarget(context.Context, *ConfiguredTarget, string) (*ConfiguredTarget, error) |
| |
| // CreateTestAction creates a new Action for the ConfiguredTarget with the given name. |
| CreateTestAction(context.Context, *TestAction, string) (*TestAction, error) |
| |
| // UpdateTestAction patches the start time, duration and status of a TestAction. |
| UpdateTestAction(context.Context, *TestAction) (*TestAction, error) |
| |
| // UpdateConfiguredTarget patches the start time, duration and status of a |
| // ConfiguredTarget. |
| UpdateConfiguredTarget(context.Context, *ConfiguredTarget) (*ConfiguredTarget, error) |
| |
| // UpdateTarget patches the start time, duration and status of a Target. |
| UpdateTarget(context.Context, *Target) (*Target, error) |
| |
| // UpdateTarget patches the start time, duration and status of a Target. |
| UpdateInvocation(context.Context, *Invocation) (*Invocation, error) |
| |
| // FinishConfiguredTarget closes a ConfiguredTarget for editing. |
| FinishConfiguredTarget(context.Context, string) error |
| |
| // FinishTarget closes a Target for editing. |
| FinishTarget(context.Context, string) error |
| |
| // FinishInvocation closes an Invocation for editing. |
| FinishInvocation(context.Context, string) error |
| } |
| |
| // New creates a new Service. Set useFakeUUIDs to true to use fake UUIDs for |
| // testing. authToken is the authorization token to use for the invocation. The same |
| // token must be used in all requests to modify a single invocation. |
| func New(client api.ResultStoreUploadClient) Service { |
| return &service{client: client} |
| } |
| |
| // The default Service implementation. |
| type service struct { |
| client api.ResultStoreUploadClient |
| } |
| |
| // uuid generates an RFC-4122 compliant Version 4 UUID. If the provided Context contains |
| // a non-empty string value for TestUUIDContextKey, that value will be used instead. If |
| // there was an error when reading the UUID from the context, a message is logged |
| // describing the error and a new UUID is generated. |
| func (s *service) uuid(ctx context.Context) string { |
| value, err := TestUUID(ctx) |
| |
| if err != nil { |
| log.Println(err) |
| return uuid.New().String() |
| } |
| |
| if value == "" { |
| return uuid.New().String() |
| } |
| |
| return value |
| } |
| |
| func (s *service) CreateInvocation(ctx context.Context, invocation *Invocation) (*Invocation, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.CreateInvocation(ctx, &api.CreateInvocationRequest{ |
| RequestId: s.uuid(ctx), |
| AuthorizationToken: authToken, |
| InvocationId: s.uuid(ctx), |
| Invocation: invocation.ToResultStoreInvocation(), |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(Invocation) |
| output.FromResultStoreInvocation(res) |
| return output, nil |
| } |
| |
| func (s *service) CreateConfiguration(ctx context.Context, config *Configuration, invocationName string) (*Configuration, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.CreateConfiguration(ctx, &api.CreateConfigurationRequest{ |
| RequestId: s.uuid(ctx), |
| AuthorizationToken: authToken, |
| Parent: invocationName, |
| ConfigId: config.ID, |
| Configuration: config.ToResultStoreConfiguration(), |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(Configuration) |
| output.FromResultStoreConfiguration(res) |
| return output, nil |
| } |
| |
| func (s *service) CreateTarget(ctx context.Context, target *Target, invocationName string) (*Target, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.CreateTarget(ctx, &api.CreateTargetRequest{ |
| RequestId: s.uuid(ctx), |
| AuthorizationToken: authToken, |
| Parent: invocationName, |
| TargetId: target.ID, |
| Target: target.ToResultStoreTarget(), |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(Target) |
| output.FromResultStoreTarget(res) |
| return output, nil |
| } |
| |
| func (s *service) CreateConfiguredTarget(ctx context.Context, configTarget *ConfiguredTarget, targetName string) (*ConfiguredTarget, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.CreateConfiguredTarget(ctx, &api.CreateConfiguredTargetRequest{ |
| AuthorizationToken: authToken, |
| RequestId: s.uuid(ctx), |
| Parent: targetName, |
| ConfigId: configTarget.ConfigID, |
| ConfiguredTarget: configTarget.ToResultStoreConfiguredTarget(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| output := new(ConfiguredTarget) |
| output.FromResultStoreConfiguredTarget(res) |
| return output, nil |
| } |
| |
| func (s *service) CreateTestAction(ctx context.Context, action *TestAction, configTargetName string) (*TestAction, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.CreateAction(ctx, &api.CreateActionRequest{ |
| AuthorizationToken: authToken, |
| RequestId: s.uuid(ctx), |
| Parent: configTargetName, |
| ActionId: action.ID, |
| Action: action.ToResultStoreAction(), |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(TestAction) |
| output.FromResultStoreAction(res) |
| return output, nil |
| } |
| |
| // UpdateTestAction updates the duration and status of a previously started TestAction. |
| func (s *service) UpdateTestAction(ctx context.Context, action *TestAction) (*TestAction, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.UpdateAction(ctx, &api.UpdateActionRequest{ |
| AuthorizationToken: authToken, |
| Action: action.ToResultStoreAction(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(TestAction) |
| output.FromResultStoreAction(res) |
| return output, nil |
| } |
| |
| // UpdateConfiguredTarget updates the duration and status of a previously started |
| // UpdateConfigured. |
| func (s *service) UpdateConfiguredTarget(ctx context.Context, configTarget *ConfiguredTarget) (*ConfiguredTarget, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.UpdateConfiguredTarget(ctx, &api.UpdateConfiguredTargetRequest{ |
| AuthorizationToken: authToken, |
| ConfiguredTarget: configTarget.ToResultStoreConfiguredTarget(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(ConfiguredTarget) |
| output.FromResultStoreConfiguredTarget(res) |
| return output, nil |
| } |
| |
| // UpdateTarget updates the duration and status of a previously started Target. |
| func (s *service) UpdateTarget(ctx context.Context, target *Target) (*Target, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.UpdateTarget(ctx, &api.UpdateTargetRequest{ |
| AuthorizationToken: authToken, |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| Target: target.ToResultStoreTarget(), |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(Target) |
| output.FromResultStoreTarget(res) |
| return output, nil |
| } |
| |
| // UpdateInvocation updates the duration and status of a previously started Invocation. |
| func (s *service) UpdateInvocation(ctx context.Context, invocation *Invocation) (*Invocation, error) { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| res, err := s.client.UpdateInvocation(ctx, &api.UpdateInvocationRequest{ |
| AuthorizationToken: authToken, |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| Invocation: invocation.ToResultStoreInvocation(), |
| }) |
| if err != nil { |
| return nil, err |
| } |
| output := new(Invocation) |
| output.FromResultStoreInvocation(res) |
| return output, nil |
| } |
| |
| // FinishConfiguredTarget closes a ConfiguredTarget for editing. |
| func (s *service) FinishConfiguredTarget(ctx context.Context, name string) error { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return err |
| } |
| |
| _, err = s.client.FinishConfiguredTarget(ctx, &api.FinishConfiguredTargetRequest{ |
| AuthorizationToken: authToken, |
| Name: name, |
| }) |
| return err |
| } |
| |
| // FinishTarget closes a Target for editing. |
| func (s *service) FinishTarget(ctx context.Context, name string) error { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return err |
| } |
| |
| _, err = s.client.FinishTarget(ctx, &api.FinishTargetRequest{ |
| AuthorizationToken: authToken, |
| Name: name, |
| }) |
| return err |
| } |
| |
| // FinishInvocation closes an Invocation for editing. |
| func (s *service) FinishInvocation(ctx context.Context, name string) error { |
| authToken, err := AuthToken(ctx) |
| if err != nil { |
| return err |
| } |
| |
| _, err = s.client.FinishInvocation(ctx, &api.FinishInvocationRequest{ |
| AuthorizationToken: authToken, |
| Name: name, |
| }) |
| return err |
| } |