summaryrefslogtreecommitdiffstats
path: root/hosted-api/src/main/java/ai/vespa/hosted/api/TestConfig.java
blob: d77dfc23577041c32c0796315075c1508d2db951 (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
136
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.hosted.api;

import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.SlimeUtils;

import java.net.URI;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.Objects.requireNonNull;

/**
 * Config required to run a functional or verification test of a Vespa deployment.
 *
 * @author jvenstad
 */
public class TestConfig {

    private final ApplicationId application;
    private final ZoneId zone;
    private final SystemName system;
    private final boolean isCI;
    private final String platform;
    private final long revision;
    private final Instant deployedAt;
    private final Map<ZoneId, Map<String, URI>> deployments;
    private final Map<ZoneId, List<String>> contentClusters;

    public TestConfig(ApplicationId application, ZoneId zone, SystemName system, boolean isCI,
                      String platform, long revision, Instant deployedAt,
                      Map<ZoneId, Map<String, URI>> deployments, Map<ZoneId, List<String>> contentClusters) {
        if ( ! deployments.containsKey(zone))
            throw new IllegalArgumentException("Config must contain a deployment for its zone, but only does for " + deployments.keySet());
        this.application = requireNonNull(application);
        this.zone = requireNonNull(zone);
        this.system = requireNonNull(system);
        this.isCI = isCI;
        this.platform = platform;
        this.revision = revision;
        this.deployedAt = deployedAt;
        this.deployments = deployments.entrySet().stream()
                                      .collect(Collectors.toUnmodifiableMap(entry -> entry.getKey(),
                                                                            entry -> Map.copyOf(entry.getValue())));
        this.contentClusters = contentClusters.entrySet().stream()
                                              .collect(Collectors.toUnmodifiableMap(entry -> entry.getKey(),
                                                                                    entry -> List.copyOf(entry.getValue())));
    }

    /**
     * Parses the given test config JSON and returns a new config instance.
     *
     * If the given JSON has a "localEndpoints" element, a config object with default values
     * is returned, using {@link #fromEndpointsOnly}. Otherwise, all config attributes are parsed.
     */
    public static TestConfig fromJson(byte[] jsonBytes) {
        Inspector config = SlimeUtils.jsonToSlime(jsonBytes).get();
        if (config.field("localEndpoints").valid())
            return TestConfig.fromEndpointsOnly(toClusterMap(config.field("localEndpoints")));

        ApplicationId application = ApplicationId.fromSerializedForm(config.field("application").asString());
        ZoneId zone = ZoneId.from(config.field("zone").asString());
        SystemName system = SystemName.from(config.field("system").asString());
        boolean isCI = config.field("isCI").asBool();
        String platform = config.field("platform").asString();
        long revision = config.field("revision").asLong();
        Instant deployedAt = Instant.ofEpochMilli(config.field("deployedAt").asLong());
        Map<ZoneId, Map<String, URI>> deployments = new HashMap<>();
        config.field("zoneEndpoints").traverse((ObjectTraverser) (zoneId, clustersObject) -> {
            deployments.put(ZoneId.from(zoneId), toClusterMap(clustersObject));
        });
        Map<ZoneId, List<String>> contentClusters = new HashMap<>();
        config.field("clusters").traverse(((ObjectTraverser) (zoneId, clustersArray) -> {
            List<String> clusters = new ArrayList<>();
            clustersArray.traverse((ArrayTraverser) (__, cluster) -> clusters.add(cluster.asString()));
            contentClusters.put(ZoneId.from(zoneId), clusters);
        }));
        return new TestConfig(application, zone, system, isCI, platform, revision, deployedAt, deployments, contentClusters);
    }

    static Map<String, URI> toClusterMap(Inspector clustersObject) {
        Map<String, URI> clusters = new HashMap<>();
        clustersObject.traverse((ObjectTraverser) (cluster, uri) -> clusters.put(cluster, URI.create(uri.asString())));
        return clusters;
    }

    /**
     * Returns a TestConfig with default values for everything except the endpoints.
     * @param endpoints the endpoint for each of the containers specified in services.xml, by container id
     */
    public static TestConfig fromEndpointsOnly(Map<String, URI> endpoints) {
        return new TestConfig(ApplicationId.defaultId(),
                              ZoneId.defaultId(),
                              SystemName.dev,
                              false,
                              "",
                              0,
                              Instant.EPOCH,
                              Map.of(ZoneId.defaultId(), endpoints),
                              Map.of());
    }

    /** Returns the full id of the application to test. */
    public ApplicationId application() { return application; }

    /** Returns the zone of the deployment to test. */
    public ZoneId zone() { return zone; }

    /** Returns the Vespa cloud system this is run against. */
    public SystemName system() { return system; }

    /** Returns whether this is a CI job (or a local developer environment). */
    public boolean isCI() { return isCI; }

    /** Returns an immutable view of deployments, per zone, of the application to test. */
    public Map<ZoneId, Map<String, URI>> deployments() { return deployments; }

    /** Returns an immutable view of content clusters, per zone, of the application to test. */
    public Map<ZoneId, List<String>> contentClusters() { return contentClusters; }

    public String platformVersion() { return platform; }

    public long applicationVersion() { return revision; }

    public Instant deployedAt() { return deployedAt; }

}