Remove AppEngineServiceUtils (#2003)

The only method that is called from this class is setNumInstances. However we
don't current use `nomulus set_num_instances` anywhere. If we need to change
the number of instances, it is either done by updating appengine-web.xml, which
is deployed by Spinnaker, or doing it manually as a break-glass fix via gcloud
or on Pantheon.
This commit is contained in:
Lai Jiang 2023-04-21 10:11:12 -04:00 committed by GitHub
parent 1222f39aa4
commit a239a66359
9 changed files with 1 additions and 712 deletions

View file

@ -97,7 +97,6 @@ public final class RegistryTool {
.put("save_sql_credential", SaveSqlCredentialCommand.class)
.put("send_escrow_report_to_icann", SendEscrowReportToIcannCommand.class)
.put("set_database_migration_state", SetDatabaseMigrationStateCommand.class)
.put("set_num_instances", SetNumInstancesCommand.class)
.put("setup_ote", SetupOteCommand.class)
.put("uniform_rapid_suspension", UniformRapidSuspensionCommand.class)
.put("unlock_domain", UnlockDomainCommand.class)

View file

@ -144,8 +144,6 @@ interface RegistryToolComponent {
void inject(SendEscrowReportToIcannCommand command);
void inject(SetNumInstancesCommand command);
void inject(SetupOteCommand command);
void inject(UniformRapidSuspensionCommand command);

View file

@ -1,172 +0,0 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableSetMultimap.flatteningToImmutableSetMultimap;
import static google.registry.util.CollectionUtils.nullToEmpty;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.api.services.appengine.v1.Appengine;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryConfig.Config;
import google.registry.request.Action.Service;
import google.registry.util.AppEngineServiceUtils;
import java.io.IOException;
import java.util.List;
import javax.inject.Inject;
/** A command to set the number of instances for an App Engine service. */
@Parameters(
separators = " =",
commandDescription =
"Set the number of instances for a given service and version. "
+ "Note that this command only works for manual scaling service.")
final class SetNumInstancesCommand implements Command {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final ImmutableList<Service> ALL_DEPLOYED_SERVICES =
ImmutableList.copyOf(Service.values());
private static final ImmutableMap<String, Service> SERVICE_ID_TO_SERVICE =
Maps.uniqueIndex(ALL_DEPLOYED_SERVICES, Service::getServiceId);
@Parameter(
names = {"-s", "--services"},
description =
"Comma-delimited list of App Engine services to set. "
+ "Allowed values: [DEFAULT, TOOLS, BACKEND, PUBAPI]")
private List<Service> services = ImmutableList.of();
@Parameter(
names = {"-v", "--versions"},
description =
"Comma-delimited list of App Engine versions to set, e.g., canary. "
+ "Cannot be set if --non_live_versions is set.")
private List<String> versions = ImmutableList.of();
@Parameter(
names = {"-n", "--num_instances"},
description =
"The new number of instances for the given versions "
+ "or for all non-live versions if --non_live_versions is set.",
required = true)
private Long numInstances;
@Parameter(
names = "--non_live_versions",
description = "Whether to set number of instances for all non-live versions.",
arity = 1)
private Boolean nonLiveVersions = false;
@Inject AppEngineServiceUtils appEngineServiceUtils;
@Inject Appengine appengine;
@Inject
@Config("projectId")
String projectId;
@Override
public void run() {
if (nonLiveVersions) {
checkArgument(versions.isEmpty(), "--versions cannot be set if --non_live_versions is set");
services = services.isEmpty() ? ALL_DEPLOYED_SERVICES : services;
ImmutableSetMultimap<Service, String> allLiveVersionsMap = getAllLiveVersionsMap(services);
ImmutableSetMultimap<Service, String> manualScalingVersionsMap =
getManualScalingVersionsMap(services);
// Set number of instances for versions which are manual scaling and non-live
manualScalingVersionsMap.forEach(
(service, versionId) -> {
if (!allLiveVersionsMap.containsEntry(service, versionId)) {
setNumInstances(service, versionId, numInstances);
}
});
} else {
checkArgument(!services.isEmpty(), "Service must be specified");
checkArgument(!versions.isEmpty(), "Version must be specified");
checkArgument(numInstances > 0, "Number of instances must be greater than zero");
ImmutableSetMultimap<Service, String> manualScalingVersionsMap =
getManualScalingVersionsMap(services);
for (Service service : services) {
for (String versionId : versions) {
checkArgument(
manualScalingVersionsMap.containsEntry(service, versionId),
"Version %s of service %s is not managed through manual scaling",
versionId,
service);
setNumInstances(service, versionId, numInstances);
}
}
}
}
private void setNumInstances(Service service, String version, long numInstances) {
appEngineServiceUtils.setNumInstances(service.getServiceId(), version, numInstances);
logger.atInfo().log(
"Successfully set version %s of service %s to %d instances.",
version, service, numInstances);
}
private ImmutableSetMultimap<Service, String> getAllLiveVersionsMap(List<Service> services) {
try {
return nullToEmpty(appengine.apps().services().list(projectId).execute().getServices())
.stream()
.filter(
service ->
services.contains(SERVICE_ID_TO_SERVICE.getOrDefault(service.getId(), null)))
.collect(
flatteningToImmutableSetMultimap(
service -> SERVICE_ID_TO_SERVICE.get(service.getId()),
service -> nullToEmpty(service.getSplit().getAllocations()).keySet().stream()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private ImmutableSetMultimap<Service, String> getManualScalingVersionsMap(
List<Service> services) {
return services.stream()
.collect(
flatteningToImmutableSetMultimap(
service -> service,
service -> {
try {
return nullToEmpty(
appengine
.apps()
.services()
.versions()
.list(projectId, service.getServiceId())
.execute()
.getVersions())
.stream()
.filter(version -> version.getManualScaling() != null)
.map(version -> version.getId());
} catch (IOException e) {
throw new RuntimeException(e);
}
}));
}
}

View file

@ -1,238 +0,0 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableMultimap;
import google.registry.testing.AppEngineAdminApiHelper;
import google.registry.util.AppEngineServiceUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
/** Unit tests for {@link SetNumInstancesCommand}. */
public class SetNumInstancesCommandTest extends CommandTestCase<SetNumInstancesCommand> {
@Mock AppEngineServiceUtils appEngineServiceUtils;
private static final String projectId = "domain-registry-test";
@BeforeEach
void beforeEach() {
command = new SetNumInstancesCommand();
command.appEngineServiceUtils = appEngineServiceUtils;
command.projectId = projectId;
}
@Test
void test_missingService_throwsException() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> runCommand("--versions=version", "--num_instances=5"));
assertThat(thrown).hasMessageThat().contains("Service must be specified");
}
@Test
void test_emptyService_throwsException() {
ParameterException thrown =
assertThrows(
ParameterException.class,
() -> runCommand("--services=", "--versions=version", "--num_instances=5"));
assertThat(thrown)
.hasMessageThat()
.contains(
"Invalid value for -s parameter. Allowed values:[DEFAULT, TOOLS, BACKEND, PUBAPI]");
}
@Test
void test_invalidService_throwsException() {
ParameterException thrown =
assertThrows(
ParameterException.class,
() ->
runCommand(
"--services=INVALID,DEFAULT", "--versions=version", "--num_instances=5"));
assertThat(thrown)
.hasMessageThat()
.contains(
"Invalid value for -s parameter. Allowed values:[DEFAULT, TOOLS, BACKEND, PUBAPI]");
}
@Test
void test_missingVersion_throwsException() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> runCommand("--services=DEFAULT", "--num_instances=5"));
assertThat(thrown).hasMessageThat().contains("Version must be specified");
}
@Test
void test_emptyVersion_throwsException() {
ParameterException thrown =
assertThrows(
ParameterException.class,
() -> runCommand("--services=DEFAULT", "--num_instances=5", "--versions"));
assertThat(thrown).hasMessageThat().contains("Expected a value after parameter --versions");
}
@Test
void test_missingNumInstances_throwsException() {
ParameterException thrown =
assertThrows(
ParameterException.class, () -> runCommand("--services=DEFAULT", "--versions=version"));
assertThat(thrown)
.hasMessageThat()
.contains("The following option is required: -n, --num_instances");
}
@Test
void test_invalidNumInstances_throwsException() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> runCommand("--services=DEFAULT", "--versions=version", "--num_instances=-5"));
assertThat(thrown).hasMessageThat().contains("Number of instances must be greater than zero");
}
@Test
void test_versionNotNullWhenSettingAllNonLiveVersions_throwsException() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> runCommand("--services=DEFAULT", "--versions=version", "--num_instances=-5"));
assertThat(thrown).hasMessageThat().contains("Number of instances must be greater than zero");
}
@MockitoSettings(strictness = Strictness.LENIENT)
@Test
void test_settingNonManualScalingVersions_throwsException() {
command.appengine =
new AppEngineAdminApiHelper.Builder()
.setAppId(projectId)
.setManualScalingVersionsMap(ImmutableMultimap.of("default", "version1"))
.build()
.getAppengine();
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
runCommand(
"--non_live_versions=true",
"--services=DEFAULT",
"--versions=version",
"--num_instances=10"));
assertThat(thrown)
.hasMessageThat()
.contains("--versions cannot be set if --non_live_versions is set");
}
@MockitoSettings(strictness = Strictness.LENIENT)
@Test
void test_validParameters_succeeds() throws Exception {
command.appengine =
new AppEngineAdminApiHelper.Builder()
.setAppId(projectId)
.setManualScalingVersionsMap(ImmutableMultimap.of("default", "version"))
.build()
.getAppengine();
runCommand("--services=DEFAULT", "--versions=version", "--num_instances=10");
verify(appEngineServiceUtils, times(1)).setNumInstances("default", "version", 10L);
}
@MockitoSettings(strictness = Strictness.LENIENT)
@Test
void test_validShortParametersAndLowercaseService_succeeds() throws Exception {
command.appengine =
new AppEngineAdminApiHelper.Builder()
.setAppId(projectId)
.setManualScalingVersionsMap(ImmutableMultimap.of("default", "version"))
.build()
.getAppengine();
runCommand("-s default", "-v version", "-n 10");
verify(appEngineServiceUtils, times(1)).setNumInstances("default", "version", 10L);
}
@MockitoSettings(strictness = Strictness.LENIENT)
@Test
void test_settingMultipleServicesAndVersions_succeeds() throws Exception {
command.appengine =
new AppEngineAdminApiHelper.Builder()
.setAppId(projectId)
.setManualScalingVersionsMap(
ImmutableMultimap.of(
"default", "version1",
"default", "version2",
"backend", "version1",
"backend", "version2"))
.build()
.getAppengine();
runCommand("--services=DEFAULT,BACKEND", "--versions=version1,version2", "--num_instances=10");
verify(appEngineServiceUtils, times(1)).setNumInstances("default", "version1", 10L);
verify(appEngineServiceUtils, times(1)).setNumInstances("default", "version2", 10L);
verify(appEngineServiceUtils, times(1)).setNumInstances("backend", "version1", 10L);
verify(appEngineServiceUtils, times(1)).setNumInstances("backend", "version2", 10L);
}
@Test
void test_settingAllNonLiveVersions_succeeds() throws Exception {
command.appengine =
new AppEngineAdminApiHelper.Builder()
.setAppId(projectId)
.setManualScalingVersionsMap(
ImmutableMultimap.of(
"default", "version1", "default", "version2", "default", "version3"))
.setLiveVersionsMap(ImmutableMultimap.of("default", "version2"))
.build()
.getAppengine();
runCommand("--non_live_versions=true", "--services=DEFAULT", "--num_instances=10");
verify(appEngineServiceUtils, times(1)).setNumInstances("default", "version1", 10L);
verify(appEngineServiceUtils, times(0)).setNumInstances("default", "version2", 10L);
verify(appEngineServiceUtils, times(1)).setNumInstances("default", "version3", 10L);
}
@Test
void test_noNonLiveVersions_succeeds() throws Exception {
command.appengine =
new AppEngineAdminApiHelper.Builder()
.setAppId(projectId)
.setManualScalingVersionsMap(
ImmutableMultimap.of(
"default", "version1", "default", "version2", "default", "version3"))
.setLiveVersionsMap(
ImmutableMultimap.of(
"default", "version1", "default", "version2", "default", "version3"))
.build()
.getAppengine();
runCommand("--non_live_versions=true", "--services=DEFAULT", "--num_instances=10");
verify(appEngineServiceUtils, times(0)).setNumInstances("default", "version1", 10L);
verify(appEngineServiceUtils, times(0)).setNumInstances("default", "version2", 10L);
verify(appEngineServiceUtils, times(0)).setNumInstances("default", "version3", 10L);
}
}

View file

@ -33,8 +33,7 @@ class RollbackStep:
Two steps are handled differently. The _UpdateDeployTag step gets a piped
shell command, which needs to be handled differently. The
_SetManualScalingNumInstances step uses the AppEngine Admin API client in
this package to set the number of instances. The Nomulus set_num_instances
command is not working right now.
this package to set the number of instances.
"""
description: str

View file

@ -1,63 +0,0 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.util;
/**
* A wrapper for {@link com.google.appengine.api.modules.ModulesService} that provides a saner API.
*/
public interface AppEngineServiceUtils {
/**
* Returns a host name to use for the given service.
*
* <p>Note that this host name will not include a version, so it will always be whatever the live
* version is at the time that you hit the URL.
*/
String getServiceHostname(String service);
/**
* Returns a host name to use for the given service and current version.
*
* <p>Note that this host name will include the current version now at time of URL generation,
* which will not be the live version in the future.
*/
String getCurrentVersionHostname(String service);
/** Returns a host name to use for the given service and version. */
String getVersionHostname(String service, String version);
/**
* Converts a multi-level App Engine host name (not URL) to the -dot- single subdomain format.
*
* <p>This is needed because appspot.com only has a single wildcard SSL certificate, so the native
* App Engine URLs of the form service.projectid.appspot.com or
* version.service.projectid.appspot.com won't work over HTTPS when being fetched from outside of
* GCP. The work-around is to change all of the "." subdomain markers to "-dot-". E.g.:
*
* <ul>
* <li>tools.projectid.appspot.com --&gt; tools-dot-projectid.appspot.com
* <li>version.backend.projectid.appspot.com --&gt;
* version-dot-backend-dot-projectid.appspot.com
* </ul>
*
* @see <a
* href="https://cloud.google.com/appengine/docs/standard/java/how-requests-are-routed">How
* App Engine requests are routed</a>
*/
String convertToSingleSubdomain(String hostname);
/** Set the number of instances at runtime for a given service and version. */
void setNumInstances(String service, String version, long numInstances);
}

View file

@ -1,77 +0,0 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.util;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.appengine.api.modules.ModulesService;
import com.google.common.flogger.FluentLogger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
/** A wrapper for {@link ModulesService} that provides a saner API. */
public class AppEngineServiceUtilsImpl implements AppEngineServiceUtils {
private static final Pattern APPSPOT_HOSTNAME_PATTERN =
Pattern.compile("^(.*)\\.appspot\\.com$");
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final ModulesService modulesService;
@Inject
public AppEngineServiceUtilsImpl(ModulesService modulesService) {
this.modulesService = modulesService;
}
@Override
public String getServiceHostname(String service) {
// This will be in the format "version.service.projectid.appspot.com"
String hostnameWithVersion = modulesService.getVersionHostname(service, null);
// Strip off the version and return just "service.projectid.appspot.com"
return hostnameWithVersion.replaceFirst("^[^.]+\\.", "");
}
@Override
public String getCurrentVersionHostname(String service) {
return modulesService.getVersionHostname(service, null);
}
@Override
public String getVersionHostname(String service, String version) {
checkArgumentNotNull(version, "Must specify the version");
return modulesService.getVersionHostname(service, version);
}
@Override
public void setNumInstances(String service, String version, long numInstances) {
checkArgumentNotNull(service, "Must specify the service");
checkArgumentNotNull(version, "Must specify the version");
checkArgument(numInstances > 0, "Number of instances must be greater than 0");
modulesService.setNumInstances(service, version, numInstances);
}
@Override
public String convertToSingleSubdomain(String hostname) {
Matcher matcher = APPSPOT_HOSTNAME_PATTERN.matcher(hostname);
if (!matcher.matches()) {
logger.atWarning().log(
"Skipping conversion because hostname '%s' can't be parsed.", hostname);
return hostname;
}
return matcher.group(1).replace(".", "-dot-") + ".appspot.com";
}
}

View file

@ -14,8 +14,6 @@
package google.registry.util;
import com.google.appengine.api.modules.ModulesService;
import com.google.appengine.api.modules.ModulesServiceFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import dagger.Binds;
@ -41,17 +39,6 @@ public abstract class UtilsModule {
@Singleton
abstract Clock provideClock(SystemClock clock);
@Provides
@Singleton
static ModulesService provideModulesService() {
return ModulesServiceFactory.getModulesService();
}
@Binds
@Singleton
abstract AppEngineServiceUtils provideAppEngineServiceUtils(
AppEngineServiceUtilsImpl appEngineServiceUtilsImpl);
@Singleton
@Provides
public static SecureRandom provideSecureRandom() {

View file

@ -1,144 +0,0 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.util;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.appengine.api.modules.ModulesService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
/** Unit tests for {@link AppEngineServiceUtilsImpl}. */
@ExtendWith(MockitoExtension.class)
class AppEngineServiceUtilsImplTest {
@Mock private ModulesService modulesService;
private AppEngineServiceUtils appEngineServiceUtils;
@BeforeEach
void beforeEach() {
appEngineServiceUtils = new AppEngineServiceUtilsImpl(modulesService);
}
@Test
void test_getServiceHostname_doesntIncludeVersionId() {
when(modulesService.getVersionHostname(anyString(), isNull()))
.thenReturn("1234.servicename.projectid.appspot.fake");
assertThat(appEngineServiceUtils.getServiceHostname("servicename"))
.isEqualTo("servicename.projectid.appspot.fake");
}
@Test
void test_getVersionHostname_doesIncludeVersionId() {
when(modulesService.getVersionHostname(anyString(), isNull()))
.thenReturn("1234.servicename.projectid.appspot.fake");
assertThat(appEngineServiceUtils.getCurrentVersionHostname("servicename"))
.isEqualTo("1234.servicename.projectid.appspot.fake");
}
@Test
void test_getVersionHostname_worksWithVersionId() {
when(modulesService.getVersionHostname(anyString(), eq("2345")))
.thenReturn("2345.servicename.projectid.appspot.fake");
assertThat(appEngineServiceUtils.getVersionHostname("servicename", "2345"))
.isEqualTo("2345.servicename.projectid.appspot.fake");
}
@Test
void test_getVersionHostname_throwsWhenVersionIdIsNull() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> appEngineServiceUtils.getVersionHostname("servicename", null));
assertThat(thrown).hasMessageThat().isEqualTo("Must specify the version");
}
@Test
void test_setNumInstances_worksWithValidParameters() {
appEngineServiceUtils.setNumInstances("service", "version", 10L);
verify(modulesService, times(1)).setNumInstances("service", "version", 10L);
}
@Test
void test_setNumInstances_throwsWhenServiceIsNull() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> appEngineServiceUtils.setNumInstances(null, "version", 10L));
assertThat(thrown).hasMessageThat().isEqualTo("Must specify the service");
}
@Test
void test_setNumInstances_throwsWhenVersionIsNull() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> appEngineServiceUtils.setNumInstances("service", null, 10L));
assertThat(thrown).hasMessageThat().isEqualTo("Must specify the version");
}
@Test
void test_setNumInstances_throwsWhenNumInstancesIsInvalid() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> appEngineServiceUtils.setNumInstances("service", "version", -10L));
assertThat(thrown).hasMessageThat().isEqualTo("Number of instances must be greater than 0");
}
@Test
void test_convertToSingleSubdomain_doesNothingWithoutServiceOrHostname() {
assertThat(appEngineServiceUtils.convertToSingleSubdomain("projectid.appspot.com"))
.isEqualTo("projectid.appspot.com");
}
@Test
void test_convertToSingleSubdomain_doesNothingWhenItCannotParseCorrectly() {
assertThat(appEngineServiceUtils.convertToSingleSubdomain("garbage.notrealhost.example"))
.isEqualTo("garbage.notrealhost.example");
}
@Test
void test_convertToSingleSubdomain_convertsWithServiceName() {
assertThat(appEngineServiceUtils.convertToSingleSubdomain("service.projectid.appspot.com"))
.isEqualTo("service-dot-projectid.appspot.com");
}
@Test
void test_convertToSingleSubdomain_convertsWithVersionAndServiceName() {
assertThat(
appEngineServiceUtils.convertToSingleSubdomain("version.service.projectid.appspot.com"))
.isEqualTo("version-dot-service-dot-projectid.appspot.com");
}
@Test
void test_convertToSingleSubdomain_convertsWithInstanceAndVersionAndServiceName() {
assertThat(
appEngineServiceUtils.convertToSingleSubdomain(
"instanceid.version.service.projectid.appspot.com"))
.isEqualTo("instanceid-dot-version-dot-service-dot-projectid.appspot.com");
}
}