Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

Feature/enrich app config #726

Merged
merged 7 commits into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ message ApplicationConfiguration {
app.coronawarn.server.common.protocols.internal.ApplicationVersionConfiguration appVersion = 5;

app.coronawarn.server.common.protocols.internal.AppFeatures appFeatures = 6;

repeated string supportedCountries = 7;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,17 @@
import app.coronawarn.server.common.protocols.internal.AppFeatures;
import app.coronawarn.server.common.protocols.internal.ApplicationConfiguration;
import app.coronawarn.server.common.protocols.internal.ApplicationConfiguration.Builder;
import app.coronawarn.server.common.protocols.internal.ApplicationVersionConfiguration;
import app.coronawarn.server.common.protocols.internal.ApplicationVersionInfo;
import app.coronawarn.server.common.protocols.internal.SemanticVersion;
import app.coronawarn.server.services.distribution.config.DistributionServiceConfig;
import app.coronawarn.server.services.distribution.config.DistributionServiceConfig.AppVersions;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;



/**
* Provides the application configuration needed for the mobile client. Contains all necessary sub-configs, including:
* <ul>
Expand Down Expand Up @@ -54,9 +61,47 @@ public class ApplicationConfigurationPublicationConfig {
@Bean
public ApplicationConfiguration createMasterConfiguration(DistributionServiceConfig distributionServiceConfig)
throws UnableToLoadFileException {

return YamlLoader.loadYamlIntoProtobufBuilder(MASTER_FILE, Builder.class)
.setAppFeatures(
AppFeatures.newBuilder().addAllAppFeatures(distributionServiceConfig.getAppFeaturesProto()).build())
AppFeatures.newBuilder().addAllAppFeatures(distributionServiceConfig.getAppFeaturesProto()).build()
)
.addAllSupportedCountries(List.of(distributionServiceConfig.getSupportedCountries()))
.setAppVersion(buildApplicationVersionConfiguration(distributionServiceConfig))
.build();
}

/**
* Fetches the master configuration as a ApplicationConfiguration instance.
*
* @return test.
*/
public ApplicationVersionConfiguration buildApplicationVersionConfiguration(
DistributionServiceConfig distributionServiceConfig) {
AppVersions appVersions = distributionServiceConfig.getAppVersions();
return ApplicationVersionConfiguration.newBuilder()
.setAndroid(buildApplicationVersionInfo(appVersions.getLatestAndroid(), appVersions.getMinAndroid()))
.setIos(buildApplicationVersionInfo(appVersions.getLatestIos(), appVersions.getMinIos()))
.build();
}

private ApplicationVersionInfo buildApplicationVersionInfo(String latestVersion, String minVersion) {
return ApplicationVersionInfo.newBuilder()
.setLatest(buildSemanticVersion(latestVersion))
.setMin(buildSemanticVersion(minVersion))
.build();
}

private SemanticVersion buildSemanticVersion(String version) {
return SemanticVersion.newBuilder()
.setMajor(getSemanticVersionNumber(version, 0))
.setMinor(getSemanticVersionNumber(version, 1))
.setPatch(getSemanticVersionNumber(version, 2))
.build();
}

private int getSemanticVersionNumber(String version, int position) {
String[] items = version.split("\\.");
return Integer.valueOf(items[position]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
package app.coronawarn.server.services.distribution.config;

import app.coronawarn.server.common.protocols.external.exposurenotification.SignatureInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.constraints.Max;
Expand All @@ -47,6 +49,7 @@ public class DistributionServiceConfig {
private static final String ALGORITHM_OID_REGEX = "^[0-9]+[\\.[0-9]+]*$";
private static final String BUNDLE_REGEX = "^[a-z-]+[\\.[a-z-]+]*$";
private static final String PRIVATE_KEY_REGEX = "^(classpath:|file:[/]+)[a-zA-Z0-9_-]+[/[a-zA-Z0-9_-]+]*(.pem)?$";
private static final String SUPPORTED_COUNTRY_CODES_REGEX = "^([a-zA-Z]{2}(\\,*[a-zA-Z]{2})*)$";

private Paths paths;
private TestData testData;
Expand All @@ -71,6 +74,9 @@ public class DistributionServiceConfig {
private Api api;
private ObjectStore objectStore;
private List<AppFeature> appFeatures;
@Pattern(regexp = SUPPORTED_COUNTRY_CODES_REGEX)
private String supportedCountries;
private AppVersions appVersions;

public Paths getPaths() {
return paths;
Expand Down Expand Up @@ -185,8 +191,26 @@ public void setAppFeatures(List<AppFeature> appFeatures) {
this.appFeatures = appFeatures;
}

public String[] getSupportedCountries() {
return supportedCountries.split(",");
}

public void setSupportedCountries(String supportedCountries) {
this.supportedCountries = supportedCountries;
}

public AppVersions getAppVersions() {
return appVersions;
}

public void setAppVersions(AppVersions appVersions) {
this.appVersions = appVersions;
}


/**
* Get app features as list of protobuf objects.
*
* @return list of {@link app.coronawarn.server.common.protocols.internal.AppFeature}
*/
public List<app.coronawarn.server.common.protocols.internal.AppFeature> getAppFeaturesProto() {
Expand Down Expand Up @@ -583,4 +607,46 @@ public void setValue(Integer value) {
this.value = value;
}
}

public static class AppVersions {

private String latestIos;
private String minIos;
private String latestAndroid;
private String minAndroid;


public String getLatestIos() {
return latestIos;
}

public void setLatestIos(String latestIos) {
this.latestIos = latestIos;
}

public String getMinIos() {
return minIos;
}

public void setMinIos(String minIos) {
this.minIos = minIos;
}

public String getLatestAndroid() {
return latestAndroid;
}

public void setLatestAndroid(String latestAndroid) {
this.latestAndroid = latestAndroid;
}

public String getMinAndroid() {
return minAndroid;
}

public void setMinAndroid(String minAndroid) {
this.minAndroid = minAndroid;
}

}
}
11 changes: 9 additions & 2 deletions services/distribution/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,14 @@ services:
force-update-keyfiles: ${FORCE_UPDATE_KEYFILES:false}

app-features:
- label: isPlausibleDeniabilityActive
value: ${PLAUSIBLE_DENIABILITY_ACTIVE:1}
- label: reserved
value: ${reserved:1}
supported-countries: ${SUPPORTED_COUNTRIES:DE}
app-versions:
latest-ios: ${LATEST_IOS_VERSION:0.8.2}
min-ios: ${MIN_IOS_VERSION:0.5.0}
latest-android: ${LATEST_IOS_VERSION:1.0.4}
min-android: ${MIN_ANDROID_VERSION:1.0.4}

spring:
main:
Expand All @@ -98,6 +104,7 @@ spring:

datasource:
driver-class-name: org.postgresql.Driver

url: jdbc:postgresql://${POSTGRESQL_SERVICE_HOST}:${POSTGRESQL_SERVICE_PORT}/${POSTGRESQL_DATABASE}?ssl=true&sslmode=verify-full&sslrootcert=${SSL_POSTGRES_CERTIFICATE_PATH}&sslcert=${SSL_DISTRIBUTION_CERTIFICATE_PATH}&sslkey=${SSL_DISTRIBUTION_PRIVATE_KEY_PATH}
username: ${POSTGRESQL_USER_DISTRIBUTION:local_setup_distribution}
password: ${POSTGRESQL_PASSWORD_DISTRIBUTION:local_setup_distribution}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,3 @@ min-risk-score: 11
attenuation-duration: !include attenuation-duration.yaml
risk-score-classes: !include risk-score-classification.yaml
exposure-config: !include exposure-config.yaml
app-version: !include app-version-config.yaml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,128 @@
import static org.assertj.core.api.Assertions.assertThat;

import app.coronawarn.server.common.protocols.internal.ApplicationVersionConfiguration;
import app.coronawarn.server.services.distribution.assembly.appconfig.UnableToLoadFileException;
import app.coronawarn.server.services.distribution.assembly.appconfig.YamlLoader;
import app.coronawarn.server.services.distribution.assembly.appconfig.ApplicationConfigurationPublicationConfig;
import app.coronawarn.server.services.distribution.assembly.appconfig.validation.ValidationError.ErrorType;
import app.coronawarn.server.services.distribution.config.DistributionServiceConfig;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.stream.Stream;

@EnableConfigurationProperties(value = DistributionServiceConfig.class)
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {DistributionServiceConfig.class,ApplicationConfigurationPublicationConfig.class},
initializers = ConfigFileApplicationContextInitializer.class)

class ApplicationVersionConfigurationValidatorTest {

private static final ValidationResult SUCCESS = new ValidationResult();

@Test
void succeedsIfLatestEqualsMin() throws UnableToLoadFileException {
var validator = buildValidator("app-version/latest-equals-min.yaml");
private ConfigurationValidator buildValidator(DistributionServiceConfig distributionServiceConfig) {
ApplicationVersionConfiguration appConfig = applicationConfigurationPublicationConfig
.buildApplicationVersionConfiguration(distributionServiceConfig);
return new ApplicationVersionConfigurationValidator(appConfig);
}

@Autowired
DistributionServiceConfig distributionServiceConfig;

@Autowired
ApplicationConfigurationPublicationConfig applicationConfigurationPublicationConfig;

@ParameterizedTest
@MethodSource("setSemanticVersionsLatestHigherThanMin")
void succeedsIfLatestHigherThanMin(String latestAndroid, String minAndroid, String latestIos, String minIos) {
distributionServiceConfig.getAppVersions().setLatestAndroid(latestAndroid);
distributionServiceConfig.getAppVersions().setMinAndroid(minAndroid);
distributionServiceConfig.getAppVersions().setLatestIos(latestIos);
distributionServiceConfig.getAppVersions().setMinIos(minIos);

var validator = buildValidator(distributionServiceConfig);
assertThat(validator.validate()).isEqualTo(SUCCESS);
}
private static Stream<Arguments> setSemanticVersionsLatestHigherThanMin() {
return Stream.of(
Arguments.of("2.0.0", "1.0.0", "1.0.0", "1.0.0"),
Arguments.of("0.2.0", "0.1.0", "1.0.0", "1.0.0"),
Arguments.of("0.0.2", "0.0.1", "1.0.0", "1.0.0"),
Arguments.of("1.0.0", "1.0.0", "2.0.0", "1.0.0"),
Arguments.of("1.0.0", "1.0.0", "0.2.0", "0.1.0"),
Arguments.of("1.0.0", "1.0.0", "0.0.2", "0.0.1")
);
}

@ParameterizedTest
@MethodSource("setSemanticVersionsLatestEqualsMin")
void succeedsWithEqualSemanticVersion(String latestAndroid, String minAndroid, String latestIos, String minIos) {

@Test
void succeedsIfLatestHigherThanMin() throws UnableToLoadFileException {
var validator = buildValidator("app-version/latest-higher-than-min.yaml");
distributionServiceConfig.getAppVersions().setLatestAndroid(latestAndroid);
distributionServiceConfig.getAppVersions().setMinAndroid(minAndroid);
distributionServiceConfig.getAppVersions().setLatestIos(latestIos);
distributionServiceConfig.getAppVersions().setMinIos(minIos);

var validator = buildValidator(distributionServiceConfig);
assertThat(validator.validate()).isEqualTo(SUCCESS);
}

@Test
void failsIfLatestLowerThanMin() throws UnableToLoadFileException {
var validator = buildValidator("app-version/latest-lower-than-min.yaml");
assertThat(validator.validate()).isEqualTo(
buildExpectedResult(buildError(CONFIG_PREFIX + "ios.[latest|min]", "1.2.2", ErrorType.MIN_GREATER_THAN_MAX)));
private static Stream<Arguments> setSemanticVersionsLatestEqualsMin() {
return Stream.of(
Arguments.of("1.0.0", "1.0.0", "1.0.0", "1.0.0"),
Arguments.of("0.1.0", "0.1.0", "1.0.0", "1.0.0"),
Arguments.of("0.0.1", "0.0.1", "1.0.0", "1.0.0"),
Arguments.of("1.0.0", "1.0.0", "1.0.0", "1.0.0"),
Arguments.of("1.0.0", "1.0.0", "0.1.0", "0.1.0"),
Arguments.of("1.0.0", "1.0.0", "0.0.1", "0.0.1")
);
}

@ParameterizedTest
@MethodSource("setSemanticVersionsLatestLowerThanMinAndroid")
void failsWithBadSemanticVersionAndroid(String latestAndroid, String minAndroid, String latestIos, String minIos) {

distributionServiceConfig.getAppVersions().setLatestAndroid(latestAndroid);
distributionServiceConfig.getAppVersions().setMinAndroid(minAndroid);
distributionServiceConfig.getAppVersions().setLatestIos(latestIos);
distributionServiceConfig.getAppVersions().setMinIos(minIos);

var validator = buildValidator(distributionServiceConfig);

assertThat(validator.validate()).isEqualTo(buildExpectedResult(buildError(CONFIG_PREFIX + "android.[latest|min]", minAndroid, ErrorType.MIN_GREATER_THAN_MAX)));
}
private static Stream<Arguments> setSemanticVersionsLatestLowerThanMinAndroid() {
return Stream.of(
Arguments.of("1.0.0", "2.0.0", "1.0.0", "1.0.0"),
Arguments.of("1.0.0", "1.1.0", "1.0.0", "1.0.0"),
Arguments.of("1.0.0", "1.0.1", "1.0.0", "1.0.0")
);
}

@ParameterizedTest
@MethodSource("setSemanticVersionsLatestLowerThanMinIos")
void failsWithBadSemanticVersionIos(String latestAndroid, String minAndroid, String latestIos, String minIos) {

distributionServiceConfig.getAppVersions().setLatestAndroid(latestAndroid);
distributionServiceConfig.getAppVersions().setMinAndroid(minAndroid);
distributionServiceConfig.getAppVersions().setLatestIos(latestIos);
distributionServiceConfig.getAppVersions().setMinIos(minIos);

var validator = buildValidator(distributionServiceConfig);

assertThat(validator.validate()).isEqualTo(buildExpectedResult(buildError(CONFIG_PREFIX + "ios.[latest|min]", minIos, ErrorType.MIN_GREATER_THAN_MAX)));
}
private static Stream<Arguments> setSemanticVersionsLatestLowerThanMinIos() {
return Stream.of(

private ConfigurationValidator buildValidator(String filePath) throws UnableToLoadFileException {
var configBuilder = YamlLoader.loadYamlIntoProtobufBuilder(filePath, ApplicationVersionConfiguration.Builder.class);
return new ApplicationVersionConfigurationValidator(configBuilder.build());
Arguments.of("1.0.0", "1.0.0", "1.0.0", "2.0.0"),
Arguments.of("1.0.0", "1.0.0", "1.0.0", "1.1.0"),
Arguments.of("1.0.0", "1.0.0", "1.0.0", "1.0.1")
);
}
}
18 changes: 0 additions & 18 deletions services/distribution/src/test/resources/app-version/all_ok.yaml

This file was deleted.

Loading