| // Copyright 2019 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 main |
| |
| import ( |
| "context" |
| "math/rand" |
| "time" |
| |
| "fuchsia.googlesource.com/infra/infra/resultstore" |
| "fuchsia.googlesource.com/infra/infra/resultstore/fields" |
| "github.com/google/uuid" |
| ) |
| |
| // Dummy test log URLs. |
| const ( |
| passingTestLogURL = "gs://fuchsia-infra-test/tilo_passed_test.log" |
| failingTestLogURL = "gs://fuchsia-infra-test/tilo_failed_test.log" |
| ) |
| |
| // simulator is used to simulate the execution of a collection of tests in ResultStore. |
| // The simulator is useful for the duration of a single invocation's lifetime. It is also |
| // assumed that the invocation takes place within a single test configuration. |
| type simulator struct { |
| client resultstore.UploadClient |
| configuration *resultstore.Configuration |
| invocation *resultstore.Invocation |
| random *rand.Rand |
| } |
| |
| func NewSimulator(ctx context.Context, client resultstore.UploadClient, projectID, configurationID string, seed int64) (*simulator, error) { |
| // Create the invocation for this Simulation. |
| startTime := time.Now() |
| invocation, err := client.CreateInvocation(ctx, &resultstore.Invocation{ |
| ProjectID: projectID, |
| ID: uuid.New().String(), |
| StartTime: startTime, |
| }) |
| if err != nil { |
| return nil, err |
| } |
| |
| invocation.StartTime = startTime |
| |
| // Create the environment for this Simulation. |
| configuration, err := client.CreateConfiguration(ctx, &resultstore.Configuration{ |
| ID: configurationID, |
| InvocationID: invocation.ID, |
| Properties: map[string]string{ |
| "a": "b", |
| "c": "d", |
| }, |
| }, invocation.Name) |
| if err != nil { |
| return nil, err |
| } |
| |
| return &simulator{ |
| client: client, |
| configuration: configuration, |
| invocation: invocation, |
| random: rand.New(rand.NewSource(seed)), |
| }, nil |
| } |
| |
| // Returns the URL to this simulator's Invocation in Result Store. |
| func (s *simulator) InvocationURL() string { |
| return resultstore.Staging.InvocationURL(s.invocation.ID) |
| } |
| |
| // End finishes this simulator's invocation. |
| func (s *simulator) End(ctx context.Context, status resultstore.Status) error { |
| s.invocation.Status = status |
| s.invocation.Duration = 10 * time.Minute |
| if _, err := s.client.UpdateInvocation(ctx, s.invocation, []string{ |
| fields.StatusAttributes, |
| fields.Duration, |
| }); err != nil { |
| return err |
| } |
| |
| return s.client.FinishInvocation(ctx, s.invocation.Name) |
| } |
| |
| // Test simulates the execution of a test with the given name. |
| func (s *simulator) Test(ctx context.Context, test string) (resultstore.Status, error) { |
| var status resultstore.Status |
| |
| // Create a test target for the test. |
| startTime := time.Now() |
| target, err := s.client.CreateTarget(ctx, &resultstore.Target{ |
| ID: &resultstore.TargetID{ |
| ID: test, |
| InvocationID: s.invocation.ID, |
| }, |
| StartTime: startTime, |
| }, s.invocation.Name) |
| if err != nil { |
| return resultstore.Unknown, err |
| } |
| |
| // Create a ConfiguredTarget for the target |
| configuredTarget, err := s.client.CreateConfiguredTarget(ctx, &resultstore.ConfiguredTarget{ |
| ID: &resultstore.ConfiguredTargetID{ |
| InvocationID: s.invocation.ID, |
| TargetID: target.ID.ID, |
| ConfigID: s.configuration.ID, |
| }, |
| StartTime: startTime, |
| }, target.Name) |
| if err != nil { |
| return resultstore.Unknown, err |
| } |
| |
| // Create a test action the configured target. |
| action, err := s.client.CreateTestAction(ctx, &resultstore.TestAction{ |
| ID: &resultstore.TestActionID{ |
| ID: "test", |
| InvocationID: s.invocation.ID, |
| TargetID: target.ID.ID, |
| ConfigID: configuredTarget.ID.ConfigID, |
| }, |
| StartTime: startTime, |
| }, configuredTarget.Name) |
| if err != nil { |
| return resultstore.Unknown, err |
| } |
| |
| // Update that the test has finished |
| const duration = 10 * time.Minute |
| logURL := passingTestLogURL |
| status = resultstore.Passed |
| if s.random.Intn(2) < 1 { |
| status = resultstore.Failed |
| logURL = failingTestLogURL |
| } |
| |
| action.StartTime = startTime |
| action.Duration = duration |
| action.TestLogURI = logURL |
| action.Status = status |
| if _, err := s.client.UpdateTestAction(ctx, action, []string{ |
| fields.Duration, |
| fields.Files, |
| fields.StatusAttributes, |
| }); err != nil { |
| return resultstore.Unknown, err |
| } |
| |
| configuredTarget.StartTime = startTime |
| configuredTarget.Duration = duration |
| configuredTarget.Status = status |
| if _, err := s.client.UpdateConfiguredTarget(ctx, configuredTarget, []string{ |
| fields.Duration, |
| fields.StatusAttributes, |
| }); err != nil { |
| return resultstore.Unknown, err |
| } |
| |
| target.StartTime = startTime |
| target.Duration = duration |
| target.Status = status |
| target.TestLogURI = logURL |
| if _, err := s.client.UpdateTarget(ctx, target, []string{ |
| fields.Duration, |
| fields.Files, |
| fields.StatusAttributes, |
| }); err != nil { |
| return resultstore.Unknown, err |
| } |
| |
| if err := s.client.FinishConfiguredTarget(ctx, configuredTarget.Name); err != nil { |
| return resultstore.Unknown, err |
| } |
| if err := s.client.FinishTarget(ctx, target.Name); err != nil { |
| return resultstore.Unknown, err |
| } |
| |
| return status, nil |
| } |