| // Copyright (C) 2016 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package robotester |
| |
| import ( |
| "time" |
| |
| "android.googlesource.com/platform/tools/gpu/client/git" |
| "android.googlesource.com/platform/tools/gpu/framework/device" |
| "android.googlesource.com/platform/tools/gpu/framework/log" |
| "android.googlesource.com/platform/tools/gpu/framework/task" |
| "android.googlesource.com/platform/tools/gpu/tools/robotester/build" |
| "android.googlesource.com/platform/tools/gpu/tools/robotester/db" |
| "android.googlesource.com/platform/tools/gpu/tools/robotester/db/sql/storage" |
| "android.googlesource.com/platform/tools/gpu/tools/robotester/replay" |
| "android.googlesource.com/platform/tools/gpu/tools/robotester/service" |
| "android.googlesource.com/platform/tools/gpu/tools/robotester/sync" |
| "android.googlesource.com/platform/tools/gpu/tools/robotester/trace" |
| ) |
| |
| var ( |
| // The time between updates of the state. |
| updateStateInterval = time.Second * 5 |
| |
| // The time between git pull requests. |
| syncFrequency = time.Minute * 5 |
| ) |
| |
| // Run begins execution of the service using the specified config and database. |
| func Run(ctx log.Context, cfg service.Config, database *db.DB) error { |
| state := &service.State{ |
| Config: cfg, |
| DB: database, |
| Host: device.Host(ctx), |
| } |
| g, err := git.New(state.Config.Source) |
| if err != nil { |
| return err |
| } |
| state.Git = g |
| |
| // Check there are no local changes. |
| if !state.Config.IgnoreLocalChanges { |
| status, err := g.Status(ctx) |
| if err != nil { |
| return err |
| } |
| if !status.Clean() { |
| return ctx.V("Status", status).AsError("Project has local changes") |
| } |
| } |
| |
| // Register the host device. |
| if err := state.DB.AddDevices(ctx, state.Host); err != nil { |
| return ctx.V("Host", state.Host).WrapError(err, "Failed to add the host device to the database") |
| } |
| |
| // Find any tasks that were left in a running state. Change these to aborted. |
| tasks, err := state.DB.QueryTasks(ctx, db.TaskQuery{ |
| Status: db.Running, |
| Host: storage.DeviceID(&state.Host), |
| }) |
| if err != nil { |
| return err |
| } |
| for _, t := range tasks { |
| t.Status = db.Aborted |
| ctx.Warning().V("Task", t).Log("Changing task from state RUNNING -> ABORTED") |
| if err := state.DB.AddTasks(ctx, t); err != nil { |
| ctx.Fail(err, "Failed to update task") |
| } |
| } |
| return poll(ctx, state) |
| } |
| |
| func poll(ctx log.Context, state *service.State) error { |
| traceEvents := task.Events{} |
| replayEvents := task.Events{} |
| childContext, childCancel := task.WithCancel(ctx) |
| for { |
| // Wait for either the update interval, or service shutdown |
| if task.ShouldStop(ctx).TryWait(updateStateInterval) { |
| // service is shutting down |
| return task.StopReason(ctx) |
| } |
| if time.Since(state.LastSync) > syncFrequency { |
| // Always true on the first time through |
| if err := sync.Run(childContext, state); err != nil { |
| return err |
| } |
| } |
| if !state.Config.NoBuild { |
| if !state.HeadCL.SHA.IsValid() { |
| // No cl yet, do nothing |
| continue |
| } |
| status, err := build.GetStatus(childContext, state) |
| if err != nil { |
| return err |
| } |
| if status == db.InvalidStatus { |
| childCancel() |
| traceEvents.Wait(ctx) |
| replayEvents.Wait(ctx) |
| childContext, childCancel = task.WithCancel(ctx) |
| if err = build.Run(childContext, state).Result(); err != nil { |
| ctx.Fail(err, "build errored") |
| continue |
| } |
| if status, err = build.GetStatus(childContext, state); err != nil { |
| return err |
| } |
| } |
| if status != db.Success { |
| // not a successful build cl, do nothing else |
| continue |
| } |
| } |
| if err := trace.Run(childContext, state, &traceEvents); err != nil { |
| ctx.Fail(err, "trace errored") |
| } |
| if err := replay.Run(childContext, state, &replayEvents); err != nil { |
| ctx.Fail(err, "replay errored") |
| } |
| } |
| } |