blob: 1e4c4b1f74c2eca5c5c228a1d2e26f0de48ab27d [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 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
}