summaryrefslogtreecommitdiffstats
path: root/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java
blob: d1303c4a7ed0df79040f90488d66c37006451a1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.deployment;

import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.integration.ArtifactRepositoryMock;
import com.yahoo.vespa.hosted.controller.restapi.ContainerControllerTester;

import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;

import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.component;

/**
 * Create a build job for testing purposes. In most cases this should be constructed by calling
 * {@link DeploymentTester#jobCompletion(JobType)} or {@link ContainerControllerTester#jobCompletion(JobType)}.
 *
 * @author mpolden
 */

public class BuildJob {

    public static final long defaultBuildNumber = 42;

    private JobType job;
    private ApplicationId applicationId;
    private Optional<DeploymentJobs.JobError> jobError = Optional.empty();
    private Optional<SourceRevision> sourceRevision = Optional.of(DeploymentContext.defaultSourceRevision);
    private long projectId;
    private long buildNumber = defaultBuildNumber;

    private final Consumer<DeploymentJobs.JobReport> reportConsumer;
    private final ArtifactRepositoryMock artifactRepository;

    public BuildJob(Consumer<DeploymentJobs.JobReport> reportConsumer, ArtifactRepositoryMock artifactRepository) {
        Objects.requireNonNull(reportConsumer, "reportConsumer cannot be null");
        Objects.requireNonNull(artifactRepository, "artifactRepository cannot be null");
        this.reportConsumer = reportConsumer;
        this.artifactRepository = artifactRepository;
    }

    public BuildJob type(JobType job) {
        this.job = job;
        return this;
    }

    public BuildJob application(Application application) {
        if (application.projectId().isPresent())
            this.projectId = application.projectId().getAsLong();

        return application(application.id().defaultInstance());
    }

    public BuildJob application(ApplicationId applicationId) {
        this.applicationId = applicationId;
        return this;
    }

    public BuildJob error(DeploymentJobs.JobError jobError) {
        this.jobError = Optional.of(jobError);
        return this;
    }

    public BuildJob sourceRevision(SourceRevision sourceRevision) {
        this.sourceRevision = Optional.of(sourceRevision);
        return this;
    }

    public BuildJob buildNumber(long buildNumber) {
        this.buildNumber = requireBuildNumber(buildNumber);
        return this;
    }

    public BuildJob nextBuildNumber(int increment) {
        return buildNumber(buildNumber + requireBuildNumber(increment));
    }

    public BuildJob nextBuildNumber() {
        return nextBuildNumber(1);
    }

    public BuildJob projectId(long projectId) {
        this.projectId = projectId;
        return this;
    }

    public BuildJob success(boolean success) {
        this.jobError = success ? Optional.empty() : Optional.of(DeploymentJobs.JobError.unknown);
        return this;
    }

    public BuildJob unsuccessful() {
        return success(false);
    }

    /** Create a job report for this build job */
    public DeploymentJobs.JobReport report() {
        return job == component ? DeploymentJobs.JobReport.ofComponent(applicationId, projectId, buildNumber, jobError, sourceRevision.get())
                                : DeploymentJobs.JobReport.ofJob(applicationId, job, buildNumber, jobError);
    }

    /** Upload given application package to artifact repository as part of this job */
    public BuildJob uploadArtifact(ApplicationPackage applicationPackage) {
        Objects.requireNonNull(job, "job cannot be null");
        Objects.requireNonNull(applicationId, "applicationId cannot be null");
        if (job != component) {
            throw new IllegalStateException(job + " cannot upload artifact");
        }
        artifactRepository.put(applicationId, applicationPackage, ApplicationVersion.from(sourceRevision.get(), buildNumber).id());
        return this;
    }

    /** Send report for this build job to the controller */
    public void submit() {
        if (job == component &&
            !artifactRepository.contains(applicationId, ApplicationVersion.from(sourceRevision.get(), buildNumber).id())) {
            throw new IllegalStateException(job + " must upload artifact before reporting completion");
        }
        reportConsumer.accept(report());
    }

    private static long requireBuildNumber(long n) {
        if (n <= 0) {
            throw new IllegalArgumentException("Build number must be positive");
        }
        return n;
    }

}