Implement platform management features
This commit is contained in:
@@ -25,6 +25,34 @@ type progressDistributionBuilder struct {
|
||||
payload []byte
|
||||
}
|
||||
|
||||
type failingBuildProgressStore struct {
|
||||
repo.Store
|
||||
buildJobs repo.ClientManagerBuildJobRepository
|
||||
}
|
||||
|
||||
func (store failingBuildProgressStore) ClientManagerBuildJobs() repo.ClientManagerBuildJobRepository {
|
||||
return store.buildJobs
|
||||
}
|
||||
|
||||
type failWhenDistributionJobRunningRepository struct {
|
||||
repo.ClientManagerBuildJobRepository
|
||||
jobs repo.JobRepository
|
||||
err error
|
||||
}
|
||||
|
||||
func (repository failWhenDistributionJobRunningRepository) List(filter domain.ClientManagerBuildJobFilter) ([]domain.ClientManagerBuildJob, error) {
|
||||
jobs, err := repository.jobs.List(domain.JobFilter{ServerInstanceID: filter.ServerInstanceID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, job := range jobs {
|
||||
if job.Capability == domain.JobCapabilityDistributionBuild && job.State == domain.JobStateRunning {
|
||||
return nil, repository.err
|
||||
}
|
||||
}
|
||||
return repository.ClientManagerBuildJobRepository.List(filter)
|
||||
}
|
||||
|
||||
func (builder captureDistributionBuilder) Readiness() (bool, string) {
|
||||
return true, ""
|
||||
}
|
||||
@@ -379,6 +407,49 @@ func TestCoreServiceProjectsPlatformBuilderProgressBeforeCompletion(t *testing.T
|
||||
completeDistributionBuild(t, svc, distribution, nil)
|
||||
}
|
||||
|
||||
func TestCoreServiceTerminalizesPlatformBuildWhenRunningProjectionFails(t *testing.T) {
|
||||
svc, session, instance := newDistributionTestFixture(t)
|
||||
const leakedDetail = "sensitive-builder-token /private/platform/build/input/auth-key"
|
||||
baseStore := svc.store
|
||||
svc.store = failingBuildProgressStore{
|
||||
Store: baseStore,
|
||||
buildJobs: failWhenDistributionJobRunningRepository{
|
||||
ClientManagerBuildJobRepository: baseStore.ClientManagerBuildJobs(),
|
||||
jobs: baseStore.Jobs(),
|
||||
err: errors.New(leakedDetail),
|
||||
},
|
||||
}
|
||||
|
||||
distribution, err := svc.GenerateRunDistributionForSession(session, domain.RunDistributionGenerateRequest{
|
||||
ServerInstanceID: instance.ID,
|
||||
TargetOS: "linux",
|
||||
TargetArch: "amd64",
|
||||
IdempotencyKey: "running-projection-failure-terminalizes",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("queue platform distribution: %v", err)
|
||||
}
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
job, jobErr := svc.GetJob(distribution.BuildJobID)
|
||||
updated, distributionErr := svc.store.RunDistributions().Get(distribution.ID)
|
||||
if jobErr != nil || distributionErr != nil {
|
||||
t.Fatalf("read failed build state: jobErr=%v distributionErr=%v", jobErr, distributionErr)
|
||||
}
|
||||
if isTerminalJobState(job.State) {
|
||||
if job.State != domain.JobStateFailed || updated.Status != domain.DistributionStatusFailed {
|
||||
t.Fatalf("projection failure did not end in failed state: job=%+v distribution=%+v", job, updated)
|
||||
}
|
||||
if strings.Contains(job.Progress.Message, "sensitive-builder-token") || strings.Contains(job.Progress.Message, "/private/") || strings.Contains(job.TerminalFingerprint, "sensitive-builder-token") {
|
||||
t.Fatalf("terminal build state leaked internal failure details: %+v", job)
|
||||
}
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
t.Fatal("platform build remained non-terminal after running projection failure")
|
||||
}
|
||||
|
||||
func TestCoreServiceDiscardsBuildCompletedAfterKeyReset(t *testing.T) {
|
||||
svc, session, instance := newDistributionTestFixture(t)
|
||||
inputs := make(chan domain.DistributionBuildInput, 1)
|
||||
|
||||
Reference in New Issue
Block a user