mirror of
https://github.com/google/nomulus
synced 2026-01-30 09:32:22 +00:00
Compare commits
25 Commits
proxy-2023
...
proxy-2023
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34d329c158 | ||
|
|
425ecdcd87 | ||
|
|
77ee124374 | ||
|
|
b9742adc0b | ||
|
|
d4cd25c4ae | ||
|
|
8b7e938ed6 | ||
|
|
c216c874b4 | ||
|
|
0ab9471c8d | ||
|
|
d482754f66 | ||
|
|
fe086b43f5 | ||
|
|
95f1bca3fb | ||
|
|
178a2323d9 | ||
|
|
a44aa1378f | ||
|
|
d0f625f70e | ||
|
|
fb59874234 | ||
|
|
b6083e227f | ||
|
|
5805b6859e | ||
|
|
3108e8a871 | ||
|
|
ec142caf9c | ||
|
|
e60ad58098 | ||
|
|
83e9e7fb5c | ||
|
|
438c523fcb | ||
|
|
025a2faff2 | ||
|
|
fd822dd333 | ||
|
|
9b93749d43 |
@@ -103,6 +103,7 @@ explodeWar.doLast {
|
||||
file("${it.explodedAppDirectory}/WEB-INF/lib/tools.jar").setWritable(true)
|
||||
}
|
||||
|
||||
appengineDeployAll.finalizedBy ':cloudSchedulerDeployer'
|
||||
rootProject.deploy.dependsOn appengineDeployAll
|
||||
rootProject.stage.dependsOn appengineStage
|
||||
tasks['war'].dependsOn ':console-webapp:buildConsoleWebappProd'
|
||||
|
||||
15
build.gradle
15
build.gradle
@@ -558,6 +558,21 @@ task coreDev {
|
||||
|
||||
javadocDependentTasks.each { tasks.javadoc.dependsOn(it) }
|
||||
|
||||
// Runs the script, which deploys cloud scheduler tasks based on the config
|
||||
task cloudSchedulerDeployer {
|
||||
doLast {
|
||||
def env = environment
|
||||
if (!prodOrSandboxEnv) {
|
||||
exec {
|
||||
commandLine 'go', 'run',
|
||||
"${rootDir}/release/builder/cloudSchedulerDeployer.go",
|
||||
"${rootDir}/core/src/main/java/google/registry/env/${env}/default/WEB-INF/cloud-scheduler-tasks.xml",
|
||||
"domain-registry-${env}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// disable javadoc in subprojects, these will break because they don't have
|
||||
// the correct classpath (see above).
|
||||
gradle.taskGraph.whenReady { graph ->
|
||||
|
||||
3878
console-webapp/package-lock.json
generated
3878
console-webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,24 +13,24 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^15.1.0",
|
||||
"@angular/cdk": "^15.0.4",
|
||||
"@angular/common": "^15.1.0",
|
||||
"@angular/compiler": "^15.1.0",
|
||||
"@angular/core": "^15.1.0",
|
||||
"@angular/forms": "^15.1.0",
|
||||
"@angular/material": "^15.0.4",
|
||||
"@angular/platform-browser": "^15.1.0",
|
||||
"@angular/platform-browser-dynamic": "^15.1.0",
|
||||
"@angular/router": "^15.1.0",
|
||||
"@angular/animations": "^15.2.2",
|
||||
"@angular/cdk": "^15.2.2",
|
||||
"@angular/common": "^15.2.2",
|
||||
"@angular/compiler": "^15.2.2",
|
||||
"@angular/core": "^15.2.2",
|
||||
"@angular/forms": "^15.2.2",
|
||||
"@angular/material": "^15.2.2",
|
||||
"@angular/platform-browser": "^15.2.2",
|
||||
"@angular/platform-browser-dynamic": "^15.2.2",
|
||||
"@angular/router": "^15.2.2",
|
||||
"rxjs": "~7.5.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^15.1.0",
|
||||
"@angular/cli": "~15.1.0",
|
||||
"@angular/compiler-cli": "^15.1.0",
|
||||
"@angular-devkit/build-angular": "^15.2.4",
|
||||
"@angular/cli": "~15.2.4",
|
||||
"@angular/compiler-cli": "^15.2.2",
|
||||
"@types/jasmine": "~4.0.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"concurrently": "^7.6.0",
|
||||
|
||||
@@ -1028,6 +1028,7 @@ test {
|
||||
// TODO(weiminyu): Remove dependency on sqlIntegrationTest
|
||||
}.dependsOn(fragileTest, outcastTest, standardTest, registryToolIntegrationTest, sqlIntegrationTest)
|
||||
|
||||
|
||||
// When we override tests, we also break the cleanTest command.
|
||||
cleanTest.dependsOn(cleanFragileTest, cleanOutcastTest, cleanStandardTest,
|
||||
cleanRegistryToolIntegrationTest, cleanSqlIntegrationTest)
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
@@ -86,6 +85,6 @@ public final class AsyncTaskEnqueuer {
|
||||
cloudTasksUtils.enqueue(
|
||||
QUEUE_ASYNC_ACTIONS,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
ResaveEntityAction.PATH, Service.BACKEND.toString(), params, etaDuration));
|
||||
ResaveEntityAction.PATH, Service.BACKEND, params, etaDuration));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
@@ -36,12 +36,18 @@ import com.google.common.net.MediaType;
|
||||
import com.google.common.net.UrlEscapers;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.util.Timestamps;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CollectionUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Utilities for dealing with Cloud Tasks. */
|
||||
@@ -57,11 +63,12 @@ public class CloudTasksUtils implements Serializable {
|
||||
private final String locationId;
|
||||
private final SerializableCloudTasksClient client;
|
||||
|
||||
@Inject
|
||||
public CloudTasksUtils(
|
||||
Retrier retrier,
|
||||
Clock clock,
|
||||
String projectId,
|
||||
String locationId,
|
||||
@Config("projectId") String projectId,
|
||||
@Config("locationId") String locationId,
|
||||
SerializableCloudTasksClient client) {
|
||||
this.retrier = retrier;
|
||||
this.clock = clock;
|
||||
@@ -108,7 +115,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
* the worker service</a>
|
||||
*/
|
||||
private Task createTask(
|
||||
String path, HttpMethod method, String service, Multimap<String, String> params) {
|
||||
String path, HttpMethod method, Service service, Multimap<String, String> params) {
|
||||
checkArgument(
|
||||
path != null && !path.isEmpty() && path.charAt(0) == '/',
|
||||
"The path must start with a '/'.");
|
||||
@@ -119,7 +126,8 @@ public class CloudTasksUtils implements Serializable {
|
||||
AppEngineHttpRequest.Builder requestBuilder =
|
||||
AppEngineHttpRequest.newBuilder()
|
||||
.setHttpMethod(method)
|
||||
.setAppEngineRouting(AppEngineRouting.newBuilder().setService(service).build());
|
||||
.setAppEngineRouting(
|
||||
AppEngineRouting.newBuilder().setService(service.toString()).build());
|
||||
|
||||
if (!CollectionUtils.isNullOrEmpty(params)) {
|
||||
Escaper escaper = UrlEscapers.urlPathSegmentEscaper();
|
||||
@@ -165,7 +173,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
private Task createTaskWithJitter(
|
||||
String path,
|
||||
HttpMethod method,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Optional<Integer> jitterSeconds) {
|
||||
if (!jitterSeconds.isPresent() || jitterSeconds.get() <= 0) {
|
||||
@@ -199,7 +207,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
private Task createTaskWithDelay(
|
||||
String path,
|
||||
HttpMethod method,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Duration delay) {
|
||||
if (delay.isEqual(Duration.ZERO)) {
|
||||
@@ -211,11 +219,11 @@ public class CloudTasksUtils implements Serializable {
|
||||
.build();
|
||||
}
|
||||
|
||||
public Task createPostTask(String path, String service, Multimap<String, String> params) {
|
||||
public Task createPostTask(String path, Service service, Multimap<String, String> params) {
|
||||
return createTask(path, HttpMethod.POST, service, params);
|
||||
}
|
||||
|
||||
public Task createGetTask(String path, String service, Multimap<String, String> params) {
|
||||
public Task createGetTask(String path, Service service, Multimap<String, String> params) {
|
||||
return createTask(path, HttpMethod.GET, service, params);
|
||||
}
|
||||
|
||||
@@ -224,7 +232,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
*/
|
||||
public Task createPostTaskWithJitter(
|
||||
String path,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Optional<Integer> jitterSeconds) {
|
||||
return createTaskWithJitter(path, HttpMethod.POST, service, params, jitterSeconds);
|
||||
@@ -235,7 +243,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
*/
|
||||
public Task createGetTaskWithJitter(
|
||||
String path,
|
||||
String service,
|
||||
Service service,
|
||||
Multimap<String, String> params,
|
||||
Optional<Integer> jitterSeconds) {
|
||||
return createTaskWithJitter(path, HttpMethod.GET, service, params, jitterSeconds);
|
||||
@@ -243,13 +251,13 @@ public class CloudTasksUtils implements Serializable {
|
||||
|
||||
/** Create a {@link Task} via HTTP.POST that will be delayed for {@code delay}. */
|
||||
public Task createPostTaskWithDelay(
|
||||
String path, String service, Multimap<String, String> params, Duration delay) {
|
||||
String path, Service service, Multimap<String, String> params, Duration delay) {
|
||||
return createTaskWithDelay(path, HttpMethod.POST, service, params, delay);
|
||||
}
|
||||
|
||||
/** Create a {@link Task} via HTTP.GET that will be delayed for {@code delay}. */
|
||||
public Task createGetTaskWithDelay(
|
||||
String path, String service, Multimap<String, String> params, Duration delay) {
|
||||
String path, Service service, Multimap<String, String> params, Duration delay) {
|
||||
return createTaskWithDelay(path, HttpMethod.GET, service, params, delay);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.google.common.collect.Sets;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.EppResourceUtils;
|
||||
import google.registry.model.domain.Domain;
|
||||
@@ -98,7 +98,7 @@ public class DeleteProberDataAction implements Runnable {
|
||||
/** Number of domains to retrieve and delete per SQL transaction. */
|
||||
private static final int BATCH_SIZE = 1000;
|
||||
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
|
||||
@Inject
|
||||
@Parameter(PARAM_DRY_RUN)
|
||||
@@ -264,6 +264,6 @@ public class DeleteProberDataAction implements Runnable {
|
||||
// messages, or auto-renews because those will all be hard-deleted the next time the job runs
|
||||
// anyway.
|
||||
tm().putAll(ImmutableList.of(deletedDomain, historyEntry));
|
||||
dnsQueue.addDomainRefreshTask(deletedDomain.getDomainName());
|
||||
dnsUtils.requestDomainDnsRefresh(deletedDomain.getDomainName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.flows.custom.CustomLogicFactoryModule;
|
||||
import google.registry.flows.custom.CustomLogicModule;
|
||||
import google.registry.flows.domain.DomainPricingLogic;
|
||||
import google.registry.flows.domain.DomainPricingLogic.AllocationTokenInvalidForPremiumNameException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingEvent.Cancellation;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
@@ -53,6 +54,7 @@ import google.registry.util.Clock;
|
||||
import google.registry.util.SystemClock;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.inject.Singleton;
|
||||
import org.apache.beam.sdk.Pipeline;
|
||||
@@ -383,24 +385,31 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
|
||||
// It is OK to always create a OneTime, even though the domain might be deleted or transferred
|
||||
// later during autorenew grace period, as a cancellation will always be written out in those
|
||||
// instances.
|
||||
OneTime oneTime =
|
||||
new OneTime.Builder()
|
||||
.setBillingTime(billingTime)
|
||||
.setRegistrarId(recurring.getRegistrarId())
|
||||
// Determine the cost for a one-year renewal.
|
||||
.setCost(
|
||||
domainPricingLogic
|
||||
.getRenewPrice(tld, recurring.getTargetId(), eventTime, 1, recurring)
|
||||
.getRenewCost())
|
||||
.setEventTime(eventTime)
|
||||
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
|
||||
.setDomainHistory(historyEntry)
|
||||
.setPeriodYears(1)
|
||||
.setReason(recurring.getReason())
|
||||
.setSyntheticCreationTime(endTime)
|
||||
.setCancellationMatchingBillingEvent(recurring)
|
||||
.setTargetId(recurring.getTargetId())
|
||||
.build();
|
||||
OneTime oneTime = null;
|
||||
try {
|
||||
oneTime =
|
||||
new OneTime.Builder()
|
||||
.setBillingTime(billingTime)
|
||||
.setRegistrarId(recurring.getRegistrarId())
|
||||
// Determine the cost for a one-year renewal.
|
||||
.setCost(
|
||||
domainPricingLogic
|
||||
.getRenewPrice(
|
||||
tld, recurring.getTargetId(), eventTime, 1, recurring, Optional.empty())
|
||||
.getRenewCost())
|
||||
.setEventTime(eventTime)
|
||||
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
|
||||
.setDomainHistory(historyEntry)
|
||||
.setPeriodYears(1)
|
||||
.setReason(recurring.getReason())
|
||||
.setSyntheticCreationTime(endTime)
|
||||
.setCancellationMatchingBillingEvent(recurring)
|
||||
.setTargetId(recurring.getTargetId())
|
||||
.build();
|
||||
} catch (AllocationTokenInvalidForPremiumNameException e) {
|
||||
// This should not be reached since we are not using an allocation token
|
||||
return;
|
||||
}
|
||||
results.add(oneTime);
|
||||
}
|
||||
results.add(
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.auto.value.AutoValue;
|
||||
import com.google.cloud.storage.BlobId;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.keyring.api.PgpHelper;
|
||||
import google.registry.model.common.Cursor;
|
||||
@@ -46,7 +47,6 @@ import google.registry.rde.RdeUtil;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.RequestParameters;
|
||||
import google.registry.tldconfig.idn.IdnTableEnum;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.xjc.rdeheader.XjcRdeHeader;
|
||||
import google.registry.xjc.rdeheader.XjcRdeHeaderElement;
|
||||
import google.registry.xml.ValidationMode;
|
||||
@@ -306,7 +306,7 @@ public class RdeIO {
|
||||
RDE_UPLOAD_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
RdeUploadAction.PATH,
|
||||
Service.BACKEND.getServiceId(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
RequestParameters.PARAM_TLD,
|
||||
key.tld(),
|
||||
@@ -318,7 +318,7 @@ public class RdeIO {
|
||||
BRDA_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
BrdaCopyAction.PATH,
|
||||
Service.BACKEND.getServiceId(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
RequestParameters.PARAM_TLD,
|
||||
key.tld(),
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.beam.common.RegistryJpaIO;
|
||||
import google.registry.beam.common.RegistryPipelineOptions;
|
||||
import google.registry.config.CloudTasksUtilsModule;
|
||||
@@ -62,7 +63,6 @@ import google.registry.rde.DepositFragment;
|
||||
import google.registry.rde.PendingDeposit;
|
||||
import google.registry.rde.PendingDeposit.PendingDepositCoder;
|
||||
import google.registry.rde.RdeMarshaller;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.UtilsModule;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
@@ -19,18 +19,15 @@ import com.google.cloud.tasks.v2.CloudTasksClient;
|
||||
import com.google.cloud.tasks.v2.CloudTasksSettings;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.batch.CloudTasksUtils.GcpCloudTasksClient;
|
||||
import google.registry.batch.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.config.CredentialModule.DefaultCredential;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.CloudTasksUtils.GcpCloudTasksClient;
|
||||
import google.registry.util.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.util.GoogleCredentialsBundle;
|
||||
import google.registry.util.Retrier;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.function.Supplier;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* A {@link Module} that provides {@link CloudTasksUtils}.
|
||||
@@ -41,17 +38,6 @@ import javax.inject.Singleton;
|
||||
@Module
|
||||
public abstract class CloudTasksUtilsModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
public static CloudTasksUtils provideCloudTasksUtils(
|
||||
@Config("projectId") String projectId,
|
||||
@Config("locationId") String locationId,
|
||||
SerializableCloudTasksClient client,
|
||||
Retrier retrier,
|
||||
Clock clock) {
|
||||
return new CloudTasksUtils(retrier, clock, projectId, locationId, client);
|
||||
}
|
||||
|
||||
// Provides a supplier instead of using a Dagger @Provider because the latter is not serializable.
|
||||
@Provides
|
||||
public static Supplier<CloudTasksClient> provideCloudTasksClientSupplier(
|
||||
|
||||
@@ -107,9 +107,9 @@ public final class RegistryConfig {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudSchedulerServiceAccountEmail")
|
||||
public static String provideCloudSchedulerServiceAccountEmail(RegistryConfigSettings config) {
|
||||
return config.gcpProject.cloudSchedulerServiceAccountEmail;
|
||||
@Config("serviceAccountEmails")
|
||||
public static ImmutableList<String> provideServiceAccountEmails(RegistryConfigSettings config) {
|
||||
return ImmutableList.copyOf(config.gcpProject.serviceAccountEmails);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -930,7 +930,7 @@ public final class RegistryConfig {
|
||||
* <p>Note that this uses {@code @Named} instead of {@code @Config} so that it can be used from
|
||||
* the low-level util package, which cannot have a dependency on the config package.
|
||||
*
|
||||
* @see google.registry.util.CloudTasksUtils
|
||||
* @see google.registry.batch.CloudTasksUtils
|
||||
*/
|
||||
@Provides
|
||||
@Named("transientFailureRetries")
|
||||
|
||||
@@ -54,7 +54,7 @@ public class RegistryConfigSettings {
|
||||
public String backendServiceUrl;
|
||||
public String toolsServiceUrl;
|
||||
public String pubapiServiceUrl;
|
||||
public String cloudSchedulerServiceAccountEmail;
|
||||
public List<String> serviceAccountEmails;
|
||||
}
|
||||
|
||||
/** Configuration options for OAuth settings for authenticating users. */
|
||||
|
||||
@@ -22,8 +22,11 @@ gcpProject:
|
||||
backendServiceUrl: https://localhost
|
||||
toolsServiceUrl: https://localhost
|
||||
pubapiServiceUrl: https://localhost
|
||||
# Service account used by Cloud Scheduler to send authenticated requests.
|
||||
cloudSchedulerServiceAccountEmail: cloud-scheduler-email@email.com
|
||||
# Service accounts eligible for authorization (e.g. default service account,
|
||||
# account used by Cloud Scheduler) to send authenticated requests.
|
||||
serviceAccountEmails:
|
||||
- default-service-account-email@email.com
|
||||
- cloud-scheduler-email@email.com
|
||||
|
||||
gSuite:
|
||||
# Publicly accessible domain name of the running G Suite instance.
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
@@ -45,7 +46,6 @@ import google.registry.request.ParameterMap;
|
||||
import google.registry.request.RequestParameters;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
@@ -158,6 +158,6 @@ public final class TldFanoutAction implements Runnable {
|
||||
params.put(RequestParameters.PARAM_TLD, tld);
|
||||
}
|
||||
return cloudTasksUtils.createPostTaskWithJitter(
|
||||
endpoint, Service.BACKEND.toString(), params, jitterSeconds);
|
||||
endpoint, Service.BACKEND, params, jitterSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,5 +34,8 @@ public class DnsConstants {
|
||||
public static final String DNS_TARGET_CREATE_TIME_PARAM = "Create-Time";
|
||||
|
||||
/** The possible values of the {@code DNS_TARGET_TYPE_PARAM} parameter. */
|
||||
public enum TargetType { DOMAIN, HOST, ZONE }
|
||||
public enum TargetType {
|
||||
DOMAIN,
|
||||
HOST
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,11 +77,15 @@ public class DnsQueue {
|
||||
private static final RateLimiter rateLimiter = RateLimiter.create(9);
|
||||
|
||||
@Inject
|
||||
public DnsQueue(@Named(DNS_PULL_QUEUE_NAME) Queue queue, Clock clock) {
|
||||
DnsQueue(@Named(DNS_PULL_QUEUE_NAME) Queue queue, Clock clock) {
|
||||
this.queue = queue;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
Clock getClock() {
|
||||
return clock;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static DnsQueue createForTesting(Clock clock) {
|
||||
return new DnsQueue(getQueue(DNS_PULL_QUEUE_NAME), clock);
|
||||
@@ -108,7 +112,7 @@ public class DnsQueue {
|
||||
}
|
||||
|
||||
/** Adds a task to the queue to refresh the DNS information for the specified subordinate host. */
|
||||
public TaskHandle addHostRefreshTask(String hostName) {
|
||||
TaskHandle addHostRefreshTask(String hostName) {
|
||||
Optional<InternetDomainName> tld = Registries.findTldForName(InternetDomainName.from(hostName));
|
||||
checkArgument(
|
||||
tld.isPresent(), String.format("%s is not a subordinate host to a known tld", hostName));
|
||||
@@ -116,12 +120,12 @@ public class DnsQueue {
|
||||
}
|
||||
|
||||
/** Enqueues a task to refresh DNS for the specified domain now. */
|
||||
public TaskHandle addDomainRefreshTask(String domainName) {
|
||||
TaskHandle addDomainRefreshTask(String domainName) {
|
||||
return addDomainRefreshTask(domainName, Duration.ZERO);
|
||||
}
|
||||
|
||||
/** Enqueues a task to refresh DNS for the specified domain at some point in the future. */
|
||||
public TaskHandle addDomainRefreshTask(String domainName, Duration countdown) {
|
||||
TaskHandle addDomainRefreshTask(String domainName, Duration countdown) {
|
||||
return addToQueue(
|
||||
TargetType.DOMAIN,
|
||||
domainName,
|
||||
@@ -129,11 +133,6 @@ public class DnsQueue {
|
||||
countdown);
|
||||
}
|
||||
|
||||
/** Adds a task to the queue to refresh the DNS information for the specified zone. */
|
||||
public TaskHandle addZoneRefreshTask(String zoneName) {
|
||||
return addToQueue(TargetType.ZONE, zoneName, zoneName, Duration.ZERO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of tasks that can be leased with {@link #leaseTasks}.
|
||||
*
|
||||
|
||||
74
core/src/main/java/google/registry/dns/DnsUtils.java
Normal file
74
core/src/main/java/google/registry/dns/DnsUtils.java
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2023 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.dns;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import google.registry.model.common.DnsRefreshRequest;
|
||||
import google.registry.model.tld.Registries;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Utility class to handle DNS refresh requests. */
|
||||
// TODO: Make this a static util function once we are done with the DNS pull queue migration.
|
||||
public class DnsUtils {
|
||||
|
||||
private final DnsQueue dnsQueue;
|
||||
|
||||
@Inject
|
||||
DnsUtils(DnsQueue dnsQueue) {
|
||||
this.dnsQueue = dnsQueue;
|
||||
}
|
||||
|
||||
private void requestDnsRefresh(String name, TargetType type, Duration delay) {
|
||||
// Throws an IllegalArgumentException if the name is not under a managed TLD -- we only update
|
||||
// DNS for names that are under our management.
|
||||
String tld = Registries.findTldForNameOrThrow(InternetDomainName.from(name)).toString();
|
||||
if (usePullQueue()) {
|
||||
if (TargetType.HOST.equals(type)) {
|
||||
dnsQueue.addHostRefreshTask(name);
|
||||
} else {
|
||||
dnsQueue.addDomainRefreshTask(name, delay);
|
||||
}
|
||||
} else {
|
||||
tm().transact(
|
||||
() ->
|
||||
tm().insert(
|
||||
new DnsRefreshRequest(
|
||||
type, name, tld, tm().getTransactionTime().plus(delay))));
|
||||
}
|
||||
}
|
||||
|
||||
public void requestDomainDnsRefresh(String domainName, Duration delay) {
|
||||
requestDnsRefresh(domainName, TargetType.DOMAIN, delay);
|
||||
}
|
||||
|
||||
public void requestDomainDnsRefresh(String domainName) {
|
||||
requestDomainDnsRefresh(domainName, Duration.ZERO);
|
||||
}
|
||||
|
||||
public void requestHostDnsRefresh(String hostName) {
|
||||
requestDnsRefresh(hostName, TargetType.HOST, Duration.ZERO);
|
||||
}
|
||||
|
||||
private boolean usePullQueue() {
|
||||
return !DatabaseMigrationStateSchedule.getValueAtTime(dnsQueue.getClock().nowUtc())
|
||||
.equals(MigrationState.DNS_SQL);
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import dagger.Lazy;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.dns.DnsMetrics.ActionStatus;
|
||||
import google.registry.dns.DnsMetrics.CommitStatus;
|
||||
@@ -54,7 +55,6 @@ import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.DomainNameUtils;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.SendEmailService;
|
||||
@@ -85,7 +85,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private final DnsQueue dnsQueue;
|
||||
private final DnsUtils dnsUtils;
|
||||
private final DnsWriterProxy dnsWriterProxy;
|
||||
private final DnsMetrics dnsMetrics;
|
||||
private final Duration timeout;
|
||||
@@ -139,7 +139,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
@Config("gSuiteOutgoingEmailAddress") InternetAddress gSuiteOutgoingEmailAddress,
|
||||
@Header(APP_ENGINE_RETRY_HEADER) Optional<Integer> appEngineRetryCount,
|
||||
@Header(CLOUD_TASKS_RETRY_HEADER) Optional<Integer> cloudTasksRetryCount,
|
||||
DnsQueue dnsQueue,
|
||||
DnsUtils dnsUtils,
|
||||
DnsWriterProxy dnsWriterProxy,
|
||||
DnsMetrics dnsMetrics,
|
||||
LockHandler lockHandler,
|
||||
@@ -147,7 +147,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
CloudTasksUtils cloudTasksUtils,
|
||||
SendEmailService sendEmailService,
|
||||
Response response) {
|
||||
this.dnsQueue = dnsQueue;
|
||||
this.dnsUtils = dnsUtils;
|
||||
this.dnsWriterProxy = dnsWriterProxy;
|
||||
this.dnsMetrics = dnsMetrics;
|
||||
this.timeout = timeout;
|
||||
@@ -339,7 +339,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
DNS_PUBLISH_PUSH_QUEUE_NAME,
|
||||
cloudTasksUtils.createPostTask(
|
||||
PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put(PARAM_TLD, tld)
|
||||
.put(PARAM_DNS_WRITER, dnsWriter)
|
||||
@@ -356,10 +356,10 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
private void requeueBatch() {
|
||||
logger.atInfo().log("Requeueing batch for retry.");
|
||||
for (String domain : nullToEmpty(domains)) {
|
||||
dnsQueue.addDomainRefreshTask(domain);
|
||||
dnsUtils.requestDomainDnsRefresh(domain);
|
||||
}
|
||||
for (String host : nullToEmpty(hosts)) {
|
||||
dnsQueue.addHostRefreshTask(host);
|
||||
dnsUtils.requestHostDnsRefresh(host);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ import com.google.common.collect.Ordering;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hashing;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.tld.Registries;
|
||||
@@ -53,7 +54,6 @@ import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@@ -372,7 +372,7 @@ public final class ReadDnsQueueAction implements Runnable {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
PublishDnsUpdatesAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put(PARAM_TLD, tld)
|
||||
.put(PARAM_DNS_WRITER, dnsWriter)
|
||||
|
||||
@@ -39,7 +39,7 @@ import javax.inject.Inject;
|
||||
public final class RefreshDnsAction implements Runnable {
|
||||
|
||||
private final Clock clock;
|
||||
private final DnsQueue dnsQueue;
|
||||
private final DnsUtils dnsUtils;
|
||||
private final String domainOrHostName;
|
||||
private final TargetType type;
|
||||
|
||||
@@ -48,11 +48,11 @@ public final class RefreshDnsAction implements Runnable {
|
||||
@Parameter("domainOrHostName") String domainOrHostName,
|
||||
@Parameter("type") TargetType type,
|
||||
Clock clock,
|
||||
DnsQueue dnsQueue) {
|
||||
DnsUtils dnsUtils) {
|
||||
this.domainOrHostName = domainOrHostName;
|
||||
this.type = type;
|
||||
this.clock = clock;
|
||||
this.dnsQueue = dnsQueue;
|
||||
this.dnsUtils = dnsUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,11 +63,11 @@ public final class RefreshDnsAction implements Runnable {
|
||||
switch (type) {
|
||||
case DOMAIN:
|
||||
loadAndVerifyExistence(Domain.class, domainOrHostName);
|
||||
dnsQueue.addDomainRefreshTask(domainOrHostName);
|
||||
dnsUtils.requestDomainDnsRefresh(domainOrHostName);
|
||||
break;
|
||||
case HOST:
|
||||
verifyHostIsSubordinate(loadAndVerifyExistence(Host.class, domainOrHostName));
|
||||
dnsQueue.addHostRefreshTask(domainOrHostName);
|
||||
dnsUtils.requestHostDnsRefresh(domainOrHostName);
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("Unsupported type: " + type);
|
||||
|
||||
@@ -45,14 +45,14 @@ public class RefreshDnsOnHostRenameAction implements Runnable {
|
||||
|
||||
private final VKey<Host> hostKey;
|
||||
private final Response response;
|
||||
private final DnsQueue dnsQueue;
|
||||
private final DnsUtils dnsUtils;
|
||||
|
||||
@Inject
|
||||
RefreshDnsOnHostRenameAction(
|
||||
@Parameter(PARAM_HOST_KEY) String hostKey, Response response, DnsQueue dnsQueue) {
|
||||
@Parameter(PARAM_HOST_KEY) String hostKey, Response response, DnsUtils dnsUtils) {
|
||||
this.hostKey = VKey.createEppVKeyFromString(hostKey);
|
||||
this.response = response;
|
||||
this.dnsQueue = dnsQueue;
|
||||
this.dnsUtils = dnsUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,7 +76,7 @@ public class RefreshDnsOnHostRenameAction implements Runnable {
|
||||
.stream()
|
||||
.map(domainKey -> tm().loadByKey(domainKey))
|
||||
.filter(Domain::shouldPublishToDns)
|
||||
.forEach(domain -> dnsQueue.addDomainRefreshTask(domain.getDomainName()));
|
||||
.forEach(domain -> dnsUtils.requestDomainDnsRefresh(domain.getDomainName()));
|
||||
}
|
||||
|
||||
if (!hostValid) {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
</cronentries>
|
||||
@@ -6,6 +6,7 @@
|
||||
<mode>pull</mode>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for publishing DNS updates in batches. -->
|
||||
<queue>
|
||||
<name>dns-publish</name>
|
||||
<rate>100/s</rate>
|
||||
@@ -18,6 +19,7 @@
|
||||
</retry-parameters>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for uploading RDE deposits to the escrow provider. -->
|
||||
<queue>
|
||||
<name>rde-upload</name>
|
||||
<rate>10/m</rate>
|
||||
@@ -28,6 +30,7 @@
|
||||
</retry-parameters>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for uploading RDE reports to ICANN. -->
|
||||
<queue>
|
||||
<name>rde-report</name>
|
||||
<rate>1/s</rate>
|
||||
@@ -37,6 +40,7 @@
|
||||
</retry-parameters>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for copying BRDA deposits to GCS. -->
|
||||
<queue>
|
||||
<name>brda</name>
|
||||
<rate>1/m</rate>
|
||||
@@ -74,7 +78,7 @@
|
||||
</retry-parameters>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for tasks to produce LORDN CSV reports, either by the query or queue method. -->
|
||||
<!-- Queue for tasks to produce LORDN CSV reports, populated by a Cloud Scheduler fanout job. -->
|
||||
<queue>
|
||||
<name>nordn</name>
|
||||
<rate>1/s</rate>
|
||||
@@ -84,18 +88,6 @@
|
||||
</retry-parameters>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for LORDN Claims CSV rows to be periodically queried and then uploaded in batches. -->
|
||||
<queue>
|
||||
<name>lordn-claims</name>
|
||||
<mode>pull</mode>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for LORDN Sunrise CSV rows to be periodically queried and then uploaded in batches. -->
|
||||
<queue>
|
||||
<name>lordn-sunrise</name>
|
||||
<mode>pull</mode>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for tasks that sync data to Google Spreadsheets. -->
|
||||
<queue>
|
||||
<name>sheet</name>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
</cronentries>
|
||||
@@ -7,7 +7,7 @@
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<manual-scaling>
|
||||
<instances>12</instances>
|
||||
<instances>24</instances>
|
||||
</manual-scaling>
|
||||
|
||||
<system-properties>
|
||||
|
||||
@@ -90,7 +90,18 @@
|
||||
<schedule>0 */1 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<!-- TODO: @ptkach add resaveAllEppResourcesPipelineAction https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/env/production/default/WEB-INF/cron.xml;l=105 -->
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<name>resaveAllEppResourcesPipeline</name>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<!--
|
||||
Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
|
||||
with 1st of the month 09:00
|
||||
-->
|
||||
<schedule>0 9 1 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/updateRegistrarRdapBaseUrls]]></url>
|
||||
@@ -162,30 +173,6 @@
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=sunrise&pullQueue]]></url>
|
||||
<name>nordnUploadSunrisePullQueue</name>
|
||||
<description>
|
||||
This job uploads LORDN Sunrise CSV files for each TLD to MarksDB using
|
||||
pull queue. It should be run at most every three hours, or at absolute
|
||||
minimum every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=claims&pullQueue]]></url>
|
||||
<name>nordnUploadClaimsPullQueue</name>
|
||||
<description>
|
||||
This job uploads LORDN Claims CSV files for each TLD to MarksDB using pull
|
||||
queue. It should be run at most every three hours, or at absolute minimum
|
||||
every 26 hours.
|
||||
</description>
|
||||
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
|
||||
<schedule>0 */12 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
|
||||
<name>deleteProberData</name>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
</cronentries>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
|
||||
<cronentries>
|
||||
|
||||
</cronentries>
|
||||
@@ -11,9 +11,6 @@
|
||||
<!--
|
||||
This only needs to run once per day, but we launch additional jobs in case the
|
||||
cursor is lagging behind, so it'll catch up to the current date eventually.
|
||||
|
||||
See <a href="../../../production/default/WEB-INF/cron.xml">production config</a> for an
|
||||
explanation of job starting times.
|
||||
-->
|
||||
<schedule>7 */12 * * *</schedule>
|
||||
</task>
|
||||
@@ -95,6 +92,19 @@
|
||||
<schedule>0 3 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
|
||||
<name>resaveAllEppResourcesPipeline</name>
|
||||
<description>
|
||||
This job resaves all our resources, projected in time to "now".
|
||||
</description>
|
||||
<!--
|
||||
Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
|
||||
with 1st of the month 09:00
|
||||
-->
|
||||
<schedule>0 9 1 * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
|
||||
<name>deleteExpiredDomains</name>
|
||||
@@ -132,8 +142,6 @@
|
||||
<schedule>0 5 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<!-- TODO: @ptkach add resaveAllEppResourcesPipelineAction https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/env/sandbox/default/WEB-INF/cron.xml;l=89 -->
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<name>readDnsQueue</name>
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.flows.EppException;
|
||||
@@ -116,6 +117,7 @@ import org.joda.time.DateTime;
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_CHECK)
|
||||
public final class DomainCheckFlow implements Flow {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
@Inject ResourceCommand resourceCommand;
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject EppInput eppInput;
|
||||
@@ -271,6 +273,12 @@ public final class DomainCheckFlow implements Flow {
|
||||
|
||||
for (FeeCheckCommandExtensionItem feeCheckItem : feeCheck.getItems()) {
|
||||
for (String domainName : getDomainNamesToCheckForFee(feeCheckItem, domainNames.keySet())) {
|
||||
Optional<AllocationToken> defaultToken =
|
||||
DomainFlowUtils.checkForDefaultToken(
|
||||
Registry.get(InternetDomainName.from(domainName).parent().toString()),
|
||||
domainName,
|
||||
registrarId,
|
||||
now);
|
||||
FeeCheckResponseExtensionItem.Builder<?> builder = feeCheckItem.createResponseBuilder();
|
||||
Optional<Domain> domain = Optional.ofNullable(domainObjs.get(domainName));
|
||||
handleFeeRequest(
|
||||
@@ -281,7 +289,7 @@ public final class DomainCheckFlow implements Flow {
|
||||
feeCheck.getCurrency(),
|
||||
now,
|
||||
pricingLogic,
|
||||
allocationToken,
|
||||
allocationToken.isPresent() ? allocationToken : defaultToken,
|
||||
availableDomains.contains(domainName),
|
||||
recurrences.getOrDefault(domainName, null));
|
||||
responseItems.add(builder.setDomainNameIfSupported(domainName).build());
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.flows.FlowUtils.persistEntityChanges;
|
||||
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
|
||||
@@ -54,7 +52,6 @@ import static google.registry.model.tld.Registry.TldState.QUIET_PERIOD;
|
||||
import static google.registry.model.tld.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.model.tld.label.ReservationType.NAME_COLLISION;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
|
||||
|
||||
@@ -62,9 +59,8 @@ import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.AssociationProhibitsOperationException;
|
||||
import google.registry.flows.EppException.CommandUseErrorException;
|
||||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
@@ -86,8 +82,6 @@ import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.DomainCommand.Create;
|
||||
@@ -123,10 +117,7 @@ import google.registry.model.tld.Registry.TldType;
|
||||
import google.registry.model.tld.label.ReservationType;
|
||||
import google.registry.model.tmch.ClaimsList;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.tmch.LordnTaskUtils;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
@@ -235,7 +226,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
@Inject DomainCreateFlowCustomLogic flowCustomLogic;
|
||||
@Inject DomainFlowTmchUtils tmchUtils;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
|
||||
@Inject DomainCreateFlow() {}
|
||||
|
||||
@Override
|
||||
@@ -273,6 +265,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
validateLaunchCreateNotice(launchCreate.get().getNotice(), domainLabel, isSuperuser, now);
|
||||
}
|
||||
boolean isSunriseCreate = hasSignedMarks && (tldState == START_DATE_SUNRISE);
|
||||
// TODO(sarahbot@): Add check for valid EPP actions on the token
|
||||
Optional<AllocationToken> allocationToken =
|
||||
allocationTokenFlowUtils.verifyAllocationTokenCreateIfPresent(
|
||||
command,
|
||||
@@ -282,7 +275,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
boolean defaultTokenUsed = false;
|
||||
if (!allocationToken.isPresent() && !registry.getDefaultPromoTokens().isEmpty()) {
|
||||
allocationToken = checkForDefaultToken(registry, command);
|
||||
allocationToken =
|
||||
DomainFlowUtils.checkForDefaultToken(registry, command.getDomainName(), registrarId, now);
|
||||
if (allocationToken.isPresent()) {
|
||||
defaultTokenUsed = true;
|
||||
}
|
||||
@@ -405,12 +399,9 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
.addGracePeriod(
|
||||
GracePeriod.forBillingEvent(GracePeriodStatus.ADD, repoId, createBillingEvent))
|
||||
.setLordnPhase(
|
||||
!DatabaseMigrationStateSchedule.getValueAtTime(tm().getTransactionTime())
|
||||
.equals(MigrationState.NORDN_SQL)
|
||||
? LordnPhase.NONE
|
||||
: hasSignedMarks
|
||||
? LordnPhase.SUNRISE
|
||||
: hasClaimsNotice ? LordnPhase.CLAIMS : LordnPhase.NONE);
|
||||
hasSignedMarks
|
||||
? LordnPhase.SUNRISE
|
||||
: hasClaimsNotice ? LordnPhase.CLAIMS : LordnPhase.NONE);
|
||||
Domain domain = domainBuilder.build();
|
||||
if (allocationToken.isPresent()
|
||||
&& allocationToken.get().getTokenType().equals(TokenType.PACKAGE)) {
|
||||
@@ -433,8 +424,9 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
allocationTokenFlowUtils.redeemToken(
|
||||
allocationToken.get(), domainHistory.getHistoryEntryId()));
|
||||
}
|
||||
enqueueTasks(domain, hasSignedMarks, hasClaimsNotice);
|
||||
|
||||
if (domain.shouldPublishToDns()) {
|
||||
dnsUtils.requestDomainDnsRefresh(domain.getDomainName());
|
||||
}
|
||||
EntityChanges entityChanges =
|
||||
flowCustomLogic.beforeSave(
|
||||
DomainCreateFlowCustomLogic.BeforeSaveParameters.newBuilder()
|
||||
@@ -458,36 +450,6 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
.build();
|
||||
}
|
||||
|
||||
private Optional<AllocationToken> checkForDefaultToken(
|
||||
Registry registry, DomainCommand.Create command) throws EppException {
|
||||
Map<VKey<AllocationToken>, Optional<AllocationToken>> tokens =
|
||||
AllocationToken.getAll(registry.getDefaultPromoTokens());
|
||||
ImmutableList<Optional<AllocationToken>> tokenList =
|
||||
registry.getDefaultPromoTokens().stream()
|
||||
.map(tokens::get)
|
||||
.filter(Optional::isPresent)
|
||||
.collect(toImmutableList());
|
||||
checkState(
|
||||
!isNullOrEmpty(tokenList),
|
||||
"Failure while loading default TLD promotions from the database");
|
||||
// Check if any of the tokens are valid for this domain registration
|
||||
for (Optional<AllocationToken> token : tokenList) {
|
||||
try {
|
||||
AllocationTokenFlowUtils.validateToken(
|
||||
InternetDomainName.from(command.getDomainName()),
|
||||
token.get(),
|
||||
registrarId,
|
||||
tm().getTransactionTime());
|
||||
} catch (AssociationProhibitsOperationException e) {
|
||||
// Allocation token was not valid for this registration, continue to check the next token in
|
||||
// the list
|
||||
continue;
|
||||
}
|
||||
// Only use the first valid token in the list
|
||||
return token;
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
/**
|
||||
* Verifies that signed marks are only sent during sunrise.
|
||||
*
|
||||
@@ -707,17 +669,6 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
.build();
|
||||
}
|
||||
|
||||
private void enqueueTasks(Domain newDomain, boolean hasSignedMarks, boolean hasClaimsNotice) {
|
||||
if (newDomain.shouldPublishToDns()) {
|
||||
dnsQueue.addDomainRefreshTask(newDomain.getDomainName());
|
||||
}
|
||||
if (!DatabaseMigrationStateSchedule.getValueAtTime(tm().getTransactionTime())
|
||||
.equals(MigrationState.NORDN_SQL)
|
||||
&& (hasClaimsNotice || hasSignedMarks)) {
|
||||
LordnTaskUtils.enqueueDomainTask(newDomain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the {@link RenewalPriceBehavior} and the renewal price that needs be stored in the
|
||||
* {@link Recurring} billing events.
|
||||
|
||||
@@ -44,7 +44,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.AssociationProhibitsOperationException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
@@ -129,7 +129,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject DomainHistory.Builder historyBuilder;
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
@Inject Trid trid;
|
||||
@Inject AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@@ -260,7 +260,7 @@ public final class DomainDeleteFlow implements TransactionalFlow {
|
||||
// If there's a pending transfer, the gaining client's autorenew billing
|
||||
// event and poll message will already have been deleted in
|
||||
// ResourceDeleteFlow since it's listed in serverApproveEntities.
|
||||
dnsQueue.addDomainRefreshTask(existingDomain.getDomainName());
|
||||
dnsUtils.requestDomainDnsRefresh(existingDomain.getDomainName());
|
||||
|
||||
entitiesToSave.add(newDomain, domainHistory);
|
||||
EntityChanges entityChanges =
|
||||
|
||||
@@ -39,6 +39,7 @@ import static google.registry.model.tld.label.ReservationType.RESERVED_FOR_ANCHO
|
||||
import static google.registry.model.tld.label.ReservationType.RESERVED_FOR_SPECIFIC_USE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
@@ -63,6 +64,7 @@ import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.AssociationProhibitsOperationException;
|
||||
import google.registry.flows.EppException.AuthorizationErrorException;
|
||||
import google.registry.flows.EppException.CommandUseErrorException;
|
||||
import google.registry.flows.EppException.ObjectDoesNotExistException;
|
||||
@@ -72,6 +74,7 @@ import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
|
||||
import google.registry.flows.EppException.RequiredParameterMissingException;
|
||||
import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||
import google.registry.flows.EppException.UnimplementedOptionException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils;
|
||||
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
@@ -671,6 +674,8 @@ public class DomainFlowUtils {
|
||||
String feeClass = null;
|
||||
ImmutableList<Fee> fees = ImmutableList.of();
|
||||
switch (feeRequest.getCommandName()) {
|
||||
// TODO(sarahbot@): Add check of valid EPP actions on token before passing the token to the
|
||||
// fee request.
|
||||
case CREATE:
|
||||
// Don't return a create price for reserved names.
|
||||
if (isReserved(domainName, isSunrise) && !isAvailable) {
|
||||
@@ -695,7 +700,8 @@ public class DomainFlowUtils {
|
||||
builder.setAvailIfSupported(true);
|
||||
fees =
|
||||
pricingLogic
|
||||
.getRenewPrice(registry, domainNameString, now, years, recurringBillingEvent)
|
||||
.getRenewPrice(
|
||||
registry, domainNameString, now, years, recurringBillingEvent, allocationToken)
|
||||
.getFees();
|
||||
break;
|
||||
case RESTORE:
|
||||
@@ -1191,6 +1197,44 @@ public class DomainFlowUtils {
|
||||
.getResultList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a valid default token to be used for a domain create command.
|
||||
*
|
||||
* <p>If there is more than one valid default token for the registration, only the first valid
|
||||
* token found on the TLD's default token list will be returned.
|
||||
*/
|
||||
public static Optional<AllocationToken> checkForDefaultToken(
|
||||
Registry registry, String domainName, String registrarId, DateTime now) throws EppException {
|
||||
if (isNullOrEmpty(registry.getDefaultPromoTokens())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Map<VKey<AllocationToken>, Optional<AllocationToken>> tokens =
|
||||
AllocationToken.getAll(registry.getDefaultPromoTokens());
|
||||
ImmutableList<Optional<AllocationToken>> tokenList =
|
||||
registry.getDefaultPromoTokens().stream()
|
||||
.map(tokens::get)
|
||||
.filter(Optional::isPresent)
|
||||
.collect(toImmutableList());
|
||||
checkState(
|
||||
!isNullOrEmpty(tokenList),
|
||||
"Failure while loading default TLD promotions from the database");
|
||||
// Check if any of the tokens are valid for this domain registration
|
||||
for (Optional<AllocationToken> token : tokenList) {
|
||||
try {
|
||||
AllocationTokenFlowUtils.validateToken(
|
||||
InternetDomainName.from(domainName), token.get(), registrarId, now);
|
||||
} catch (AssociationProhibitsOperationException | StatusProhibitsOperationException e) {
|
||||
// Allocation token was not valid for this registration, continue to check the next token in
|
||||
// the list
|
||||
continue;
|
||||
}
|
||||
// Only use the first valid token in the list
|
||||
return token;
|
||||
}
|
||||
// No valid default token found
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/** Resource linked to this domain does not exist. */
|
||||
static class LinkedResourcesDoNotExistException extends ObjectDoesNotExistException {
|
||||
public LinkedResourcesDoNotExistException(Class<?> type, ImmutableSet<String> resourceIds) {
|
||||
|
||||
@@ -34,6 +34,7 @@ import google.registry.model.domain.fee.BaseFee;
|
||||
import google.registry.model.domain.fee.BaseFee.FeeType;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenBehavior;
|
||||
import google.registry.model.pricing.PremiumPricingEngine.DomainPrices;
|
||||
import google.registry.model.tld.Registry;
|
||||
import java.math.RoundingMode;
|
||||
@@ -112,21 +113,22 @@ public final class DomainPricingLogic {
|
||||
String domainName,
|
||||
DateTime dateTime,
|
||||
int years,
|
||||
@Nullable Recurring recurringBillingEvent) {
|
||||
@Nullable Recurring recurringBillingEvent,
|
||||
Optional<AllocationToken> allocationToken)
|
||||
throws AllocationTokenInvalidForPremiumNameException {
|
||||
checkArgument(years > 0, "Number of years must be positive");
|
||||
Money renewCost;
|
||||
DomainPrices domainPrices = getPricesForDomainName(domainName, dateTime);
|
||||
boolean isRenewCostPremiumPrice;
|
||||
// recurring billing event is null if the domain is still available. Billing events are created
|
||||
// in the process of domain creation.
|
||||
if (recurringBillingEvent == null) {
|
||||
DomainPrices domainPrices = getPricesForDomainName(domainName, dateTime);
|
||||
renewCost = domainPrices.getRenewCost().multipliedBy(years);
|
||||
renewCost = getDomainRenewCostWithDiscount(domainPrices, years, allocationToken);
|
||||
isRenewCostPremiumPrice = domainPrices.isPremium();
|
||||
} else {
|
||||
switch (recurringBillingEvent.getRenewalPriceBehavior()) {
|
||||
case DEFAULT:
|
||||
DomainPrices domainPrices = getPricesForDomainName(domainName, dateTime);
|
||||
renewCost = domainPrices.getRenewCost().multipliedBy(years);
|
||||
renewCost = getDomainRenewCostWithDiscount(domainPrices, years, allocationToken);
|
||||
isRenewCostPremiumPrice = domainPrices.isPremium();
|
||||
break;
|
||||
// if the renewal price behavior is specified, then the renewal price should be the same
|
||||
@@ -136,6 +138,7 @@ public final class DomainPricingLogic {
|
||||
recurringBillingEvent.getRenewalPrice(),
|
||||
"Unexpected behavior: renewal price cannot be null when renewal behavior is"
|
||||
+ " SPECIFIED");
|
||||
// Don't apply allocation token to renewal price when SPECIFIED
|
||||
renewCost = recurringBillingEvent.getRenewalPrice().get().multipliedBy(years);
|
||||
isRenewCostPremiumPrice = false;
|
||||
break;
|
||||
@@ -143,9 +146,11 @@ public final class DomainPricingLogic {
|
||||
// at standard price of domains at the time, even if the domain is premium
|
||||
case NONPREMIUM:
|
||||
renewCost =
|
||||
Registry.get(getTldFromDomainName(domainName))
|
||||
.getStandardRenewCost(dateTime)
|
||||
.multipliedBy(years);
|
||||
getDomainCostWithDiscount(
|
||||
false,
|
||||
years,
|
||||
allocationToken,
|
||||
Registry.get(getTldFromDomainName(domainName)).getStandardRenewCost(dateTime));
|
||||
isRenewCostPremiumPrice = false;
|
||||
break;
|
||||
default:
|
||||
@@ -202,7 +207,7 @@ public final class DomainPricingLogic {
|
||||
@Nullable Recurring recurringBillingEvent)
|
||||
throws EppException {
|
||||
FeesAndCredits renewPrice =
|
||||
getRenewPrice(registry, domainName, dateTime, 1, recurringBillingEvent);
|
||||
getRenewPrice(registry, domainName, dateTime, 1, recurringBillingEvent, Optional.empty());
|
||||
return customLogic.customizeTransferPrice(
|
||||
TransferPriceParameters.newBuilder()
|
||||
.setFeesAndCredits(
|
||||
@@ -242,25 +247,40 @@ public final class DomainPricingLogic {
|
||||
private Money getDomainCreateCostWithDiscount(
|
||||
DomainPrices domainPrices, int years, Optional<AllocationToken> allocationToken)
|
||||
throws EppException {
|
||||
return getDomainCostWithDiscount(
|
||||
domainPrices.isPremium(), years, allocationToken, domainPrices.getCreateCost());
|
||||
}
|
||||
|
||||
/** Returns the domain renew cost with allocation-token-related discounts applied. */
|
||||
private Money getDomainRenewCostWithDiscount(
|
||||
DomainPrices domainPrices, int years, Optional<AllocationToken> allocationToken)
|
||||
throws AllocationTokenInvalidForPremiumNameException {
|
||||
return getDomainCostWithDiscount(
|
||||
domainPrices.isPremium(), years, allocationToken, domainPrices.getRenewCost());
|
||||
}
|
||||
|
||||
private Money getDomainCostWithDiscount(
|
||||
boolean isPremium, int years, Optional<AllocationToken> allocationToken, Money oneYearCost)
|
||||
throws AllocationTokenInvalidForPremiumNameException {
|
||||
if (allocationToken.isPresent()
|
||||
&& allocationToken.get().getDiscountFraction() != 0.0
|
||||
&& domainPrices.isPremium()
|
||||
&& isPremium
|
||||
&& !allocationToken.get().shouldDiscountPremiums()) {
|
||||
throw new AllocationTokenInvalidForPremiumNameException();
|
||||
}
|
||||
Money oneYearCreateCost = domainPrices.getCreateCost();
|
||||
Money totalDomainCreateCost = oneYearCreateCost.multipliedBy(years);
|
||||
Money totalDomainFlowCost = oneYearCost.multipliedBy(years);
|
||||
|
||||
// Apply the allocation token discount, if applicable.
|
||||
if (allocationToken.isPresent()) {
|
||||
if (allocationToken.isPresent()
|
||||
&& allocationToken.get().getTokenBehavior().equals(TokenBehavior.DEFAULT)) {
|
||||
int discountedYears = Math.min(years, allocationToken.get().getDiscountYears());
|
||||
Money discount =
|
||||
oneYearCreateCost.multipliedBy(
|
||||
oneYearCost.multipliedBy(
|
||||
discountedYears * allocationToken.get().getDiscountFraction(),
|
||||
RoundingMode.HALF_EVEN);
|
||||
totalDomainCreateCost = totalDomainCreateCost.minus(discount);
|
||||
totalDomainFlowCost = totalDomainFlowCost.minus(discount);
|
||||
}
|
||||
return totalDomainCreateCost;
|
||||
return totalDomainFlowCost;
|
||||
}
|
||||
|
||||
/** An allocation token was provided that is invalid for premium domains. */
|
||||
|
||||
@@ -172,6 +172,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
|
||||
Renew command = (Renew) resourceCommand;
|
||||
// Loads the target resource if it exists
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
// TODO(sarahbot@): Add check for valid EPP actions on the token
|
||||
Optional<AllocationToken> allocationToken =
|
||||
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
|
||||
existingDomain,
|
||||
@@ -198,7 +199,8 @@ public final class DomainRenewFlow implements TransactionalFlow {
|
||||
targetId,
|
||||
now,
|
||||
years,
|
||||
existingRecurringBillingEvent);
|
||||
existingRecurringBillingEvent,
|
||||
allocationToken);
|
||||
validateFeeChallenge(feeRenew, feesAndCredits, false);
|
||||
flowCustomLogic.afterValidation(
|
||||
AfterValidationParameters.newBuilder()
|
||||
|
||||
@@ -34,7 +34,7 @@ import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.CommandUseErrorException;
|
||||
import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||
@@ -122,7 +122,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject DomainHistory.Builder historyBuilder;
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@Inject DomainRestoreRequestFlow() {}
|
||||
@@ -186,7 +186,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
|
||||
entitiesToSave.add(newDomain, domainHistory, autorenewEvent, autorenewPollMessage);
|
||||
tm().putAll(entitiesToSave.build());
|
||||
tm().delete(existingDomain.getDeletePollMessage());
|
||||
dnsQueue.addDomainRefreshTask(existingDomain.getDomainName());
|
||||
dnsUtils.requestDomainDnsRefresh(existingDomain.getDomainName());
|
||||
return responseBuilder
|
||||
.setExtensions(createResponseExtensions(feesAndCredits, feeUpdate, isExpired))
|
||||
.build();
|
||||
|
||||
@@ -49,7 +49,7 @@ import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.RegistrarId;
|
||||
@@ -156,7 +156,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject Trid trid;
|
||||
@Inject DomainHistory.Builder historyBuilder;
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject DomainUpdateFlowCustomLogic flowCustomLogic;
|
||||
@Inject DomainPricingLogic pricingLogic;
|
||||
@@ -183,7 +183,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
|
||||
historyBuilder.setType(DOMAIN_UPDATE).setDomain(newDomain).build();
|
||||
validateNewState(newDomain);
|
||||
if (requiresDnsUpdate(existingDomain, newDomain)) {
|
||||
dnsQueue.addDomainRefreshTask(targetId);
|
||||
dnsUtils.requestDomainDnsRefresh(targetId);
|
||||
}
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
entitiesToSave.add(newDomain, domainHistory);
|
||||
|
||||
@@ -28,7 +28,7 @@ import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.ParameterValueRangeErrorException;
|
||||
import google.registry.flows.EppException.RequiredParameterMissingException;
|
||||
@@ -85,7 +85,7 @@ public final class HostCreateFlow implements TransactionalFlow {
|
||||
@Inject @RegistrarId String registrarId;
|
||||
@Inject @TargetId String targetId;
|
||||
@Inject HostHistory.Builder historyBuilder;
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
|
||||
@Inject
|
||||
@@ -138,7 +138,7 @@ public final class HostCreateFlow implements TransactionalFlow {
|
||||
.build());
|
||||
// Only update DNS if this is a subordinate host. External hosts have no glue to write, so
|
||||
// they are only written as NS records from the referencing domain.
|
||||
dnsQueue.addHostRefreshTask(targetId);
|
||||
dnsUtils.requestHostDnsRefresh(targetId);
|
||||
}
|
||||
tm().insertAll(entitiesToSave);
|
||||
return responseBuilder.setResData(HostCreateData.create(targetId, now)).build();
|
||||
|
||||
@@ -24,7 +24,7 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.RegistrarId;
|
||||
@@ -71,7 +71,7 @@ public final class HostDeleteFlow implements TransactionalFlow {
|
||||
StatusValue.PENDING_DELETE,
|
||||
StatusValue.SERVER_DELETE_PROHIBITED);
|
||||
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
@Inject ExtensionManager extensionManager;
|
||||
@Inject @RegistrarId String registrarId;
|
||||
@Inject @TargetId String targetId;
|
||||
@@ -104,7 +104,7 @@ public final class HostDeleteFlow implements TransactionalFlow {
|
||||
}
|
||||
Host newHost = existingHost.asBuilder().setStatusValues(null).setDeletionTime(now).build();
|
||||
if (existingHost.isSubordinate()) {
|
||||
dnsQueue.addHostRefreshTask(existingHost.getHostName());
|
||||
dnsUtils.requestHostDnsRefresh(existingHost.getHostName());
|
||||
tm().update(
|
||||
tm().loadByKey(existingHost.getSuperordinateDomain())
|
||||
.asBuilder()
|
||||
|
||||
@@ -36,7 +36,8 @@ import com.google.cloud.tasks.v2.Task;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.dns.RefreshDnsOnHostRenameAction;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.ObjectAlreadyExistsException;
|
||||
@@ -65,7 +66,6 @@ import google.registry.model.host.HostHistory;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
@@ -124,7 +124,7 @@ public final class HostUpdateFlow implements TransactionalFlow {
|
||||
@Inject @Superuser boolean isSuperuser;
|
||||
@Inject HostHistory.Builder historyBuilder;
|
||||
@Inject AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject CloudTasksUtils cloudTasksUtils;
|
||||
|
||||
@@ -266,21 +266,21 @@ public final class HostUpdateFlow implements TransactionalFlow {
|
||||
// Only update DNS for subordinate hosts. External hosts have no glue to write, so they
|
||||
// are only written as NS records from the referencing domain.
|
||||
if (existingHost.isSubordinate()) {
|
||||
dnsQueue.addHostRefreshTask(existingHost.getHostName());
|
||||
dnsUtils.requestHostDnsRefresh(existingHost.getHostName());
|
||||
}
|
||||
// In case of a rename, there are many updates we need to queue up.
|
||||
if (((Update) resourceCommand).getInnerChange().getHostName() != null) {
|
||||
// If the renamed host is also subordinate, then we must enqueue an update to write the new
|
||||
// glue.
|
||||
if (newHost.isSubordinate()) {
|
||||
dnsQueue.addHostRefreshTask(newHost.getHostName());
|
||||
dnsUtils.requestHostDnsRefresh(newHost.getHostName());
|
||||
}
|
||||
// We must also enqueue updates for all domains that use this host as their nameserver so
|
||||
// that their NS records can be updated to point at the new name.
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTask(
|
||||
RefreshDnsOnHostRenameAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(PARAM_HOST_KEY, existingHost.createVKey().stringify()));
|
||||
cloudTasksUtils.enqueue(QUEUE_HOST_RENAME, task);
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.protobuf.Timestamp;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
@@ -337,7 +337,7 @@ public class LoadTestAction implements Runnable {
|
||||
cloudTasksUtils
|
||||
.createPostTask(
|
||||
"/_dr/epptool",
|
||||
Service.TOOLS.toString(),
|
||||
Service.TOOLS,
|
||||
ImmutableMultimap.of(
|
||||
"clientId",
|
||||
registrarId,
|
||||
|
||||
@@ -90,7 +90,10 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
SEQUENCE_BASED_ALLOCATE_ID(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY),
|
||||
|
||||
/** Use SQL-based Nordn upload flow instead of the pull queue-based one. */
|
||||
NORDN_SQL(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY);
|
||||
NORDN_SQL(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY),
|
||||
|
||||
/** Use SQL-based DNS update flow instead of the pull queue-based one. */
|
||||
DNS_SQL(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY);
|
||||
|
||||
private final PrimaryDatabase primaryDatabase;
|
||||
private final boolean isReadOnly;
|
||||
@@ -171,7 +174,11 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
|
||||
MigrationState.SQL_PRIMARY)
|
||||
.putAll(MigrationState.SQL_ONLY, MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
.putAll(MigrationState.SEQUENCE_BASED_ALLOCATE_ID, MigrationState.NORDN_SQL)
|
||||
.putAll(MigrationState.NORDN_SQL, MigrationState.SEQUENCE_BASED_ALLOCATE_ID);
|
||||
.putAll(
|
||||
MigrationState.NORDN_SQL,
|
||||
MigrationState.SEQUENCE_BASED_ALLOCATE_ID,
|
||||
MigrationState.DNS_SQL)
|
||||
.putAll(MigrationState.DNS_SQL, MigrationState.NORDN_SQL);
|
||||
|
||||
// In addition, we can always transition from a state to itself (useful when updating the map).
|
||||
Arrays.stream(MigrationState.values()).forEach(state -> builder.put(state, state));
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright 2023 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.model.common;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.dns.PublishDnsUpdatesAction;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@Entity
|
||||
@Table(indexes = {@Index(columnList = "requestTime"), @Index(columnList = "lastProcessTime")})
|
||||
public class DnsRefreshRequest extends ImmutableObject {
|
||||
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Id
|
||||
@SuppressWarnings("unused")
|
||||
protected long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private TargetType type;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String tld;
|
||||
|
||||
@Column(nullable = false)
|
||||
private DateTime requestTime;
|
||||
|
||||
@Column(nullable = false)
|
||||
private DateTime lastProcessTime;
|
||||
|
||||
public TargetType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getTld() {
|
||||
return tld;
|
||||
}
|
||||
|
||||
public DateTime getRequestTime() {
|
||||
return requestTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The time at which the entity was last processed.
|
||||
*
|
||||
* <p>Note that "processed" means that it was read, not necessarily that the DNS request was
|
||||
* processed successfully. The subsequent steps to bundle requests together and enqueue them in a
|
||||
* Cloud Tasks queue for {@link PublishDnsUpdatesAction} to process can still fail.
|
||||
*
|
||||
* <p>This value allows us to control if a row is just recently read and should be skipped, should
|
||||
* there are concurrent reads that all attempt to read the rows with oldest {@link #requestTime},
|
||||
* or another read that comes too early after the previous read.
|
||||
*/
|
||||
public DateTime getLastProcessTime() {
|
||||
return lastProcessTime;
|
||||
}
|
||||
|
||||
protected DnsRefreshRequest() {}
|
||||
|
||||
private DnsRefreshRequest(
|
||||
@Nullable Long id,
|
||||
TargetType type,
|
||||
String name,
|
||||
String tld,
|
||||
DateTime requestTime,
|
||||
DateTime lastProcessTime) {
|
||||
checkNotNull(type, "Target type cannot be null");
|
||||
checkNotNull(name, "Domain/host name cannot be null");
|
||||
checkNotNull(tld, "TLD cannot be null");
|
||||
checkNotNull(requestTime, "Request time cannot be null");
|
||||
checkNotNull(lastProcessTime, "Last process time cannot be null");
|
||||
if (id != null) {
|
||||
this.id = id;
|
||||
}
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.tld = tld;
|
||||
this.requestTime = requestTime;
|
||||
this.lastProcessTime = lastProcessTime;
|
||||
}
|
||||
|
||||
public DnsRefreshRequest(TargetType type, String name, String tld, DateTime requestTime) {
|
||||
this(null, type, name, tld, requestTime, START_OF_TIME);
|
||||
}
|
||||
|
||||
public DnsRefreshRequest updateProcessTime(DateTime processTime) {
|
||||
checkArgument(
|
||||
processTime.isAfter(getRequestTime()),
|
||||
"Process time %s must be later than request time %s",
|
||||
processTime,
|
||||
getRequestTime());
|
||||
checkArgument(
|
||||
processTime.isAfter(getLastProcessTime()),
|
||||
"New process time %s must be later than the old one %s",
|
||||
processTime,
|
||||
getLastProcessTime());
|
||||
return new DnsRefreshRequest(id, getType(), getName(), getTld(), getRequestTime(), processTime);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.UpdateAutoTimestampEntity;
|
||||
import google.registry.persistence.VKey;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
@@ -47,7 +48,6 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
private Long id;
|
||||
|
||||
/** GAIA ID associated with the user in question. */
|
||||
@Column(nullable = false)
|
||||
private String gaiaId;
|
||||
|
||||
/** Email address of the user in question. */
|
||||
@@ -118,6 +118,11 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
return new Builder(clone(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VKey<User> createVKey() {
|
||||
return VKey.create(User.class, getId());
|
||||
}
|
||||
|
||||
/** Builder for constructing immutable {@link User} objects. */
|
||||
public static class Builder extends Buildable.Builder<User> {
|
||||
|
||||
@@ -129,7 +134,6 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
|
||||
@Override
|
||||
public User build() {
|
||||
checkArgumentNotNull(getInstance().gaiaId, "Gaia ID cannot be null");
|
||||
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
|
||||
checkArgumentNotNull(getInstance().userRoles, "User roles cannot be null");
|
||||
return super.build();
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package google.registry.model.domain.fee;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.Period;
|
||||
import java.util.Optional;
|
||||
@@ -37,7 +39,19 @@ public abstract class FeeQueryCommandExtensionItem extends ImmutableObject {
|
||||
RENEW,
|
||||
TRANSFER,
|
||||
RESTORE,
|
||||
UPDATE
|
||||
UPDATE;
|
||||
|
||||
public static CommandName parseKnownCommand(String string) {
|
||||
try {
|
||||
CommandName command = valueOf(string);
|
||||
checkArgument(!command.equals(UNKNOWN));
|
||||
return command;
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid EPP action name. Valid actions are CREATE, RENEW, TRANSFER, RESTORE, and"
|
||||
+ " UPDATE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The default validity period (if not specified) is 1 year for all operations. */
|
||||
|
||||
@@ -45,6 +45,7 @@ import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.UpdateAutoTimestampEntity;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.common.TimedTransitionProperty;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.WithVKey;
|
||||
@@ -213,6 +214,9 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
|
||||
TimedTransitionProperty<TokenStatus> tokenStatusTransitions =
|
||||
TimedTransitionProperty.withInitialValue(NOT_STARTED);
|
||||
|
||||
/** Allowed EPP actions for this token, or null if all actions are allowed. */
|
||||
@Nullable Set<CommandName> allowedEppActions;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
@@ -263,6 +267,10 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
|
||||
return tokenStatusTransitions;
|
||||
}
|
||||
|
||||
public ImmutableSet<CommandName> getAllowedEppActions() {
|
||||
return nullToEmptyImmutableCopy(allowedEppActions);
|
||||
}
|
||||
|
||||
public RenewalPriceBehavior getRenewalPriceBehavior() {
|
||||
return renewalPriceBehavior;
|
||||
}
|
||||
@@ -450,6 +458,11 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAllowedEppActions(Set<CommandName> allowedEppActions) {
|
||||
getInstance().allowedEppActions = forceEmptyToNull(allowedEppActions);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRenewalPriceBehavior(RenewalPriceBehavior renewalPriceBehavior) {
|
||||
getInstance().renewalPriceBehavior = renewalPriceBehavior;
|
||||
return this;
|
||||
|
||||
@@ -25,8 +25,6 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import google.registry.util.RequestStatusCheckerImpl;
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
@@ -70,8 +68,7 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
enum LockState {
|
||||
IN_USE,
|
||||
FREE,
|
||||
TIMED_OUT,
|
||||
OWNER_DIED
|
||||
TIMED_OUT
|
||||
}
|
||||
|
||||
@VisibleForTesting static LockMetrics lockMetrics = new LockMetrics();
|
||||
@@ -79,17 +76,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
/** The name of the locked resource. */
|
||||
@Transient @Id String lockId;
|
||||
|
||||
/**
|
||||
* Unique log ID of the request that owns this lock.
|
||||
*
|
||||
* <p>When that request is no longer running (is finished), the lock can be considered implicitly
|
||||
* released.
|
||||
*
|
||||
* <p>See {@link RequestStatusCheckerImpl#getLogId} for details about how it's created in
|
||||
* practice.
|
||||
*/
|
||||
@Column String requestLogId;
|
||||
|
||||
/** When the lock can be considered implicitly released. */
|
||||
@Column(nullable = false)
|
||||
DateTime expirationTime;
|
||||
@@ -124,7 +110,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
private static Lock create(
|
||||
String resourceName,
|
||||
String scope,
|
||||
String requestLogId,
|
||||
DateTime acquiredTime,
|
||||
Duration leaseLength) {
|
||||
checkArgument(!Strings.isNullOrEmpty(resourceName), "resourceName cannot be null or empty");
|
||||
@@ -132,7 +117,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
// Add the scope to the Lock's id so that it is unique for locks acquiring the same resource
|
||||
// across different TLDs.
|
||||
instance.lockId = makeLockId(resourceName, scope);
|
||||
instance.requestLogId = requestLogId;
|
||||
instance.expirationTime = acquiredTime.plus(leaseLength);
|
||||
instance.acquiredTime = acquiredTime;
|
||||
instance.resourceName = resourceName;
|
||||
@@ -172,18 +156,13 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
switch (acquireResult.lockState()) {
|
||||
case IN_USE:
|
||||
logger.atInfo().log(
|
||||
"Existing lock by request %s is still valid now %s (until %s) lock: %s",
|
||||
lock.requestLogId, now, lock.expirationTime, lock.lockId);
|
||||
"Existing lock by request is still valid now %s (until %s) lock: %s",
|
||||
now, lock.expirationTime, lock.lockId);
|
||||
break;
|
||||
case TIMED_OUT:
|
||||
logger.atInfo().log(
|
||||
"Existing lock by request %s is timed out now %s (was valid until %s) lock: %s",
|
||||
lock.requestLogId, now, lock.expirationTime, lock.lockId);
|
||||
break;
|
||||
case OWNER_DIED:
|
||||
logger.atInfo().log(
|
||||
"Existing lock is valid now %s (until %s), but owner (%s) isn't running lock: %s",
|
||||
now, lock.expirationTime, lock.requestLogId, lock.lockId);
|
||||
"Existing lock by request is timed out now %s (was valid until %s) lock: %s",
|
||||
now, lock.expirationTime, lock.lockId);
|
||||
break;
|
||||
case FREE:
|
||||
// There was no existing lock
|
||||
@@ -203,11 +182,7 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
|
||||
/** Try to acquire a lock. Returns absent if it can't be acquired. */
|
||||
public static Optional<Lock> acquire(
|
||||
String resourceName,
|
||||
@Nullable String tld,
|
||||
Duration leaseLength,
|
||||
RequestStatusChecker requestStatusChecker,
|
||||
boolean checkThreadRunning) {
|
||||
String resourceName, @Nullable String tld, Duration leaseLength) {
|
||||
String scope = tld != null ? tld : GLOBAL;
|
||||
Supplier<AcquireResult> lockAcquirer =
|
||||
() -> {
|
||||
@@ -219,22 +194,19 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
.orElse(null);
|
||||
if (lock != null) {
|
||||
logger.atInfo().log(
|
||||
"Loaded existing lock: %s for request: %s", lock.lockId, lock.requestLogId);
|
||||
"Loaded existing lock: %s for resource: %s", lock.lockId, lock.resourceName);
|
||||
}
|
||||
LockState lockState;
|
||||
if (lock == null) {
|
||||
lockState = LockState.FREE;
|
||||
} else if (isAtOrAfter(now, lock.expirationTime)) {
|
||||
lockState = LockState.TIMED_OUT;
|
||||
} else if (checkThreadRunning && !requestStatusChecker.isRunning(lock.requestLogId)) {
|
||||
lockState = LockState.OWNER_DIED;
|
||||
} else {
|
||||
lockState = LockState.IN_USE;
|
||||
return AcquireResult.create(now, lock, null, lockState);
|
||||
}
|
||||
|
||||
Lock newLock =
|
||||
create(resourceName, scope, requestStatusChecker.getLogId(), now, leaseLength);
|
||||
Lock newLock = create(resourceName, scope, now, leaseLength);
|
||||
tm().put(newLock);
|
||||
|
||||
return AcquireResult.create(now, lock, newLock, lockState);
|
||||
|
||||
@@ -275,6 +275,26 @@ public class Registry extends ImmutableObject implements Buildable, UnsafeSerial
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The time to live for DNS A and AAAA records.
|
||||
*
|
||||
* <p>When this field is null, the "dnsDefaultATtl" value from the config file will be used.
|
||||
*/
|
||||
Duration dnsAPlusAaaaTtl;
|
||||
|
||||
/**
|
||||
* The time to live for DNS NS records.
|
||||
*
|
||||
* <p>When this field is null, the "dnsDefaultNsTtl" value from the config file will be used.
|
||||
*/
|
||||
Duration dnsNsTtl;
|
||||
|
||||
/**
|
||||
* The time to live for DNS DS records.
|
||||
*
|
||||
* <p>When this field is null, the "dnsDefaultDsTtl" value from the config file will be used.
|
||||
*/
|
||||
Duration dnsDsTtl;
|
||||
/**
|
||||
* The unicode-aware representation of the TLD associated with this {@link Registry}.
|
||||
*
|
||||
@@ -647,6 +667,21 @@ public class Registry extends ImmutableObject implements Buildable, UnsafeSerial
|
||||
return numDnsPublishLocks;
|
||||
}
|
||||
|
||||
/** Returns the time to live for A and AAAA records. */
|
||||
public Duration getDnsAPlusAaaaTtl() {
|
||||
return dnsAPlusAaaaTtl;
|
||||
}
|
||||
|
||||
/** Returns the time to live for NS records. */
|
||||
public Duration getDnsNsTtl() {
|
||||
return dnsNsTtl;
|
||||
}
|
||||
|
||||
/** Returns the time to live for DS records. */
|
||||
public Duration getDnsDsTtl() {
|
||||
return dnsDsTtl;
|
||||
}
|
||||
|
||||
public ImmutableSet<String> getAllowedRegistrantContactIds() {
|
||||
return nullToEmptyImmutableCopy(allowedRegistrantContactIds);
|
||||
}
|
||||
@@ -737,6 +772,21 @@ public class Registry extends ImmutableObject implements Buildable, UnsafeSerial
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDnsAPlusAaaaTtl(Duration dnsAPlusAaaaTtl) {
|
||||
getInstance().dnsAPlusAaaaTtl = dnsAPlusAaaaTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDnsNsAtl(Duration dnsNsAtl) {
|
||||
getInstance().dnsNsTtl = dnsNsAtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDnsDsAtl(Duration dnsDsAtl) {
|
||||
getInstance().dnsDsTtl = dnsDsAtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAddGracePeriodLength(Duration addGracePeriodLength) {
|
||||
checkArgument(
|
||||
addGracePeriodLength.isLongerThan(Duration.ZERO),
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2023 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.persistence.converter;
|
||||
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
@Converter(autoApply = true)
|
||||
public class CommandNameSetConverter
|
||||
extends StringSetConverterBase<FeeQueryCommandExtensionItem.CommandName> {
|
||||
|
||||
@Override
|
||||
String toString(CommandName element) {
|
||||
return element.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
CommandName fromString(String value) {
|
||||
return FeeQueryCommandExtensionItem.CommandName.valueOf(value);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.SftpProgressMonitor;
|
||||
import dagger.Lazy;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.keyring.api.KeyModule.Key;
|
||||
@@ -56,7 +57,6 @@ import google.registry.request.RequestParameters;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.TeeOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -131,8 +131,7 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
|
||||
prefix.ifPresent(s -> params.put(RdeModule.PARAM_PREFIX, s));
|
||||
cloudTasksUtils.enqueue(
|
||||
RDE_REPORT_QUEUE,
|
||||
cloudTasksUtils.createPostTask(
|
||||
RdeReportAction.PATH, Service.BACKEND.getServiceId(), params));
|
||||
cloudTasksUtils.createPostTask(RdeReportAction.PATH, Service.BACKEND, params));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
@@ -37,7 +38,6 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
@@ -140,7 +140,7 @@ public class GenerateInvoicesAction implements Runnable {
|
||||
ReportingModule.BEAM_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
PublishInvoicesAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
ReportingModule.PARAM_JOB_ID,
|
||||
jobId,
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.api.services.dataflow.model.Job;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.reporting.ReportingModule;
|
||||
import google.registry.request.Action;
|
||||
@@ -33,7 +34,6 @@ import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.YearMonth;
|
||||
@@ -127,7 +127,7 @@ public class PublishInvoicesAction implements Runnable {
|
||||
BillingModule.CRON_QUEUE,
|
||||
cloudTasksUtils.createPostTask(
|
||||
CopyDetailReportsAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(PARAM_YEAR_MONTH, yearMonth.toString())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.bigquery.BigqueryJobFailureException;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.reporting.icann.IcannReportingModule.ReportType;
|
||||
@@ -34,7 +35,6 @@ import google.registry.request.Action.Service;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.SendEmailService;
|
||||
@@ -123,7 +123,7 @@ public final class IcannReportingStagingAction implements Runnable {
|
||||
CRON_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
IcannReportingUploadAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
null,
|
||||
Duration.standardMinutes(2)));
|
||||
return null;
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.keyring.api.KeyModule.Key;
|
||||
@@ -37,7 +38,6 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
@@ -135,7 +135,7 @@ public class GenerateSpec11ReportAction implements Runnable {
|
||||
ReportingModule.BEAM_QUEUE,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
PublishSpec11ReportAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
ReportingModule.PARAM_JOB_ID,
|
||||
jobId,
|
||||
|
||||
@@ -39,8 +39,6 @@ import google.registry.request.HttpException.UnsupportedMediaTypeException;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.request.lock.LockHandlerImpl;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import google.registry.util.RequestStatusCheckerImpl;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -192,18 +190,6 @@ public final class RequestModule {
|
||||
return lockHandler;
|
||||
}
|
||||
|
||||
@Provides
|
||||
static RequestStatusChecker provideRequestStatusChecker(
|
||||
RequestStatusCheckerImpl requestStatusChecker) {
|
||||
return requestStatusChecker;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@RequestLogId
|
||||
static String provideRequestLogId(RequestStatusChecker requestStatusChecker) {
|
||||
return requestStatusChecker.getLogId();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JsonPayload
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -55,7 +55,7 @@ public abstract class IdTokenAuthenticationBase implements AuthenticationMechani
|
||||
JsonWebSignature token;
|
||||
try {
|
||||
token = tokenVerifier.verify(rawIdToken);
|
||||
} catch (TokenVerifier.VerificationException e) {
|
||||
} catch (Exception e) {
|
||||
logger.atInfo().withCause(e).log("Error when verifying access token");
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||
import static google.registry.request.auth.AuthLevel.APP;
|
||||
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.auth.AuthModule.ServiceAccount;
|
||||
import javax.inject.Inject;
|
||||
@@ -30,16 +31,16 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public class ServiceAccountAuthenticationMechanism extends IdTokenAuthenticationBase {
|
||||
|
||||
private final String cloudSchedulerEmailPrefix;
|
||||
private static final String BEARER_PREFIX = "Bearer ";
|
||||
|
||||
private final ImmutableList<String> serviceAccountEmails;
|
||||
|
||||
@Inject
|
||||
public ServiceAccountAuthenticationMechanism(
|
||||
@ServiceAccount TokenVerifier tokenVerifier,
|
||||
@Config("cloudSchedulerServiceAccountEmail") String cloudSchedulerEmailPrefix) {
|
||||
|
||||
@Config("serviceAccountEmails") ImmutableList<String> serviceAccountEmails) {
|
||||
super(tokenVerifier);
|
||||
this.cloudSchedulerEmailPrefix = cloudSchedulerEmailPrefix;
|
||||
this.serviceAccountEmails = serviceAccountEmails;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,7 +54,7 @@ public class ServiceAccountAuthenticationMechanism extends IdTokenAuthentication
|
||||
|
||||
@Override
|
||||
AuthResult authResultFromEmail(String emailAddress) {
|
||||
if (emailAddress.equals(cloudSchedulerEmailPrefix)) {
|
||||
if (serviceAccountEmails.stream().anyMatch(e -> e.equals(emailAddress))) {
|
||||
return AuthResult.create(APP);
|
||||
} else {
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import google.registry.model.server.Lock;
|
||||
import google.registry.util.AppEngineTimeLimiter;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -48,12 +47,10 @@ public class LockHandlerImpl implements LockHandler {
|
||||
/** Fudge factor to make sure we kill threads before a lock actually expires. */
|
||||
private static final Duration LOCK_TIMEOUT_FUDGE = Duration.standardSeconds(5);
|
||||
|
||||
private final RequestStatusChecker requestStatusChecker;
|
||||
private final Clock clock;
|
||||
|
||||
@Inject
|
||||
public LockHandlerImpl(RequestStatusChecker requestStatusChecker, Clock clock) {
|
||||
this.requestStatusChecker = requestStatusChecker;
|
||||
public LockHandlerImpl(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@@ -114,7 +111,7 @@ public class LockHandlerImpl implements LockHandler {
|
||||
/** Allows injection of mock Lock in tests. */
|
||||
@VisibleForTesting
|
||||
Optional<Lock> acquire(String lockName, @Nullable String tld, Duration leaseLength) {
|
||||
return Lock.acquire(lockName, tld, leaseLength, requestStatusChecker, true);
|
||||
return Lock.acquire(lockName, tld, leaseLength);
|
||||
}
|
||||
|
||||
private interface LockAcquirer {
|
||||
|
||||
@@ -14,21 +14,15 @@
|
||||
|
||||
package google.registry.tmch;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
||||
import com.google.common.base.Joiner;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Helper methods for creating tasks containing CSV line data in the lordn-sunrise and lordn-claims
|
||||
* queues based on {@link Domain} changes.
|
||||
* Helper methods for creating tasks containing CSV line data based on {@link Domain#getLordnPhase}.
|
||||
*
|
||||
* <p>Note that, per the <a href="https://tools.ietf.org/html/draft-ietf-regext-tmch-func-spec-04">
|
||||
* TMCH RFC</a>, while the application-datetime data is optional (which we never send because there
|
||||
@@ -36,65 +30,32 @@ import org.joda.time.DateTime;
|
||||
*/
|
||||
public final class LordnTaskUtils {
|
||||
|
||||
public static final String QUEUE_SUNRISE = "lordn-sunrise";
|
||||
public static final String QUEUE_CLAIMS = "lordn-claims";
|
||||
public static final String COLUMNS_CLAIMS =
|
||||
"roid,domain-name,notice-id,registrar-id,"
|
||||
+ "registration-datetime,ack-datetime,application-datetime";
|
||||
public static final String COLUMNS_SUNRISE =
|
||||
"roid,domain-name,SMD-id,registrar-id," + "registration-datetime,application-datetime";
|
||||
|
||||
/** Enqueues a task in the LORDN queue representing a line of CSV for LORDN export. */
|
||||
public static void enqueueDomainTask(Domain domain) {
|
||||
tm().assertInTransaction();
|
||||
// This method needs to use transactionTime as the Domain's creationTime because CreationTime
|
||||
// isn't yet populated when this method is called during the resource flow.
|
||||
String tld = domain.getTld();
|
||||
if (domain.getLaunchNotice() == null) {
|
||||
getQueue(QUEUE_SUNRISE)
|
||||
.add(
|
||||
TaskOptions.Builder.withTag(tld)
|
||||
.method(Method.PULL)
|
||||
.payload(getCsvLineForSunriseDomain(domain, tm().getTransactionTime())));
|
||||
} else {
|
||||
getQueue(QUEUE_CLAIMS)
|
||||
.add(
|
||||
TaskOptions.Builder.withTag(tld)
|
||||
.method(Method.PULL)
|
||||
.payload(getCsvLineForClaimsDomain(domain, tm().getTransactionTime())));
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the corresponding CSV LORDN line for a sunrise domain. */
|
||||
public static String getCsvLineForSunriseDomain(Domain domain) {
|
||||
return getCsvLineForSunriseDomain(domain, domain.getCreationTime());
|
||||
}
|
||||
|
||||
// TODO: Merge into the function above after pull queue migration.
|
||||
private static String getCsvLineForSunriseDomain(Domain domain, DateTime transactionTime) {
|
||||
return Joiner.on(',')
|
||||
.join(
|
||||
domain.getRepoId(),
|
||||
domain.getDomainName(),
|
||||
domain.getSmdId(),
|
||||
getIanaIdentifier(domain.getCreationRegistrarId()),
|
||||
transactionTime); // Used as creation time.
|
||||
domain.getCreationTime()); // Used as creation time.
|
||||
}
|
||||
|
||||
/** Returns the corresponding CSV LORDN line for a claims domain. */
|
||||
public static String getCsvLineForClaimsDomain(Domain domain) {
|
||||
return getCsvLineForClaimsDomain(domain, domain.getCreationTime());
|
||||
}
|
||||
|
||||
// TODO: Merge into the function above after pull queue migration.
|
||||
private static String getCsvLineForClaimsDomain(Domain domain, DateTime transactionTime) {
|
||||
return Joiner.on(',')
|
||||
.join(
|
||||
domain.getRepoId(),
|
||||
domain.getDomainName(),
|
||||
domain.getLaunchNotice().getNoticeId().getTcnId(),
|
||||
getIanaIdentifier(domain.getCreationRegistrarId()),
|
||||
transactionTime, // Used as creation time.
|
||||
domain.getCreationTime(), // Used as creation time.
|
||||
domain.getLaunchNotice().getAcceptedTime());
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package google.registry.tmch;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.net.HttpHeaders.LOCATION;
|
||||
@@ -43,9 +42,9 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.request.Action;
|
||||
@@ -57,7 +56,6 @@ import google.registry.request.UrlConnectionUtils;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.UrlConnectionException;
|
||||
import java.io.IOException;
|
||||
@@ -66,7 +64,6 @@ import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
@@ -90,8 +87,6 @@ public final class NordnUploadAction implements Runnable {
|
||||
|
||||
static final String PATH = "/_dr/task/nordnUpload";
|
||||
static final String LORDN_PHASE_PARAM = "lordnPhase";
|
||||
// TODO: Delete after migrating off of pull queue.
|
||||
static final String PULL_QUEUE_PARAM = "pullQueue";
|
||||
|
||||
private static final int BATCH_SIZE = 1000;
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
@@ -122,10 +117,6 @@ public final class NordnUploadAction implements Runnable {
|
||||
@Parameter(RequestParameters.PARAM_TLD)
|
||||
String tld;
|
||||
|
||||
@Inject
|
||||
@Parameter(PULL_QUEUE_PARAM)
|
||||
Optional<Boolean> usePullQueue;
|
||||
|
||||
@Inject CloudTasksUtils cloudTasksUtils;
|
||||
|
||||
@Inject
|
||||
@@ -146,67 +137,59 @@ public final class NordnUploadAction implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (usePullQueue.orElse(false)) {
|
||||
try {
|
||||
processLordnTasks();
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
checkArgument(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
|
||||
"Invalid phase specified to NordnUploadAction: %s.",
|
||||
phase);
|
||||
tm().transact(
|
||||
() -> {
|
||||
// Note here that we load all domains pending Nordn in one batch, which should not
|
||||
// be a problem for the rate of domain registration that we see. If we anticipate
|
||||
// a peak in claims during TLD launch (sunrise is NOT first-come-first-serve, so
|
||||
// there should be no expectation of a peak during it), we can consider temporarily
|
||||
// increasing the frequency of Nordn upload to reduce the size of each batch.
|
||||
//
|
||||
// We did not further divide the domains into smaller batches because the
|
||||
// read-upload-write operation per small batch needs to be inside a single
|
||||
// transaction to prevent race conditions, and running several uploads in rapid
|
||||
// sucession will likely overwhelm the MarksDB upload server, which recommands a
|
||||
// maximum upload frequency of every 3 hours.
|
||||
//
|
||||
// See:
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-regext-tmch-func-spec-01#section-5.2.3.3
|
||||
List<Domain> domains =
|
||||
tm().createQueryComposer(Domain.class)
|
||||
.where("lordnPhase", EQ, LordnPhase.valueOf(Ascii.toUpperCase(phase)))
|
||||
.where("tld", EQ, tld)
|
||||
.orderBy("creationTime")
|
||||
.list();
|
||||
if (domains.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
StringBuilder csv = new StringBuilder();
|
||||
ImmutableList.Builder<Domain> newDomains = new ImmutableList.Builder<>();
|
||||
checkArgument(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
|
||||
"Invalid phase specified to NordnUploadAction: %s.",
|
||||
phase);
|
||||
tm().transact(
|
||||
() -> {
|
||||
// Note here that we load all domains pending Nordn in one batch, which should not
|
||||
// be a problem for the rate of domain registration that we see. If we anticipate
|
||||
// a peak in claims during TLD launch (sunrise is NOT first-come-first-serve, so
|
||||
// there should be no expectation of a peak during it), we can consider temporarily
|
||||
// increasing the frequency of Nordn upload to reduce the size of each batch.
|
||||
//
|
||||
// We did not further divide the domains into smaller batches because the
|
||||
// read-upload-write operation per small batch needs to be inside a single
|
||||
// transaction to prevent race conditions, and running several uploads in rapid
|
||||
// sucession will likely overwhelm the MarksDB upload server, which recommands a
|
||||
// maximum upload frequency of every 3 hours.
|
||||
//
|
||||
// See:
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-regext-tmch-func-spec-01#section-5.2.3.3
|
||||
List<Domain> domains =
|
||||
tm().createQueryComposer(Domain.class)
|
||||
.where("lordnPhase", EQ, LordnPhase.valueOf(Ascii.toUpperCase(phase)))
|
||||
.where("tld", EQ, tld)
|
||||
.orderBy("creationTime")
|
||||
.list();
|
||||
if (domains.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
StringBuilder csv = new StringBuilder();
|
||||
ImmutableList.Builder<Domain> newDomains = new ImmutableList.Builder<>();
|
||||
|
||||
domains.forEach(
|
||||
domain -> {
|
||||
if (phase.equals(PARAM_LORDN_PHASE_SUNRISE)) {
|
||||
csv.append(getCsvLineForSunriseDomain(domain)).append('\n');
|
||||
} else {
|
||||
csv.append(getCsvLineForClaimsDomain(domain)).append('\n');
|
||||
}
|
||||
Domain newDomain = domain.asBuilder().setLordnPhase(LordnPhase.NONE).build();
|
||||
newDomains.add(newDomain);
|
||||
});
|
||||
String columns =
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) ? COLUMNS_SUNRISE : COLUMNS_CLAIMS;
|
||||
String header =
|
||||
String.format("1,%s,%d\n%s\n", clock.nowUtc(), domains.size(), columns);
|
||||
try {
|
||||
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), header + csv);
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
tm().updateAll(newDomains.build());
|
||||
});
|
||||
}
|
||||
domains.forEach(
|
||||
domain -> {
|
||||
if (phase.equals(PARAM_LORDN_PHASE_SUNRISE)) {
|
||||
csv.append(getCsvLineForSunriseDomain(domain)).append('\n');
|
||||
} else {
|
||||
csv.append(getCsvLineForClaimsDomain(domain)).append('\n');
|
||||
}
|
||||
Domain newDomain = domain.asBuilder().setLordnPhase(LordnPhase.NONE).build();
|
||||
newDomains.add(newDomain);
|
||||
});
|
||||
String columns =
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) ? COLUMNS_SUNRISE : COLUMNS_CLAIMS;
|
||||
String header =
|
||||
String.format("1,%s,%d\n%s\n", clock.nowUtc(), domains.size(), columns);
|
||||
try {
|
||||
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), header + csv);
|
||||
} catch (IOException | GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
tm().updateAll(newDomains.build());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,35 +232,6 @@ public final class NordnUploadAction implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void processLordnTasks() throws IOException, GeneralSecurityException {
|
||||
checkArgument(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
|
||||
"Invalid phase specified to NordnUploadAction: %s.",
|
||||
phase);
|
||||
DateTime now = clock.nowUtc();
|
||||
Queue queue =
|
||||
getQueue(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE)
|
||||
? LordnTaskUtils.QUEUE_SUNRISE
|
||||
: LordnTaskUtils.QUEUE_CLAIMS);
|
||||
String columns = phase.equals(PARAM_LORDN_PHASE_SUNRISE) ? COLUMNS_SUNRISE : COLUMNS_CLAIMS;
|
||||
List<TaskHandle> tasks = loadAllTasks(queue, tld);
|
||||
// Note: This upload/task deletion isn't done atomically (it's not clear how one would do so
|
||||
// anyway). As a result, it is possible that the upload might succeed yet the deletion of
|
||||
// enqueued tasks might fail. If so, this would result in the same lines being uploaded to NORDN
|
||||
// across multiple uploads. This is probably OK; all that we really cannot have is a missing
|
||||
// line.
|
||||
if (!tasks.isEmpty()) {
|
||||
String csvData = convertTasksToCsv(tasks, now, columns);
|
||||
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), csvData);
|
||||
Lists.partition(tasks, BATCH_SIZE)
|
||||
.forEach(
|
||||
batch ->
|
||||
retrier.callWithRetry(
|
||||
() -> queue.deleteTask(batch), TransientFailureException.class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload LORDN file to MarksDB.
|
||||
*
|
||||
@@ -333,7 +287,7 @@ public final class NordnUploadAction implements Runnable {
|
||||
// The actionLogId is used to uniquely associate the verify task back to the upload task.
|
||||
return cloudTasksUtils.createPostTaskWithDelay(
|
||||
NordnVerifyAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.<String, String>builder()
|
||||
.put(NordnVerifyAction.NORDN_URL_PARAM, url.toString())
|
||||
.put(NordnVerifyAction.NORDN_LOG_ID_PARAM, actionLogId)
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.tmch;
|
||||
|
||||
import static com.google.common.io.Resources.asByteSource;
|
||||
import static com.google.common.io.Resources.getResource;
|
||||
import static google.registry.request.RequestParameters.extractOptionalBooleanParameter;
|
||||
import static google.registry.request.RequestParameters.extractRequiredParameter;
|
||||
|
||||
import dagger.Module;
|
||||
@@ -26,7 +25,6 @@ import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.Parameter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
|
||||
@@ -66,10 +64,4 @@ public final class TmchModule {
|
||||
static String provideNordnLogId(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, NordnVerifyAction.NORDN_LOG_ID_PARAM);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter(NordnUploadAction.PULL_QUEUE_PARAM)
|
||||
static Optional<Boolean> provideUsePullQueue(HttpServletRequest req) {
|
||||
return extractOptionalBooleanParameter(req, NordnUploadAction.PULL_QUEUE_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2023 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 google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.tools.params.KeyValueMapParameter.StringToRegistrarRoleMap;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Shared base class for commands that create or modify a {@link User}. */
|
||||
public abstract class CreateOrUpdateUserCommand extends ConfirmingCommand {
|
||||
|
||||
@Nullable
|
||||
@Parameter(names = "--email", description = "Email address of the user", required = true)
|
||||
String email;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--admin",
|
||||
description = "Whether or not the user in question is an admin",
|
||||
arity = 1)
|
||||
private Boolean isAdmin;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--global_role",
|
||||
description = "Global role, e.g. SUPPORT_LEAD, to apply to the user")
|
||||
private GlobalRole globalRole;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--registrar_roles",
|
||||
converter = StringToRegistrarRoleMap.class,
|
||||
validateWith = StringToRegistrarRoleMap.class,
|
||||
description =
|
||||
"Comma-delimited mapping of registrar name to role that the user has on that registrar")
|
||||
private ImmutableMap<String, RegistrarRole> registrarRolesMap;
|
||||
|
||||
@Nullable
|
||||
abstract User getExistingUser(String email);
|
||||
|
||||
@Override
|
||||
protected final String execute() throws Exception {
|
||||
checkArgumentNotNull(email, "Email must be provided");
|
||||
tm().transact(this::executeInTransaction);
|
||||
return String.format("Saved user with email %s", email);
|
||||
}
|
||||
|
||||
private void executeInTransaction() {
|
||||
User user = getExistingUser(email);
|
||||
UserRoles.Builder userRolesBuilder =
|
||||
(user == null) ? new UserRoles.Builder() : user.getUserRoles().asBuilder();
|
||||
|
||||
Optional.ofNullable(globalRole).ifPresent(userRolesBuilder::setGlobalRole);
|
||||
Optional.ofNullable(registrarRolesMap).ifPresent(userRolesBuilder::setRegistrarRoles);
|
||||
Optional.ofNullable(isAdmin).ifPresent(userRolesBuilder::setIsAdmin);
|
||||
|
||||
User.Builder builder =
|
||||
(user == null) ? new User.Builder().setEmailAddress(email) : user.asBuilder();
|
||||
builder.setUserRoles(userRolesBuilder.build());
|
||||
User newUser = builder.build();
|
||||
UserDao.saveUser(newUser);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2023 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 com.beust.jcommander.Parameters;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Command to create a new User. */
|
||||
@Parameters(separators = " =", commandDescription = "Update a user account")
|
||||
public class CreateUserCommand extends CreateOrUpdateUserCommand {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
User getExistingUser(String email) {
|
||||
checkArgument(
|
||||
!UserDao.loadUser(email).isPresent(), "A user with email %s already exists", email);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2023 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 google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Deletes a {@link User}. */
|
||||
@Parameters(separators = " =", commandDescription = "Delete a user account")
|
||||
public class DeleteUserCommand extends ConfirmingCommand {
|
||||
|
||||
@Nullable
|
||||
@Parameter(names = "--email", description = "Email address of the user", required = true)
|
||||
String email;
|
||||
|
||||
@Override
|
||||
protected String prompt() {
|
||||
checkArgumentNotNull(email, "Email must be provided");
|
||||
checkArgumentPresent(UserDao.loadUser(email), "Email does not correspond to a valid user");
|
||||
return String.format("Delete user with email %s?", email);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String execute() throws Exception {
|
||||
tm().transact(
|
||||
() -> {
|
||||
Optional<User> optionalUser = UserDao.loadUser(email);
|
||||
checkArgumentPresent(optionalUser, "Email no longer corresponds to a valid user");
|
||||
tm().delete(optionalUser.get());
|
||||
});
|
||||
return String.format("Deleted user with email %s", email);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STAT
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.batch.RelockDomainAction;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
@@ -34,7 +35,6 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.RegistryLockDao;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.StringGenerator;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -223,7 +223,7 @@ public final class DomainLockUtils {
|
||||
QUEUE_ASYNC_ACTIONS,
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
RelockDomainAction.PATH,
|
||||
Service.BACKEND.toString(),
|
||||
Service.BACKEND,
|
||||
ImmutableMultimap.of(
|
||||
RelockDomainAction.OLD_UNLOCK_REVISION_ID_PARAM,
|
||||
String.valueOf(lockRevisionId),
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.io.Files;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
@@ -114,6 +115,11 @@ class GenerateAllocationTokensCommand implements Command {
|
||||
description = "Comma-separated list of allowed TLDs, or null if all are allowed")
|
||||
private List<String> allowedTlds;
|
||||
|
||||
@Parameter(
|
||||
names = {"--allowed_epp_actions"},
|
||||
description = "Comma-separated list of allowed EPP actions, or null if all are allowed")
|
||||
private List<String> allowedEppActions;
|
||||
|
||||
@Parameter(
|
||||
names = {"--discount_fraction"},
|
||||
description =
|
||||
@@ -207,7 +213,13 @@ class GenerateAllocationTokensCommand implements Command {
|
||||
.setTokenType(tokenType == null ? SINGLE_USE : tokenType)
|
||||
.setAllowedRegistrarIds(
|
||||
ImmutableSet.copyOf(nullToEmpty(allowedClientIds)))
|
||||
.setAllowedTlds(ImmutableSet.copyOf(nullToEmpty(allowedTlds)));
|
||||
.setAllowedTlds(ImmutableSet.copyOf(nullToEmpty(allowedTlds)))
|
||||
.setAllowedEppActions(
|
||||
isNullOrEmpty(allowedEppActions)
|
||||
? ImmutableSet.of()
|
||||
: allowedEppActions.stream()
|
||||
.map(CommandName::parseKnownCommand)
|
||||
.collect(toImmutableSet()));
|
||||
Optional.ofNullable(discountFraction).ifPresent(token::setDiscountFraction);
|
||||
Optional.ofNullable(discountPremiums).ifPresent(token::setDiscountPremiums);
|
||||
Optional.ofNullable(discountYears).ifPresent(token::setDiscountYears);
|
||||
@@ -255,6 +267,10 @@ class GenerateAllocationTokensCommand implements Command {
|
||||
!ImmutableList.of("").equals(allowedTlds),
|
||||
"Either omit --allowed_tlds if all TLDs are allowed, or include a comma-separated list");
|
||||
|
||||
if (ImmutableList.of("").equals(allowedEppActions)) {
|
||||
allowedEppActions = ImmutableList.of();
|
||||
}
|
||||
|
||||
if (!isNullOrEmpty(tokenStatusTransitions)) {
|
||||
// Don't allow package tokens to be created with a scheduled end time since this could allow
|
||||
// future domains to be attributed to the package and never be billed. Package promotion
|
||||
|
||||
@@ -28,11 +28,11 @@ import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.model.rde.RdeMode;
|
||||
import google.registry.rde.RdeStagingAction;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.tools.params.DateTimeParameter;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
@@ -122,7 +122,7 @@ final class GenerateEscrowDepositCommand implements Command {
|
||||
cloudTasksUtils.enqueue(
|
||||
RDE_REPORT_QUEUE,
|
||||
cloudTasksUtils.createPostTask(
|
||||
RdeStagingAction.PATH, Service.BACKEND.toString(), paramsBuilder.build()));
|
||||
RdeStagingAction.PATH, Service.BACKEND, paramsBuilder.build()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public final class RegistryTool {
|
||||
.put("create_registrar_groups", CreateRegistrarGroupsCommand.class)
|
||||
.put("create_reserved_list", CreateReservedListCommand.class)
|
||||
.put("create_tld", CreateTldCommand.class)
|
||||
.put("create_user", CreateUserCommand.class)
|
||||
.put("curl", CurlCommand.class)
|
||||
.put("delete_allocation_tokens", DeleteAllocationTokensCommand.class)
|
||||
.put("delete_domain", DeleteDomainCommand.class)
|
||||
@@ -53,6 +54,7 @@ public final class RegistryTool {
|
||||
.put("delete_premium_list", DeletePremiumListCommand.class)
|
||||
.put("delete_reserved_list", DeleteReservedListCommand.class)
|
||||
.put("delete_tld", DeleteTldCommand.class)
|
||||
.put("delete_user", DeleteUserCommand.class)
|
||||
.put("encrypt_escrow_deposit", EncryptEscrowDepositCommand.class)
|
||||
.put("enqueue_poll_message", EnqueuePollMessageCommand.class)
|
||||
.put("execute_epp", ExecuteEppCommand.class)
|
||||
@@ -110,6 +112,7 @@ public final class RegistryTool {
|
||||
.put("update_reserved_list", UpdateReservedListCommand.class)
|
||||
.put("update_server_locks", UpdateServerLocksCommand.class)
|
||||
.put("update_tld", UpdateTldCommand.class)
|
||||
.put("update_user", UpdateUserCommand.class)
|
||||
.put("upload_claims_list", UploadClaimsListCommand.class)
|
||||
.put("validate_escrow_deposit", ValidateEscrowDepositCommand.class)
|
||||
.put("validate_login_credentials", ValidateLoginCredentialsCommand.class)
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
@@ -63,6 +64,13 @@ final class UpdateAllocationTokensCommand extends UpdateOrDeleteAllocationTokens
|
||||
+ "existing list.")
|
||||
private List<String> allowedTlds;
|
||||
|
||||
@Parameter(
|
||||
names = {"--allowed_epp_actions"},
|
||||
description =
|
||||
"Comma-separated list of allowed EPP actions. Use an empty string to clear the existing"
|
||||
+ " list.")
|
||||
private List<String> allowedEppActions;
|
||||
|
||||
@Parameter(
|
||||
names = {"--discount_fraction"},
|
||||
description =
|
||||
@@ -128,6 +136,9 @@ final class UpdateAllocationTokensCommand extends UpdateOrDeleteAllocationTokens
|
||||
if (ImmutableList.of("").equals(allowedTlds)) {
|
||||
allowedTlds = ImmutableList.of();
|
||||
}
|
||||
if (ImmutableList.of("").equals(allowedEppActions)) {
|
||||
allowedEppActions = ImmutableList.of();
|
||||
}
|
||||
|
||||
if (tokenStatusTransitions != null
|
||||
&& (tokenStatusTransitions.containsValue(TokenStatus.ENDED)
|
||||
@@ -184,6 +195,14 @@ final class UpdateAllocationTokensCommand extends UpdateOrDeleteAllocationTokens
|
||||
.ifPresent(clientIds -> builder.setAllowedRegistrarIds(ImmutableSet.copyOf(clientIds)));
|
||||
Optional.ofNullable(allowedTlds)
|
||||
.ifPresent(tlds -> builder.setAllowedTlds(ImmutableSet.copyOf(tlds)));
|
||||
Optional.ofNullable(allowedEppActions)
|
||||
.ifPresent(
|
||||
eppActions -> {
|
||||
builder.setAllowedEppActions(
|
||||
eppActions.stream()
|
||||
.map(CommandName::parseKnownCommand)
|
||||
.collect(toImmutableSet()));
|
||||
});
|
||||
Optional.ofNullable(discountFraction).ifPresent(builder::setDiscountFraction);
|
||||
Optional.ofNullable(discountPremiums).ifPresent(builder::setDiscountPremiums);
|
||||
Optional.ofNullable(discountYears).ifPresent(builder::setDiscountYears);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 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 google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Updates a user, assuming that the user in question already exists. */
|
||||
@Parameters(separators = " =", commandDescription = "Update a user account")
|
||||
public class UpdateUserCommand extends CreateOrUpdateUserCommand {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
User getExistingUser(String email) {
|
||||
return checkArgumentPresent(UserDao.loadUser(email), "User %s not found", email);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package google.registry.tools.params;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import java.util.Map;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
@@ -107,4 +108,18 @@ public abstract class KeyValueMapParameter<K, V>
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Combined converter/validator class for maps of registrar names to registrar roles. */
|
||||
public static class StringToRegistrarRoleMap extends KeyValueMapParameter<String, RegistrarRole> {
|
||||
|
||||
@Override
|
||||
protected String parseKey(String rawKey) {
|
||||
return rawKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegistrarRole parseValue(String rawValue) {
|
||||
return RegistrarRole.valueOf(rawValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import static google.registry.request.RequestParameters.PARAM_TLDS;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
@@ -66,7 +66,7 @@ public class RefreshDnsForAllDomainsAction implements Runnable {
|
||||
@Parameter("smearMinutes")
|
||||
int smearMinutes;
|
||||
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject DnsUtils dnsUtils;
|
||||
@Inject Clock clock;
|
||||
@Inject Random random;
|
||||
|
||||
@@ -91,7 +91,7 @@ public class RefreshDnsForAllDomainsAction implements Runnable {
|
||||
domainName -> {
|
||||
try {
|
||||
// Smear the task execution time over the next N minutes.
|
||||
dnsQueue.addDomainRefreshTask(
|
||||
dnsUtils.requestDomainDnsRefresh(
|
||||
domainName, Duration.standardMinutes(random.nextInt(smearMinutes)));
|
||||
} catch (Throwable t) {
|
||||
logger.atSevere().withCause(t).log(
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.export.sheet.SyncRegistrarsSheetAction;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
@@ -58,7 +59,6 @@ import google.registry.ui.forms.FormException;
|
||||
import google.registry.ui.forms.FormFieldException;
|
||||
import google.registry.ui.server.RegistrarFormFields;
|
||||
import google.registry.ui.server.SendEmailUtils;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.CollectionUtils;
|
||||
import google.registry.util.DiffUtils;
|
||||
import java.util.HashSet;
|
||||
@@ -643,7 +643,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
cloudTasksUtils.enqueue(
|
||||
SyncRegistrarsSheetAction.QUEUE,
|
||||
cloudTasksUtils.createGetTask(
|
||||
SyncRegistrarsSheetAction.PATH, Service.BACKEND.toString(), ImmutableMultimap.of()));
|
||||
SyncRegistrarsSheetAction.PATH, Service.BACKEND, ImmutableMultimap.of()));
|
||||
}
|
||||
String environment = Ascii.toLowerCase(String.valueOf(RegistryEnvironment.get()));
|
||||
sendEmailUtils.sendEmail(
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<class>google.registry.model.billing.BillingEvent$Recurring</class>
|
||||
<class>google.registry.model.common.Cursor</class>
|
||||
<class>google.registry.model.common.DatabaseMigrationStateSchedule</class>
|
||||
<class>google.registry.model.common.DnsRefreshRequest</class>
|
||||
<class>google.registry.model.console.User</class>
|
||||
<class>google.registry.model.contact.ContactHistory</class>
|
||||
<class>google.registry.model.contact.Contact</class>
|
||||
@@ -84,6 +85,7 @@
|
||||
<class>google.registry.persistence.converter.BillingEventFlagSetConverter</class>
|
||||
<class>google.registry.persistence.converter.BloomFilterConverter</class>
|
||||
<class>google.registry.persistence.converter.CidrAddressBlockListConverter</class>
|
||||
<class>google.registry.persistence.converter.CommandNameSetConverter</class>
|
||||
<class>google.registry.persistence.converter.CurrencyToBillingConverter</class>
|
||||
<class>google.registry.persistence.converter.CurrencyUnitConverter</class>
|
||||
<class>google.registry.persistence.converter.DatabaseMigrationScheduleTransitionConverter</class>
|
||||
|
||||
@@ -30,7 +30,6 @@ import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.CapturingLogHandler;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
import java.util.logging.Level;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.util;
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -27,9 +27,11 @@ import com.google.cloud.tasks.v2.Task;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import google.registry.batch.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.util.CloudTasksUtils.SerializableCloudTasksClient;
|
||||
import google.registry.util.Retrier;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
@@ -59,22 +61,22 @@ public class CloudTasksUtilsTest {
|
||||
|
||||
@Test
|
||||
void testSuccess_createGetTasks() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks() {
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", "myservice", params);
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", Service.BACKEND, params);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -84,42 +86,43 @@ public class CloudTasksUtilsTest {
|
||||
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withNullParams() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", null);
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, null);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withNullParams() {
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", "myservice", null);
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", Service.BACKEND, null);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8)).isEmpty();
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withEmptyParams() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", ImmutableMultimap.of());
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, ImmutableMultimap.of());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withEmptyParams() {
|
||||
Task task = cloudTasksUtils.createPostTask("/the/path", "myservice", ImmutableMultimap.of());
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTask("/the/path", Service.BACKEND, ImmutableMultimap.of());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8)).isEmpty();
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
@@ -128,12 +131,13 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithJitter("/the/path", "myservice", params, Optional.of(100));
|
||||
cloudTasksUtils.createGetTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(100));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
|
||||
Instant scheduleTime = Instant.ofEpochSecond(task.getScheduleTime().getSeconds());
|
||||
Instant lowerBoundTime = Instant.ofEpochMilli(clock.nowUtc().getMillis());
|
||||
@@ -147,11 +151,12 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter("/the/path", "myservice", params, Optional.of(1));
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(1));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -170,11 +175,11 @@ public class CloudTasksUtilsTest {
|
||||
void testSuccess_createPostTasks_withEmptyJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
"/the/path", "myservice", params, Optional.empty());
|
||||
"/the/path", Service.BACKEND, params, Optional.empty());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -185,23 +190,25 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withEmptyJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithJitter("/the/path", "myservice", params, Optional.empty());
|
||||
cloudTasksUtils.createGetTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.empty());
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withZeroJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithJitter("/the/path", "myservice", params, Optional.of(0));
|
||||
cloudTasksUtils.createPostTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(0));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -212,12 +219,13 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withZeroJitterSeconds() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithJitter("/the/path", "myservice", params, Optional.of(0));
|
||||
cloudTasksUtils.createGetTaskWithJitter(
|
||||
"/the/path", Service.BACKEND, params, Optional.of(0));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@@ -225,12 +233,12 @@ public class CloudTasksUtilsTest {
|
||||
void testSuccess_createGetTasks_withDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(10));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(10));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(Instant.ofEpochSecond(task.getScheduleTime().getSeconds()))
|
||||
.isEqualTo(Instant.ofEpochMilli(clock.nowUtc().plusMinutes(10).getMillis()));
|
||||
}
|
||||
@@ -239,11 +247,11 @@ public class CloudTasksUtilsTest {
|
||||
void testSuccess_createPostTasks_withDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(10));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(10));
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -260,7 +268,7 @@ public class CloudTasksUtilsTest {
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
cloudTasksUtils.createGetTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(-10)));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(-10)));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Negative duration is not supported.");
|
||||
}
|
||||
|
||||
@@ -271,18 +279,19 @@ public class CloudTasksUtilsTest {
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
cloudTasksUtils.createGetTaskWithDelay(
|
||||
"/the/path", "myservice", params, Duration.standardMinutes(-10)));
|
||||
"/the/path", Service.BACKEND, params, Duration.standardMinutes(-10)));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Negative duration is not supported.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_createPostTasks_withZeroDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createPostTaskWithDelay("/the/path", "myservice", params, Duration.ZERO);
|
||||
cloudTasksUtils.createPostTaskWithDelay(
|
||||
"/the/path", Service.BACKEND, params, Duration.ZERO);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri()).isEqualTo("/the/path");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getAppEngineHttpRequest().getHeadersMap().get("Content-Type"))
|
||||
.isEqualTo("application/x-www-form-urlencoded");
|
||||
assertThat(task.getAppEngineHttpRequest().getBody().toString(StandardCharsets.UTF_8))
|
||||
@@ -293,12 +302,12 @@ public class CloudTasksUtilsTest {
|
||||
@Test
|
||||
void testSuccess_createGetTasks_withZeroDelay() {
|
||||
Task task =
|
||||
cloudTasksUtils.createGetTaskWithDelay("/the/path", "myservice", params, Duration.ZERO);
|
||||
cloudTasksUtils.createGetTaskWithDelay("/the/path", Service.BACKEND, params, Duration.ZERO);
|
||||
assertThat(task.getAppEngineHttpRequest().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(task.getAppEngineHttpRequest().getRelativeUri())
|
||||
.isEqualTo("/the/path?key1=val1&key2=val2&key1=val3");
|
||||
assertThat(task.getAppEngineHttpRequest().getAppEngineRouting().getService())
|
||||
.isEqualTo("myservice");
|
||||
.isEqualTo(Service.BACKEND.toString());
|
||||
assertThat(task.getScheduleTime().getSeconds()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@@ -306,26 +315,26 @@ public class CloudTasksUtilsTest {
|
||||
void testFailure_illegalPath() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> cloudTasksUtils.createPostTask("the/path", "myservice", params));
|
||||
() -> cloudTasksUtils.createPostTask("the/path", Service.BACKEND, params));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> cloudTasksUtils.createPostTask(null, "myservice", params));
|
||||
() -> cloudTasksUtils.createPostTask(null, Service.BACKEND, params));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> cloudTasksUtils.createPostTask("", "myservice", params));
|
||||
() -> cloudTasksUtils.createPostTask("", Service.BACKEND, params));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_enqueueTask() {
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
cloudTasksUtils.enqueue("test-queue", task);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_enqueueTasks_varargs() {
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", "yourservice", params);
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", Service.TOOLS, params);
|
||||
cloudTasksUtils.enqueue("test-queue", task1, task2);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task1);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task2);
|
||||
@@ -333,8 +342,8 @@ public class CloudTasksUtilsTest {
|
||||
|
||||
@Test
|
||||
void testSuccess_enqueueTasks_iterable() {
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", "myservice", params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", "yourservice", params);
|
||||
Task task1 = cloudTasksUtils.createGetTask("/the/path", Service.BACKEND, params);
|
||||
Task task2 = cloudTasksUtils.createGetTask("/other/path", Service.TOOLS, params);
|
||||
cloudTasksUtils.enqueue("test-queue", ImmutableList.of(task1, task2));
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task1);
|
||||
verify(mockClient).enqueue("project", "location", "test-queue", task2);
|
||||
@@ -27,14 +27,14 @@ import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DatabaseHelper.persistSimpleResource;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
@@ -47,9 +47,8 @@ import google.registry.model.tld.Registry.TldType;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.DnsUtilsHelper;
|
||||
import google.registry.testing.SystemPropertyExtension;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.money.Money;
|
||||
@@ -68,13 +67,14 @@ class DeleteProberDataActionTest {
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
@RegisterExtension
|
||||
final SystemPropertyExtension systemPropertyExtension = new SystemPropertyExtension();
|
||||
|
||||
private DeleteProberDataAction action;
|
||||
|
||||
private final DnsUtils dnsUtils = mock(DnsUtils.class);
|
||||
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
// Entities in these two should not be touched.
|
||||
@@ -99,7 +99,7 @@ class DeleteProberDataActionTest {
|
||||
|
||||
private void resetAction() {
|
||||
action = new DeleteProberDataAction();
|
||||
action.dnsQueue = DnsQueue.createForTesting(new FakeClock());
|
||||
action.dnsUtils = dnsUtils;
|
||||
action.isDryRun = false;
|
||||
action.tlds = ImmutableSet.of();
|
||||
action.registryAdminRegistrarId = "TheRegistrar";
|
||||
@@ -201,7 +201,7 @@ class DeleteProberDataActionTest {
|
||||
DateTime timeAfterDeletion = DateTime.now(UTC);
|
||||
assertThat(loadByForeignKey(Domain.class, "blah.ib-any.test", timeAfterDeletion)).isEmpty();
|
||||
assertThat(loadByEntity(domain).getDeletionTime()).isLessThan(timeAfterDeletion);
|
||||
assertDnsTasksEnqueued("blah.ib-any.test");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("blah.ib-any.test");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -218,7 +218,7 @@ class DeleteProberDataActionTest {
|
||||
action.run();
|
||||
assertThat(loadByForeignKey(Domain.class, "blah.ib-any.test", timeAfterDeletion)).isEmpty();
|
||||
assertThat(loadByEntity(domain).getDeletionTime()).isLessThan(timeAfterDeletion);
|
||||
assertDnsTasksEnqueued("blah.ib-any.test");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("blah.ib-any.test");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
170
core/src/test/java/google/registry/dns/DnsUtilsTest.java
Normal file
170
core/src/test/java/google/registry/dns/DnsUtilsTest.java
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright 2023 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.dns;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.loadAllOf;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Ordering;
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import google.registry.model.common.DnsRefreshRequest;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link DnsUtils}. */
|
||||
public class DnsUtilsTest {
|
||||
|
||||
private static final String tld = "tld";
|
||||
private static final String domainName = "test.tld";
|
||||
private static final String hostName = "ns1.test.tld";
|
||||
|
||||
private final DnsQueue dnsQueue = mock(DnsQueue.class);
|
||||
private final DnsUtils dnsUtils = new DnsUtils(dnsQueue);
|
||||
|
||||
FakeClock clock = new FakeClock(DateTime.parse("2020-02-02T01:23:45Z"));
|
||||
|
||||
@RegisterExtension
|
||||
JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
DatabaseMigrationStateSchedule.useUncachedForTest();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
createTld(tld);
|
||||
when(dnsQueue.getClock()).thenReturn(clock);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_hostRefresh_pullQueue() {
|
||||
dnsUtils.requestHostDnsRefresh(hostName);
|
||||
verify(dnsQueue).addHostRefreshTask(hostName);
|
||||
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_domainRefresh_pullQueue() {
|
||||
dnsUtils.requestDomainDnsRefresh(domainName);
|
||||
verify(dnsQueue).addDomainRefreshTask(domainName, Duration.ZERO);
|
||||
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_domainRefreshWithDelay_pullQueue() {
|
||||
dnsUtils.requestDomainDnsRefresh(domainName, Duration.standardMinutes(3));
|
||||
verify(dnsQueue).addDomainRefreshTask(domainName, Duration.standardMinutes(3));
|
||||
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_hostRefresh_unmanagedHost() {
|
||||
String unmanagedHostName = "ns1.another.example";
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class, () -> dnsUtils.requestHostDnsRefresh(unmanagedHostName));
|
||||
verify(dnsQueue, never()).addHostRefreshTask(anyString());
|
||||
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_domainRefresh_unmanagedDomain() {
|
||||
String unmanagedDomainName = "another.example";
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> dnsUtils.requestDomainDnsRefresh(unmanagedDomainName));
|
||||
verify(dnsQueue, never()).addDomainRefreshTask(anyString(), any(Duration.class));
|
||||
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_hostRefresh() {
|
||||
useDnsSql();
|
||||
dnsUtils.requestHostDnsRefresh(hostName);
|
||||
verify(dnsQueue, never()).addHostRefreshTask(anyString());
|
||||
DnsRefreshRequest request = Iterables.getOnlyElement(loadAllOf(DnsRefreshRequest.class));
|
||||
assertRequest(request, TargetType.HOST, hostName, tld, clock.nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_domainRefresh() {
|
||||
useDnsSql();
|
||||
dnsUtils.requestDomainDnsRefresh(domainName);
|
||||
verify(dnsQueue, never()).addDomainRefreshTask(anyString(), any(Duration.class));
|
||||
DnsRefreshRequest request = Iterables.getOnlyElement(loadAllOf(DnsRefreshRequest.class));
|
||||
assertRequest(request, TargetType.DOMAIN, domainName, tld, clock.nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_domainRefreshWithDelay() {
|
||||
useDnsSql();
|
||||
dnsUtils.requestDomainDnsRefresh(domainName, Duration.standardMinutes(3));
|
||||
verify(dnsQueue, never()).addDomainRefreshTask(anyString(), any(Duration.class));
|
||||
DnsRefreshRequest request = Iterables.getOnlyElement(loadAllOf(DnsRefreshRequest.class));
|
||||
assertRequest(request, TargetType.DOMAIN, domainName, tld, clock.nowUtc().plusMinutes(3));
|
||||
}
|
||||
|
||||
private static void assertRequest(
|
||||
DnsRefreshRequest request, TargetType type, String name, String tld, DateTime requestTime) {
|
||||
assertThat(request.getType()).isEqualTo(type);
|
||||
assertThat(request.getName()).isEqualTo(name);
|
||||
assertThat(request.getTld()).isEqualTo(tld);
|
||||
assertThat(request.getRequestTime()).isEqualTo(requestTime);
|
||||
}
|
||||
|
||||
private void useDnsSql() {
|
||||
DateTime currentTime = clock.nowUtc();
|
||||
clock.setTo(START_OF_TIME);
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
.put(START_OF_TIME.plusMillis(8), MigrationState.NORDN_SQL)
|
||||
.put(START_OF_TIME.plusMillis(9), MigrationState.DNS_SQL)
|
||||
.build()));
|
||||
clock.setTo(currentTime);
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import google.registry.request.HttpException.ServiceUnavailableException;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DnsUtilsHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeLockHandler;
|
||||
import google.registry.testing.FakeResponse;
|
||||
@@ -82,7 +83,8 @@ public class PublishDnsUpdatesActionTest {
|
||||
private final FakeLockHandler lockHandler = new FakeLockHandler(true);
|
||||
private final DnsWriter dnsWriter = mock(DnsWriter.class);
|
||||
private final DnsMetrics dnsMetrics = mock(DnsMetrics.class);
|
||||
private final DnsQueue dnsQueue = mock(DnsQueue.class);
|
||||
private final DnsUtils dnsUtils = mock(DnsUtils.class);
|
||||
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
|
||||
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
|
||||
private PublishDnsUpdatesAction action;
|
||||
private InternetAddress outgoingRegistry;
|
||||
@@ -162,7 +164,7 @@ public class PublishDnsUpdatesActionTest {
|
||||
outgoingRegistry,
|
||||
Optional.ofNullable(retryCount),
|
||||
Optional.empty(),
|
||||
dnsQueue,
|
||||
dnsUtils,
|
||||
new DnsWriterProxy(ImmutableMap.of("correctWriter", dnsWriter)),
|
||||
dnsMetrics,
|
||||
lockHandler,
|
||||
@@ -196,7 +198,7 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
}
|
||||
|
||||
@@ -223,7 +225,7 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
}
|
||||
|
||||
@@ -276,7 +278,7 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -496,7 +498,7 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -526,7 +528,7 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -554,7 +556,7 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -580,9 +582,9 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verify(dnsQueue).addDomainRefreshTask("example.com");
|
||||
verify(dnsQueue).addHostRefreshTask("ns1.example.com");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.com");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.com");
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -608,9 +610,9 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verify(dnsQueue).addDomainRefreshTask("example.com");
|
||||
verify(dnsQueue).addHostRefreshTask("ns1.example.com");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.com");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.com");
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -632,11 +634,11 @@ public class PublishDnsUpdatesActionTest {
|
||||
Duration.standardHours(2),
|
||||
Duration.standardHours(1));
|
||||
verifyNoMoreInteractions(dnsMetrics);
|
||||
verify(dnsQueue).addDomainRefreshTask("example.com");
|
||||
verify(dnsQueue).addDomainRefreshTask("example2.com");
|
||||
verify(dnsQueue).addHostRefreshTask("ns1.example.com");
|
||||
verify(dnsQueue).addHostRefreshTask("ns2.example.com");
|
||||
verify(dnsQueue).addHostRefreshTask("ns1.example2.com");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.com");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example2.com");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.com");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns2.example.com");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example2.com");
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,21 +388,6 @@ public class ReadDnsQueueActionTest {
|
||||
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter"));
|
||||
}
|
||||
|
||||
@RetryingTest(4)
|
||||
void testSuccess_zone_getsIgnored() {
|
||||
dnsQueue.addHostRefreshTask("ns1.domain.com");
|
||||
dnsQueue.addDomainRefreshTask("domain.net");
|
||||
dnsQueue.addZoneRefreshTask("example");
|
||||
|
||||
run();
|
||||
|
||||
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
DNS_PUBLISH_PUSH_QUEUE_NAME,
|
||||
new TaskMatcher().url(PublishDnsUpdatesAction.PATH).param("domains", "domain.net"),
|
||||
new TaskMatcher().url(PublishDnsUpdatesAction.PATH).param("hosts", "ns1.domain.com"));
|
||||
}
|
||||
|
||||
private static String makeCommaSeparatedRange(int from, int to, String format) {
|
||||
return IntStream.range(from, to)
|
||||
.mapToObj(i -> String.format(format, i))
|
||||
|
||||
@@ -21,8 +21,6 @@ import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveSubordinateHost;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.domain.Domain;
|
||||
@@ -30,6 +28,7 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
import google.registry.testing.DnsUtilsHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -42,11 +41,12 @@ public class RefreshDnsActionTest {
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final DnsQueue dnsQueue = mock(DnsQueue.class);
|
||||
private final DnsUtils dnsUtils = mock(DnsUtils.class);
|
||||
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
|
||||
private final FakeClock clock = new FakeClock();
|
||||
|
||||
private void run(TargetType type, String name) {
|
||||
new RefreshDnsAction(name, type, clock, dnsQueue).run();
|
||||
new RefreshDnsAction(name, type, clock, dnsUtils).run();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@@ -59,8 +59,8 @@ public class RefreshDnsActionTest {
|
||||
Domain domain = persistActiveDomain("example.xn--q9jyb4c");
|
||||
persistActiveSubordinateHost("ns1.example.xn--q9jyb4c", domain);
|
||||
run(TargetType.HOST, "ns1.example.xn--q9jyb4c");
|
||||
verify(dnsQueue).addHostRefreshTask("ns1.example.xn--q9jyb4c");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.xn--q9jyb4c");
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,7 +74,7 @@ public class RefreshDnsActionTest {
|
||||
try {
|
||||
run(TargetType.HOST, "ns1.example.xn--q9jyb4c");
|
||||
} finally {
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
});
|
||||
assertThat(thrown)
|
||||
@@ -86,8 +86,8 @@ public class RefreshDnsActionTest {
|
||||
void testSuccess_domain() {
|
||||
persistActiveDomain("example.xn--q9jyb4c");
|
||||
run(TargetType.DOMAIN, "example.xn--q9jyb4c");
|
||||
verify(dnsQueue).addDomainRefreshTask("example.xn--q9jyb4c");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.xn--q9jyb4c");
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -24,14 +24,13 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.DnsUtilsHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -43,7 +42,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public class RefreshDnsOnHostRenameActionTest {
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2015-01-15T11:22:33Z"));
|
||||
private final DnsQueue dnsQueue = mock(DnsQueue.class);
|
||||
private final DnsUtils dnsUtils = mock(DnsUtils.class);
|
||||
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
|
||||
@RegisterExtension
|
||||
@@ -53,14 +53,7 @@ public class RefreshDnsOnHostRenameActionTest {
|
||||
private RefreshDnsOnHostRenameAction action;
|
||||
|
||||
private void createAction(String hostKey) {
|
||||
action = new RefreshDnsOnHostRenameAction(hostKey, response, dnsQueue);
|
||||
}
|
||||
|
||||
private void assertDnsTasksEnqueued(String... domains) {
|
||||
for (String domain : domains) {
|
||||
verify(dnsQueue).addDomainRefreshTask(domain);
|
||||
}
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
action = new RefreshDnsOnHostRenameAction(hostKey, response, dnsUtils);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@@ -82,7 +75,7 @@ public class RefreshDnsOnHostRenameActionTest {
|
||||
persistDomainAsDeleted(newDomain("deleted.tld", host), clock.nowUtc().minusDays(1));
|
||||
createAction(host.createVKey().stringify());
|
||||
action.run();
|
||||
assertDnsTasksEnqueued("example.tld", "otherexample.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld", "otherexample.tld");
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
}
|
||||
|
||||
@@ -90,7 +83,7 @@ public class RefreshDnsOnHostRenameActionTest {
|
||||
void testFailure_nonexistentHost() {
|
||||
createAction("kind:Host@sql:rO0ABXQABGJsYWg");
|
||||
action.run();
|
||||
assertDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo("Host to refresh does not exist: VKey<Host>(sql:blah)");
|
||||
@@ -102,7 +95,7 @@ public class RefreshDnsOnHostRenameActionTest {
|
||||
persistResource(newDomain("example.tld", host));
|
||||
createAction(host.createVKey().stringify());
|
||||
action.run();
|
||||
assertDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo("Host to refresh is already deleted: ns1.example.tld");
|
||||
|
||||
@@ -20,9 +20,11 @@ import dagger.Provides;
|
||||
import dagger.Subcomponent;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.batch.AsyncTaskEnqueuerTest;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
|
||||
import google.registry.dns.DnsQueue;
|
||||
import google.registry.dns.DnsUtils;
|
||||
import google.registry.flows.custom.CustomLogicFactory;
|
||||
import google.registry.flows.custom.TestCustomLogicFactory;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils;
|
||||
@@ -30,13 +32,13 @@ import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.request.RequestScope;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.DnsUtilsHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeLockHandler;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.tmch.TmchCertificateAuthority;
|
||||
import google.registry.tmch.TmchXmlSignature;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import google.registry.util.Sleeper;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@@ -59,11 +61,16 @@ public interface EppTestComponent {
|
||||
private FakeLockHandler lockHandler;
|
||||
private Sleeper sleeper;
|
||||
private CloudTasksHelper cloudTasksHelper;
|
||||
private DnsUtilsHelper dnsUtilsHelper;
|
||||
|
||||
public CloudTasksHelper getCloudTasksHelper() {
|
||||
return cloudTasksHelper;
|
||||
}
|
||||
|
||||
public DnsUtilsHelper getDnsUtilsHelper() {
|
||||
return dnsUtilsHelper;
|
||||
}
|
||||
|
||||
public EppMetric.Builder getMetricBuilder() {
|
||||
return metricBuilder;
|
||||
}
|
||||
@@ -82,6 +89,7 @@ public interface EppTestComponent {
|
||||
instance.metricBuilder = EppMetric.builderForRequest(clock);
|
||||
instance.lockHandler = new FakeLockHandler(true);
|
||||
instance.cloudTasksHelper = cloudTasksHelper;
|
||||
instance.dnsUtilsHelper = new DnsUtilsHelper();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -95,6 +103,11 @@ public interface EppTestComponent {
|
||||
return cloudTasksHelper.getTestCloudTasksUtils();
|
||||
}
|
||||
|
||||
@Provides
|
||||
DnsUtils provideDnsUtils() {
|
||||
return dnsUtilsHelper.getDnsUtils();
|
||||
}
|
||||
|
||||
@Provides
|
||||
Clock provideClock() {
|
||||
return clock;
|
||||
|
||||
@@ -45,6 +45,7 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.DnsUtilsHelper;
|
||||
import google.registry.testing.EppLoader;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
@@ -84,6 +85,7 @@ public abstract class FlowTestCase<F extends Flow> {
|
||||
protected TransportCredentials credentials = new PasswordOnlyTransportCredentials();
|
||||
protected EppRequestSource eppRequestSource = EppRequestSource.UNIT_TEST;
|
||||
protected CloudTasksHelper cloudTasksHelper;
|
||||
protected DnsUtilsHelper dnsUtilsHelper;
|
||||
|
||||
private EppMetric.Builder eppMetricBuilder;
|
||||
|
||||
@@ -216,6 +218,7 @@ public abstract class FlowTestCase<F extends Flow> {
|
||||
|
||||
FakesAndMocksModule fakesAndMocksModule = FakesAndMocksModule.create(clock);
|
||||
cloudTasksHelper = fakesAndMocksModule.getCloudTasksHelper();
|
||||
dnsUtilsHelper = fakesAndMocksModule.getDnsUtilsHelper();
|
||||
// Run the flow.
|
||||
return DaggerEppTestComponent.builder()
|
||||
.fakesAndMocksModule(fakesAndMocksModule)
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.flows.domain;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DEFAULT;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.eppoutput.CheckData.DomainCheck.create;
|
||||
@@ -38,6 +39,7 @@ import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
@@ -350,6 +352,28 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_allocationtoken_fee_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_allocationTokenPromotion_doesNotUseValidDefaultToken_singleYear()
|
||||
throws Exception {
|
||||
setUpDefaultToken();
|
||||
createTld("example");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountYears(2)
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().minusDays(1), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().plusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_check_allocationtoken_fee.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_allocationtoken_fee_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_allocationTokenPromotion_multiYearAndPremiums() throws Exception {
|
||||
createTld("example");
|
||||
@@ -760,6 +784,31 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_v06.xml"));
|
||||
}
|
||||
|
||||
private void setUpDefaultToken() {
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_defaultToken_v06() throws Exception {
|
||||
setUpDefaultToken();
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "USD"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v06.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_multipleReservations() throws Exception {
|
||||
persistResource(
|
||||
@@ -780,6 +829,14 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_v11.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_defaultToken_v11() throws Exception {
|
||||
setUpDefaultToken();
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_v11.xml", ImmutableMap.of("CURRENCY", "USD"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v11.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_v12() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
@@ -787,6 +844,14 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_defaultToken_v12() throws Exception {
|
||||
setUpDefaultToken();
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_v12.xml", ImmutableMap.of("CURRENCY", "USD"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_thirtyDomains_restoreFees() throws Exception {
|
||||
// Note that 30 is more than 25, which is the maximum # of entity groups you can enlist in a
|
||||
@@ -810,6 +875,14 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_v06.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_defaultTokenOnlyOnCreate_v06() throws Exception {
|
||||
setUpDefaultToken();
|
||||
setEppInput("domain_check_fee_multiple_commands_v06.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_check_fee_multiple_commands_default_token_response_v06.xml"));
|
||||
}
|
||||
|
||||
// Version 11 cannot have multiple commands.
|
||||
|
||||
@Test
|
||||
@@ -818,6 +891,80 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_defaultTokenOnlyOnCreate_v12() throws Exception {
|
||||
setUpDefaultToken();
|
||||
setEppInput("domain_check_fee_multiple_commands_v12.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_check_fee_multiple_commands_default_token_response_v12.xml"));
|
||||
}
|
||||
|
||||
void testFeeExtension_defaultToken_notValidForAllLabels_v06() throws Exception {
|
||||
createTld("example");
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("example"))
|
||||
.setDiscountPremiums(false)
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("example")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_default_token_multiple_names_v06.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_check_fee_default_token_multiple_names_response_v06.xml"));
|
||||
}
|
||||
|
||||
void testFeeExtension_defaultToken_notValidForAllLabels_v11() throws Exception {
|
||||
createTld("example");
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("example"))
|
||||
.setDiscountPremiums(false)
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("example")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_default_token_multiple_names_v11.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_check_fee_default_token_multiple_names_response_v11.xml"));
|
||||
}
|
||||
|
||||
void testFeeExtension_defaultToken_notValidForAllLabels_v12() throws Exception {
|
||||
createTld("example");
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("example"))
|
||||
.setDiscountPremiums(false)
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("example")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_default_token_multiple_names_v12.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_check_fee_default_token_multiple_names_response_v12.xml"));
|
||||
}
|
||||
|
||||
/** Test the same as {@link #testFeeExtension_multipleCommands_v06} with premium labels. */
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_v06() throws Exception {
|
||||
|
||||
@@ -54,12 +54,6 @@ import static google.registry.testing.DatabaseHelper.persistReservedList;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DomainSubject.assertAboutDomains;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static google.registry.tmch.LordnTaskUtils.QUEUE_CLAIMS;
|
||||
import static google.registry.tmch.LordnTaskUtils.QUEUE_SUNRISE;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.JPY;
|
||||
@@ -155,8 +149,6 @@ import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
@@ -183,7 +175,6 @@ import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import google.registry.tmch.SmdrlCsvParser;
|
||||
import google.registry.tmch.TmchData;
|
||||
@@ -195,12 +186,9 @@ import javax.annotation.Nullable;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.junitpioneer.jupiter.cartesian.CartesianTest;
|
||||
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
|
||||
|
||||
@@ -230,11 +218,6 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
clock.setTo(DateTime.parse("1999-04-03T22:00:00.0Z").minus(Duration.millis(1)));
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
DatabaseMigrationStateSchedule.useUncachedForTest();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void initCreateTest() throws Exception {
|
||||
createTld("tld");
|
||||
@@ -393,7 +376,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.ADD, domain.getRepoId(), billingTime, "TheRegistrar", null),
|
||||
createBillingEvent));
|
||||
assertDnsTasksEnqueued(getUniqueIdFromCommand());
|
||||
dnsUtilsHelper.assertDomainDnsRequests(getUniqueIdFromCommand());
|
||||
}
|
||||
|
||||
private void assertNoLordn() throws Exception {
|
||||
@@ -404,30 +387,16 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.hasLaunchNotice(null)
|
||||
.and()
|
||||
.hasLordnPhase(LordnPhase.NONE);
|
||||
assertNoTasksEnqueued(QUEUE_CLAIMS, QUEUE_SUNRISE);
|
||||
assertNoTasksEnqueued(QUEUE_CLAIMS, QUEUE_SUNRISE);
|
||||
}
|
||||
|
||||
private void assertSunriseLordn(String domainName) throws Exception {
|
||||
private void assertSunriseLordn() throws Exception {
|
||||
assertAboutDomains()
|
||||
.that(reloadResourceByForeignKey())
|
||||
.hasSmdId(SMD_ID)
|
||||
.and()
|
||||
.hasLaunchNotice(null);
|
||||
if (DatabaseMigrationStateSchedule.getValueAtTime(clock.nowUtc())
|
||||
.equals(MigrationState.NORDN_SQL)) {
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.SUNRISE);
|
||||
} else {
|
||||
String expectedPayload =
|
||||
String.format(
|
||||
"%s,%s,%s,1,%s",
|
||||
reloadResourceByForeignKey().getRepoId(),
|
||||
domainName,
|
||||
SMD_ID,
|
||||
SMD_VALID_TIME.plusMillis(17));
|
||||
assertTasksEnqueued(QUEUE_SUNRISE, new TaskMatcher().payload(expectedPayload));
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.NONE);
|
||||
}
|
||||
.hasLaunchNotice(null)
|
||||
.and()
|
||||
.hasLordnPhase(LordnPhase.SUNRISE);
|
||||
}
|
||||
|
||||
private void assertClaimsLordn() throws Exception {
|
||||
@@ -440,20 +409,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"370d0b7c9223372036854775807",
|
||||
"tmch",
|
||||
DateTime.parse("2010-08-16T09:00:00.0Z"),
|
||||
DateTime.parse("2009-08-16T09:00:00.0Z")));
|
||||
if (DatabaseMigrationStateSchedule.getValueAtTime(clock.nowUtc())
|
||||
.equals(MigrationState.NORDN_SQL)) {
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.CLAIMS);
|
||||
} else {
|
||||
TaskMatcher task =
|
||||
new TaskMatcher()
|
||||
.payload(
|
||||
reloadResourceByForeignKey().getRepoId()
|
||||
+ ",example-one.tld,370d0b7c9223372036854775807,1,"
|
||||
+ "2009-08-16T09:00:00.017Z,2009-08-16T09:00:00.000Z");
|
||||
assertTasksEnqueued(QUEUE_CLAIMS, task);
|
||||
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.NONE);
|
||||
}
|
||||
DateTime.parse("2009-08-16T09:00:00.0Z")))
|
||||
.and()
|
||||
.hasLordnPhase(LordnPhase.CLAIMS);
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(
|
||||
@@ -944,7 +902,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
persistContactsAndHosts("net");
|
||||
runFlowAssertResponse(loadFile("domain_create_response_idn_minna.xml"));
|
||||
assertSuccessfulCreate("xn--q9jyb4c", ImmutableSet.of());
|
||||
assertDnsTasksEnqueued("xn--abc-873b2e7eb1k8a4lpjvv.xn--q9jyb4c");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("xn--abc-873b2e7eb1k8a4lpjvv.xn--q9jyb4c");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -953,7 +911,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
persistContactsAndHosts();
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")));
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -966,7 +924,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutDomains()
|
||||
.that(reloadResourceByForeignKey())
|
||||
.hasRegistrationExpirationTime(clock.nowUtc().plusYears(1));
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -977,27 +935,19 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_claimsNotice(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
@Test
|
||||
void testSuccess_claimsNotice() throws Exception {
|
||||
clock.setTo(DateTime.parse("2009-08-16T09:00:00.0Z"));
|
||||
setEppInput("domain_create_claim_notice.xml");
|
||||
persistContactsAndHosts();
|
||||
runFlowAssertResponse(loadFile("domain_create_response_claims.xml"));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of());
|
||||
assertDnsTasksEnqueued("example-one.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example-one.tld");
|
||||
assertClaimsLordn();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_claimsNoticeInQuietPeriod(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
@Test
|
||||
void testSuccess_claimsNoticeInQuietPeriod() throws Exception {
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -1021,7 +971,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
persistContactsAndHosts();
|
||||
runFlowAssertResponse(loadFile("domain_create_response_claims.xml"));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(RESERVED), allocationToken);
|
||||
assertDnsTasksEnqueued("example-one.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example-one.tld");
|
||||
assertClaimsLordn();
|
||||
assertAllocationTokenWasRedeemed("abcDEF23456");
|
||||
}
|
||||
@@ -1034,7 +984,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of());
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1043,7 +993,6 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
persistContactsAndHosts();
|
||||
EppException thrown = assertThrows(MissingClaimsNoticeException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
assertNoTasksEnqueued(QUEUE_CLAIMS, QUEUE_SUNRISE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1419,12 +1368,8 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAllocationTokenWasRedeemed("abcDEF23456");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_anchorTenant_withClaims(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
@Test
|
||||
void testSuccess_anchorTenant_withClaims() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setDomainName("example-one.tld")
|
||||
@@ -1442,7 +1387,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
persistContactsAndHosts();
|
||||
runFlowAssertResponse(loadFile("domain_create_response_claims.xml"));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), allocationToken);
|
||||
assertDnsTasksEnqueued("example-one.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example-one.tld");
|
||||
assertClaimsLordn();
|
||||
assertAllocationTokenWasRedeemed("abcDEF23456");
|
||||
}
|
||||
@@ -1492,12 +1437,8 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE, ANCHOR_TENANT));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_anchorTenantInSunrise_withSignedMark(boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
@Test
|
||||
void testSuccess_anchorTenantInSunrise_withSignedMark() throws Exception {
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -1526,8 +1467,8 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"EXPIRATION_TIME",
|
||||
SMD_VALID_TIME.plusYears(2).toString())));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT, SUNRISE), allocationToken);
|
||||
assertDnsTasksEnqueued("test-validate.tld");
|
||||
assertSunriseLordn("test-validate.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("test-validate.tld");
|
||||
assertSunriseLordn();
|
||||
assertAllocationTokenWasRedeemed("abcDEF23456");
|
||||
}
|
||||
|
||||
@@ -1636,7 +1577,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")));
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(tm().transact(() -> tm().loadAllOf(BillingEvent.OneTime.class)));
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, BigDecimal.valueOf(19.5)));
|
||||
}
|
||||
@@ -1686,7 +1627,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.put("EXDATE", "2004-04-03T22:00:00.0Z")
|
||||
.build()));
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(tm().transact(() -> tm().loadAllOf(BillingEvent.OneTime.class)));
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
|
||||
assertThat(billingEvent.getCost()).isEqualTo(expectedPrice);
|
||||
}
|
||||
@@ -1719,7 +1660,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"domain_create_response_premium.xml",
|
||||
ImmutableMap.of("EXDATE", "2002-04-03T22:00:00.0Z", "FEE", "104.00")));
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(tm().transact(() -> tm().loadAllOf(BillingEvent.OneTime.class)));
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("rich.example");
|
||||
// 1yr @ $100 + 2yrs @ $100 * (1 - 0.98) = $104
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 104.00));
|
||||
@@ -1752,7 +1693,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"domain_create_response_premium.xml",
|
||||
ImmutableMap.of("EXDATE", "2002-04-03T22:00:00.0Z", "FEE", "204.44")));
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(tm().transact(() -> tm().loadAllOf(BillingEvent.OneTime.class)));
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("rich.example");
|
||||
// 2yrs @ $100 + 1yr @ $100 * (1 - 0.95555) = $204.44
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 204.44));
|
||||
@@ -1921,7 +1862,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")));
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(tm().transact(() -> tm().loadAllOf(BillingEvent.OneTime.class)));
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, BigDecimal.valueOf(19.5)));
|
||||
assertThat(billingEvent.getAllocationToken().get().getKey()).isEqualTo("abc123");
|
||||
@@ -2071,6 +2012,41 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, BigDecimal.valueOf(19.5)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_skipsOverExpiredDefaultToken() throws Exception {
|
||||
persistContactsAndHosts();
|
||||
AllocationToken defaultToken1 =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("aaaaa")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("NewRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.build());
|
||||
AllocationToken defaultToken2 =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setDiscountFraction(0.5)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setTokenStatusTransitions(
|
||||
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
|
||||
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
|
||||
.put(clock.nowUtc().minusDays(2), TokenStatus.VALID)
|
||||
.put(clock.nowUtc().minusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(
|
||||
ImmutableList.of(defaultToken1.createVKey(), defaultToken2.createVKey()))
|
||||
.build());
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
BillingEvent.OneTime runTest_defaultToken(String token) throws Exception {
|
||||
setEppInput("domain_create.xml", ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
runFlowAssertResponse(
|
||||
@@ -2082,7 +2058,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.put("EXDATE", "2001-04-03T22:00:00.0Z")
|
||||
.build()));
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(tm().transact(() -> tm().loadAllOf(BillingEvent.OneTime.class)));
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
|
||||
assertThat(billingEvent.getAllocationToken().get().getKey()).isEqualTo(token);
|
||||
return billingEvent;
|
||||
@@ -2097,13 +2073,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(RESERVED));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_reservedNameCollisionDomain_inSunrise_setsServerHoldAndPollMessage(
|
||||
boolean usePullQueue) throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
@Test
|
||||
void testSuccess_reservedNameCollisionDomain_inSunrise_setsServerHoldAndPollMessage()
|
||||
throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -2125,10 +2097,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"EXPIRATION_TIME",
|
||||
SMD_VALID_TIME.plusYears(2).toString())));
|
||||
|
||||
assertSunriseLordn("test-and-validate.tld");
|
||||
assertSunriseLordn();
|
||||
|
||||
// Check for SERVER_HOLD status, no DNS tasks enqueued, and collision poll message.
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
assertThat(domain.getStatusValues()).contains(SERVER_HOLD);
|
||||
assertPollMessagesWithCollisionOneTime(domain);
|
||||
@@ -2145,7 +2117,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "badcrash.tld")));
|
||||
|
||||
// Check for SERVER_HOLD status, no DNS tasks enqueued, and collision poll message.
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
assertThat(domain.getStatusValues()).contains(SERVER_HOLD);
|
||||
assertPollMessagesWithCollisionOneTime(domain);
|
||||
@@ -2646,13 +2618,8 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"tld", "domain_create_response.xml", SUPERUSER, ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark(boolean usePullQueue)
|
||||
throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
@Test
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
clock.setTo(SMD_VALID_TIME);
|
||||
setEppInput(
|
||||
@@ -2670,17 +2637,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"EXPIRATION_TIME",
|
||||
SMD_VALID_TIME.plusYears(2).toString())));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE));
|
||||
assertSunriseLordn("test-validate.tld");
|
||||
assertSunriseLordn();
|
||||
}
|
||||
|
||||
/** Test that missing type= argument on launch create works in start-date sunrise. */
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark_noType(boolean usePullQueue)
|
||||
throws Exception {
|
||||
if (!usePullQueue) {
|
||||
useNordnSql();
|
||||
}
|
||||
@Test
|
||||
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark_noType() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
clock.setTo(SMD_VALID_TIME);
|
||||
setEppInput(
|
||||
@@ -2698,7 +2660,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
"EXPIRATION_TIME",
|
||||
SMD_VALID_TIME.plusYears(2).toString())));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE));
|
||||
assertSunriseLordn("test-validate.tld");
|
||||
assertSunriseLordn();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3733,97 +3695,4 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.isEqualTo(
|
||||
"The package token abc123 cannot be used to register names for longer than 1 year.");
|
||||
}
|
||||
|
||||
private static void useNordnSql() {
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
.build()));
|
||||
tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationStateSchedule.set(
|
||||
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
|
||||
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
|
||||
.put(
|
||||
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
|
||||
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
|
||||
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
.put(START_OF_TIME.plusMillis(8), MigrationState.NORDN_SQL)
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DomainSubject.assertAboutDomains;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
@@ -101,20 +100,16 @@ import google.registry.model.transfer.TransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import java.util.Map;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link DomainDeleteFlow}. */
|
||||
class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain> {
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private Domain domain;
|
||||
private DomainHistory earlierHistoryEntry;
|
||||
|
||||
@@ -362,7 +357,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
// The add grace period is for a billable action, so it should trigger a cancellation.
|
||||
assertAutorenewClosedAndCancellationCreatedFor(
|
||||
graceBillingEvent, getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE, DomainHistory.class));
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
// There should be no poll messages. The previous autorenew poll message should now be deleted.
|
||||
assertThat(getPollMessages("TheRegistrar")).isEmpty();
|
||||
}
|
||||
@@ -752,7 +747,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
.build());
|
||||
DateTime eventTime = clock.nowUtc();
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
assertAutorenewClosedAndCancellationCreatedFor(
|
||||
graceBillingEvent,
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE, DomainHistory.class),
|
||||
@@ -770,7 +765,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
assertOnlyBillingEventIsClosedAutorenew("TheRegistrar");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DE
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.domain.fee.BaseFee.FeeType.RENEW;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
@@ -32,11 +33,13 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.FlowMetadata;
|
||||
import google.registry.flows.HttpSessionMetadata;
|
||||
import google.registry.flows.SessionMetadata;
|
||||
import google.registry.flows.custom.DomainPricingCustomLogic;
|
||||
import google.registry.flows.domain.DomainPricingLogic.AllocationTokenInvalidForPremiumNameException;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
@@ -44,6 +47,7 @@ import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
@@ -133,7 +137,8 @@ public class DomainPricingLogicTest {
|
||||
void testGetDomainRenewPrice_oneYear_standardDomain_noBilling_isStandardPrice()
|
||||
throws EppException {
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(registry, "standard.example", clock.nowUtc(), 1, null))
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry, "standard.example", clock.nowUtc(), 1, null, Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -145,7 +150,8 @@ public class DomainPricingLogicTest {
|
||||
void testGetDomainRenewPrice_multiYear_standardDomain_noBilling_isStandardPrice()
|
||||
throws EppException {
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(registry, "standard.example", clock.nowUtc(), 5, null))
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry, "standard.example", clock.nowUtc(), 5, null, Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -157,7 +163,8 @@ public class DomainPricingLogicTest {
|
||||
void testGetDomainRenewPrice_oneYear_premiumDomain_noBilling_isPremiumPrice()
|
||||
throws EppException {
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(registry, "premium.example", clock.nowUtc(), 1, null))
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry, "premium.example", clock.nowUtc(), 1, null, Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -169,7 +176,8 @@ public class DomainPricingLogicTest {
|
||||
void testGetDomainRenewPrice_multiYear_premiumDomain_noBilling_isPremiumPrice()
|
||||
throws EppException {
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(registry, "premium.example", clock.nowUtc(), 5, null))
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry, "premium.example", clock.nowUtc(), 5, null, Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -186,7 +194,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", DEFAULT, Optional.empty())))
|
||||
"premium.example", DEFAULT, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -194,6 +203,58 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_oneYear_premiumDomain_default_withToken_isPremiumPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(true)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", DEFAULT, Optional.empty()),
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 50).getAmount(), RENEW, true))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetDomainRenewPrice_oneYear_premiumDomain_default_withTokenNotValidForPremiums_throwsException()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.build());
|
||||
assertThrows(
|
||||
AllocationTokenInvalidForPremiumNameException.class,
|
||||
() ->
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", DEFAULT, Optional.empty()),
|
||||
Optional.of(allocationToken)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_multiYear_premiumDomain_default_isPremiumCost() throws EppException {
|
||||
assertThat(
|
||||
@@ -203,7 +264,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", DEFAULT, Optional.empty())))
|
||||
"premium.example", DEFAULT, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -211,6 +273,60 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_multiYear_premiumDomain_default_withToken_isPremiumPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(true)
|
||||
.setDiscountYears(2)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", DEFAULT, Optional.empty()),
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 400).getAmount(), RENEW, true))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetDomainRenewPrice_multiYear_premiumDomain_default_withTokenNotValidForPremiums_throwsException()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.setDiscountYears(2)
|
||||
.build());
|
||||
assertThrows(
|
||||
AllocationTokenInvalidForPremiumNameException.class,
|
||||
() ->
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", DEFAULT, Optional.empty()),
|
||||
Optional.of(allocationToken)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_oneYear_standardDomain_default_isNonPremiumPrice()
|
||||
throws EppException {
|
||||
@@ -221,7 +337,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", DEFAULT, Optional.empty())))
|
||||
"standard.example", DEFAULT, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -229,6 +346,33 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_oneYear_standardDomain_default_withToken_isDiscountedPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"standard.example",
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", DEFAULT, Optional.empty()),
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 5).getAmount(), RENEW, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_multiYear_standardDomain_default_isNonPremiumCost()
|
||||
throws EppException {
|
||||
@@ -239,7 +383,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", DEFAULT, Optional.empty())))
|
||||
"standard.example", DEFAULT, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -247,6 +392,34 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_multiYear_standardDomain_default_withToken_isDiscountedPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.setDiscountYears(2)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"standard.example",
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", DEFAULT, Optional.empty()),
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 40).getAmount(), RENEW, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_oneYear_premiumDomain_anchorTenant_isNonPremiumPrice()
|
||||
throws EppException {
|
||||
@@ -257,7 +430,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", NONPREMIUM, Optional.empty())))
|
||||
"premium.example", NONPREMIUM, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -265,6 +439,34 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetDomainRenewPrice_oneYear_premiumDomain_anchorTenant__withToken_isDiscountedNonPremiumPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", NONPREMIUM, Optional.empty()),
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 5).getAmount(), RENEW, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_multiYear_premiumDomain_anchorTenant_isNonPremiumCost()
|
||||
throws EppException {
|
||||
@@ -275,7 +477,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", NONPREMIUM, Optional.empty())))
|
||||
"premium.example", NONPREMIUM, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -283,6 +486,35 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetDomainRenewPrice_multiYear_premiumDomain_anchorTenant__withToken_isDiscountedNonPremiumPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.setDiscountYears(2)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", NONPREMIUM, Optional.empty()),
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 40).getAmount(), RENEW, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_oneYear_standardDomain_anchorTenant_isNonPremiumPrice()
|
||||
throws EppException {
|
||||
@@ -293,7 +525,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", NONPREMIUM, Optional.empty())))
|
||||
"standard.example", NONPREMIUM, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -311,7 +544,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", NONPREMIUM, Optional.empty())))
|
||||
"standard.example", NONPREMIUM, Optional.empty()),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -329,7 +563,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", SPECIFIED, Optional.of(Money.of(USD, 1)))))
|
||||
"standard.example", SPECIFIED, Optional.of(Money.of(USD, 1))),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -337,6 +572,71 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetDomainRenewPrice_oneYear_standardDomain_internalRegistration_withToken_isSpecifiedPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"standard.example",
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", SPECIFIED, Optional.of(Money.of(USD, 1))),
|
||||
Optional.of(allocationToken)))
|
||||
|
||||
// The allocation token should not discount the speicifed price
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 1).getAmount(), RENEW, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetDomainRenewPrice_oneYear_standardDomain_internalRegistration_withToken_doesNotChangePriceBehavior()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setRenewalPriceBehavior(DEFAULT)
|
||||
.setDiscountPremiums(false)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"standard.example",
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", SPECIFIED, Optional.of(Money.of(USD, 1))),
|
||||
Optional.of(allocationToken)))
|
||||
|
||||
// The allocation token should not discount the speicifed price
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 1).getAmount(), RENEW, false))
|
||||
.build());
|
||||
assertThat(
|
||||
Iterables.getLast(DatabaseHelper.loadAllOf(BillingEvent.Recurring.class))
|
||||
.getRenewalPriceBehavior())
|
||||
.isEqualTo(SPECIFIED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_multiYear_standardDomain_internalRegistration_isSpecifiedPrice()
|
||||
throws EppException {
|
||||
@@ -347,7 +647,36 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", SPECIFIED, Optional.of(Money.of(USD, 1)))))
|
||||
"standard.example", SPECIFIED, Optional.of(Money.of(USD, 1))),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(Money.of(USD, 5).getAmount(), RENEW, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetDomainRenewPrice_multiYear_standardDomain_internalRegistration_withToken_isSpecifiedPrice()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountPremiums(false)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry,
|
||||
"standard.example",
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"standard.example", SPECIFIED, Optional.of(Money.of(USD, 1))),
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -365,7 +694,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
1,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", SPECIFIED, Optional.of(Money.of(USD, 17)))))
|
||||
"premium.example", SPECIFIED, Optional.of(Money.of(USD, 17))),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -383,7 +713,8 @@ public class DomainPricingLogicTest {
|
||||
clock.nowUtc(),
|
||||
5,
|
||||
persistDomainAndSetRecurringBillingEvent(
|
||||
"premium.example", SPECIFIED, Optional.of(Money.of(USD, 17)))))
|
||||
"premium.example", SPECIFIED, Optional.of(Money.of(USD, 17))),
|
||||
Optional.empty()))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -398,7 +729,7 @@ public class DomainPricingLogicTest {
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
domainPricingLogic.getRenewPrice(
|
||||
registry, "standard.example", clock.nowUtc(), -1, null));
|
||||
registry, "standard.example", clock.nowUtc(), -1, null, Optional.empty()));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Number of years must be positive");
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.truth.Truth8;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
@@ -604,12 +605,21 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example.tld")
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountYears(1)
|
||||
.build());
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_renew_response.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2002-04-03T22:00:00.0Z")));
|
||||
assertThat(DatabaseHelper.loadByEntity(allocationToken).getRedemptionHistoryId()).isPresent();
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
|
||||
assertThat(billingEvent.getAllocationToken().get().getKey())
|
||||
.isEqualTo(allocationToken.getToken());
|
||||
// Price is 50% off the first year only. Non-discounted price is $11.
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 16.5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -619,11 +629,20 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||
persistDomain();
|
||||
persistResource(
|
||||
new AllocationToken.Builder().setToken("abc123").setTokenType(UNLIMITED_USE).build());
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_renew_response.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2002-04-03T22:00:00.0Z")));
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
|
||||
assertThat(billingEvent.getAllocationToken().get().getKey()).isEqualTo("abc123");
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 16.5));
|
||||
clock.advanceOneMilli();
|
||||
setEppInput(
|
||||
"domain_renew_allocationtoken.xml",
|
||||
@@ -633,6 +652,38 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
loadFile(
|
||||
"domain_renew_response.xml",
|
||||
ImmutableMap.of("DOMAIN", "other-example.tld", "EXDATE", "2002-04-03T22:00:00.0Z")));
|
||||
billingEvent = Iterables.getLast(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("other-example.tld");
|
||||
assertThat(billingEvent.getAllocationToken().get().getKey()).isEqualTo("abc123");
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 16.5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_allocationTokenMultiYearDiscount() throws Exception {
|
||||
setEppInput(
|
||||
"domain_renew_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||
persistDomain();
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example.tld")
|
||||
.setDiscountFraction(0.5)
|
||||
.setDiscountYears(10)
|
||||
.build());
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_renew_response.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2002-04-03T22:00:00.0Z")));
|
||||
assertThat(DatabaseHelper.loadByEntity(allocationToken).getRedemptionHistoryId()).isPresent();
|
||||
BillingEvent.OneTime billingEvent =
|
||||
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.OneTime.class));
|
||||
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
|
||||
assertThat(billingEvent.getAllocationToken().get().getKey())
|
||||
.isEqualTo(allocationToken.getToken());
|
||||
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 11));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -750,6 +801,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRedemptionHistoryId(historyEntryId)
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
EppException thrown =
|
||||
|
||||
@@ -29,7 +29,6 @@ import static google.registry.testing.DatabaseHelper.persistReservedList;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DomainSubject.assertAboutDomains;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.EUR;
|
||||
@@ -75,20 +74,16 @@ import google.registry.model.reporting.DomainTransactionRecord.TransactionReport
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link DomainRestoreRequestFlow}. */
|
||||
class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreRequestFlow, Domain> {
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private static final ImmutableMap<String, String> FEE_06_MAP =
|
||||
ImmutableMap.of("FEE_VERSION", "0.6", "FEE_NS", "fee", "CURRENCY", "USD");
|
||||
private static final ImmutableMap<String, String> FEE_11_MAP =
|
||||
@@ -192,7 +187,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
|
||||
.and()
|
||||
.hasLastEppUpdateRegistrarId("TheRegistrar");
|
||||
assertThat(domain.getGracePeriods()).isEmpty();
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
// The poll message for the delete should now be gone. The only poll message should be the new
|
||||
// autorenew poll message.
|
||||
assertPollMessages(
|
||||
@@ -261,7 +256,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
|
||||
.and()
|
||||
.hasLastEppUpdateRegistrarId("TheRegistrar");
|
||||
assertThat(domain.getGracePeriods()).isEmpty();
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
// The poll message for the delete should now be gone. The only poll message should be the new
|
||||
// autorenew poll message.
|
||||
assertPollMessages(
|
||||
|
||||
@@ -46,8 +46,6 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DomainSubject.assertAboutDomains;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -106,19 +104,15 @@ import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import java.util.Optional;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link DomainUpdateFlow}. */
|
||||
class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain> {
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private static final DomainDsData SOME_DSDATA =
|
||||
DomainDsData.create(
|
||||
1,
|
||||
@@ -222,7 +216,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
.and()
|
||||
.hasNoAutorenewEndTime();
|
||||
assertNoBillingEvents();
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
assertLastHistoryContainsResource(reloadResourceByForeignKey());
|
||||
}
|
||||
|
||||
@@ -351,7 +345,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
assertThat(domain.getContacts()).hasSize(3);
|
||||
assertThat(loadByKey(domain.getRegistrant()).getContactId()).isEqualTo("max_test_7");
|
||||
assertNoBillingEvents();
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -502,9 +496,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
.map(ds -> ds.cloneWithDomainRepoId(resource.getRepoId()))
|
||||
.collect(toImmutableSet()));
|
||||
if (dnsTaskEnqueued) {
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
} else {
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1765,7 +1759,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_TRANSFER_PROHIBITED))
|
||||
.build());
|
||||
runFlowAsSuperuser();
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1781,7 +1775,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.SERVER_HOLD))
|
||||
.build());
|
||||
runFlowAsSuperuser();
|
||||
assertDnsTasksEnqueued("example.tld");
|
||||
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1797,6 +1791,6 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE, StatusValue.SERVER_HOLD))
|
||||
.build());
|
||||
runFlowAsSuperuser();
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ import static google.registry.testing.DatabaseHelper.persistDeletedHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.HostSubject.assertAboutHosts;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
@@ -54,16 +52,12 @@ import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link HostCreateFlow}. */
|
||||
class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
|
||||
|
||||
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private void setEppHostCreateInput(String hostName, String hostAddrs) {
|
||||
setEppInput(
|
||||
"host_create.xml",
|
||||
@@ -122,7 +116,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
|
||||
void testSuccess_externalNeverExisted() throws Exception {
|
||||
doSuccessfulTest();
|
||||
assertAboutHosts().that(reloadResourceByForeignKey()).hasSuperordinateDomain(null);
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -133,7 +127,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
|
||||
loadByForeignKey(Domain.class, "example.tld", clock.nowUtc()).get();
|
||||
assertAboutHosts().that(host).hasSuperordinateDomain(superordinateDomain.createVKey());
|
||||
assertThat(superordinateDomain.getSubordinateHosts()).containsExactly("ns1.example.tld");
|
||||
assertDnsTasksEnqueued("ns1.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -150,7 +144,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
|
||||
persistDeletedHost(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
|
||||
doSuccessfulTest();
|
||||
assertAboutHosts().that(reloadResourceByForeignKey()).hasSuperordinateDomain(null);
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -162,7 +156,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
|
||||
loadByForeignKey(Domain.class, "example.tld", clock.nowUtc()).get();
|
||||
assertAboutHosts().that(host).hasSuperordinateDomain(superordinateDomain.createVKey());
|
||||
assertThat(superordinateDomain.getSubordinateHosts()).containsExactly("ns1.example.tld");
|
||||
assertDnsTasksEnqueued("ns1.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -24,8 +24,6 @@ import static google.registry.testing.DatabaseHelper.persistDeletedHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.HostSubject.assertAboutHosts;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -48,17 +46,13 @@ import google.registry.model.tld.Registry;
|
||||
import google.registry.model.transfer.DomainTransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link HostDeleteFlow}. */
|
||||
class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Host> {
|
||||
|
||||
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
@BeforeEach
|
||||
void initFlowTest() {
|
||||
setEppInput("host_delete.xml", ImmutableMap.of("HOSTNAME", "ns1.example.tld"));
|
||||
@@ -320,10 +314,10 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Host> {
|
||||
.hasType(Type.HOST_DELETE);
|
||||
assertNoBillingEvents();
|
||||
if (isSubordinate) {
|
||||
assertDnsTasksEnqueued(deletedHost.getHostName());
|
||||
dnsUtilsHelper.assertHostDnsRequests(deletedHost.getHostName());
|
||||
assertThat(loadByKey(deletedHost.getSuperordinateDomain()).getSubordinateHosts()).isEmpty();
|
||||
} else {
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
assertLastHistoryContainsResource(deletedHost);
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptio
|
||||
import static google.registry.testing.GenericEppResourceSubject.assertAboutEppResources;
|
||||
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
|
||||
import static google.registry.testing.HostSubject.assertAboutHosts;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@@ -81,17 +79,13 @@ import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link HostUpdateFlow}. */
|
||||
class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
|
||||
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private void setEppHostUpdateInput(
|
||||
String oldHostName, String newHostName, String ipOrStatusToAdd, String ipOrStatusToRem) {
|
||||
setEppInput(
|
||||
@@ -189,7 +183,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
Host renamedHost = doSuccessfulTest();
|
||||
assertThat(renamedHost.isSubordinate()).isTrue();
|
||||
assertDnsTasksEnqueued("ns1.example.tld", "ns2.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld", "ns2.example.tld");
|
||||
VKey<Host> oldVKeyAfterRename = ForeignKeyUtils.load(Host.class, oldHostName(), clock.nowUtc());
|
||||
assertThat(oldVKeyAfterRename).isNull();
|
||||
}
|
||||
@@ -238,7 +232,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.and()
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.HOST_UPDATE);
|
||||
assertDnsTasksEnqueued("ns1.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -264,7 +258,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.and()
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.HOST_UPDATE);
|
||||
assertDnsTasksEnqueued("ns1.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -298,7 +292,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.hasLastTransferTime(oneDayAgo);
|
||||
Domain reloadedDomain = loadByEntity(domain).cloneProjectedAtTime(now);
|
||||
assertThat(reloadedDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns1.example.tld", "ns2.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld", "ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -333,7 +327,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
assertThat(loadByEntity(foo).cloneProjectedAtTime(now).getSubordinateHosts()).isEmpty();
|
||||
assertThat(loadByEntity(example).cloneProjectedAtTime(now).getSubordinateHosts())
|
||||
.containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns2.foo.tld", "ns2.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns2.foo.tld", "ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -370,7 +364,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
assertThat(reloadedFooDomain.getSubordinateHosts()).isEmpty();
|
||||
Domain reloadedTldDomain = loadByEntity(tldDomain).cloneProjectedAtTime(now);
|
||||
assertThat(reloadedTldDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns1.example.foo", "ns2.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.foo", "ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -413,7 +407,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
assertThat(renamedHost.getLastTransferTime()).isEqualTo(oneDayAgo);
|
||||
Domain reloadedDomain = loadByEntity(domain).cloneProjectedAtTime(clock.nowUtc());
|
||||
assertThat(reloadedDomain.getSubordinateHosts()).isEmpty();
|
||||
assertDnsTasksEnqueued("ns1.example.foo");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns1.example.foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -425,7 +419,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
persistActiveHost(oldHostName());
|
||||
assertThat(domain.getSubordinateHosts()).isEmpty();
|
||||
assertThrows(CannotRenameExternalHostException.class, this::runFlow);
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -449,7 +443,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.hasLastTransferTime(null);
|
||||
assertThat(loadByEntity(domain).cloneProjectedAtTime(now).getSubordinateHosts())
|
||||
.containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns2.example.tld");
|
||||
dnsUtilsHelper.assertHostDnsRequests("ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -474,7 +468,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.hasPersistedCurrentSponsorRegistrarId("TheRegistrar")
|
||||
.and()
|
||||
.hasLastTransferTime(null);
|
||||
assertNoDnsTasksEnqueued();
|
||||
dnsUtilsHelper.assertNoMoreDnsRequests();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright 2023 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.model.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||
import static google.registry.testing.DatabaseHelper.loadAllOf;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link DnsRefreshRequest}. */
|
||||
public class DnsRefreshRequestTest extends EntityTestCase {
|
||||
|
||||
DnsRefreshRequestTest() {
|
||||
super(JpaEntityCoverageCheck.ENABLED);
|
||||
}
|
||||
|
||||
private final DnsRefreshRequest request =
|
||||
new DnsRefreshRequest(TargetType.DOMAIN, "test.example", "example", fakeClock.nowUtc());
|
||||
|
||||
@Test
|
||||
void testPersistence() {
|
||||
assertThat(request.getLastProcessTime()).isEqualTo(START_OF_TIME);
|
||||
fakeClock.advanceOneMilli();
|
||||
insertInDb(request);
|
||||
fakeClock.advanceOneMilli();
|
||||
ImmutableList<DnsRefreshRequest> requests = loadAllOf(DnsRefreshRequest.class);
|
||||
assertThat(requests.size()).isEqualTo(1);
|
||||
assertThat(requests.get(0)).isEqualTo(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullValues() {
|
||||
// type
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> new DnsRefreshRequest(null, "test.example", "example", fakeClock.nowUtc()));
|
||||
// name
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> new DnsRefreshRequest(TargetType.DOMAIN, null, "example", fakeClock.nowUtc()));
|
||||
// tld
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> new DnsRefreshRequest(TargetType.DOMAIN, "test.example", null, fakeClock.nowUtc()));
|
||||
// request time
|
||||
assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> new DnsRefreshRequest(TargetType.DOMAIN, "test.example", "example", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateProcessTime() {
|
||||
assertThat(
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> request.updateProcessTime(fakeClock.nowUtc())))
|
||||
.hasMessageThat()
|
||||
.contains("must be later than request time");
|
||||
|
||||
fakeClock.advanceOneMilli();
|
||||
fakeClock.advanceOneMilli();
|
||||
|
||||
DnsRefreshRequest newRequest = request.updateProcessTime(fakeClock.nowUtc());
|
||||
assertAboutImmutableObjects().that(newRequest).isEqualExceptFields(request, "lastProcessTime");
|
||||
assertThat(newRequest.getLastProcessTime()).isEqualTo(fakeClock.nowUtc());
|
||||
|
||||
assertThat(
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> newRequest.updateProcessTime(fakeClock.nowUtc().minusMillis(1))))
|
||||
.hasMessageThat()
|
||||
.contains("must be later than the old one");
|
||||
}
|
||||
}
|
||||
@@ -72,11 +72,7 @@ public class UserTest extends EntityTestCase {
|
||||
assertThat(assertThrows(IllegalArgumentException.class, () -> builder.setUserRoles(null)))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("User roles cannot be null");
|
||||
|
||||
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Gaia ID cannot be null");
|
||||
builder.setGaiaId("gaiaId");
|
||||
|
||||
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Email address cannot be null");
|
||||
|
||||
@@ -37,6 +37,7 @@ import google.registry.model.Buildable;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenType;
|
||||
@@ -77,6 +78,7 @@ public class AllocationTokenTest extends EntityTestCase {
|
||||
.put(DateTime.now(UTC), TokenStatus.VALID)
|
||||
.put(DateTime.now(UTC).plusWeeks(8), TokenStatus.ENDED)
|
||||
.build())
|
||||
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE, CommandName.RENEW))
|
||||
.build());
|
||||
assertThat(loadByEntity(unlimitedUseToken)).isEqualTo(unlimitedUseToken);
|
||||
|
||||
@@ -113,6 +115,7 @@ public class AllocationTokenTest extends EntityTestCase {
|
||||
.put(DateTime.now(UTC), TokenStatus.VALID)
|
||||
.put(DateTime.now(UTC).plusWeeks(8), TokenStatus.ENDED)
|
||||
.build())
|
||||
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE, CommandName.RENEW))
|
||||
.build());
|
||||
AllocationToken persisted = loadByEntity(unlimitedUseToken);
|
||||
assertThat(SerializeUtils.serializeDeserialize(persisted)).isEqualTo(persisted);
|
||||
|
||||
@@ -18,17 +18,14 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.model.server.Lock.LockState.FREE;
|
||||
import static google.registry.model.server.Lock.LockState.IN_USE;
|
||||
import static google.registry.model.server.Lock.LockState.OWNER_DIED;
|
||||
import static google.registry.model.server.Lock.LockState.TIMED_OUT;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.server.Lock.LockState;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@@ -41,7 +38,6 @@ public class LockTest extends EntityTestCase {
|
||||
private static final String RESOURCE_NAME = "foo";
|
||||
private static final Duration ONE_DAY = Duration.standardDays(1);
|
||||
private static final Duration TWO_MILLIS = Duration.millis(2);
|
||||
private static final RequestStatusChecker requestStatusChecker = mock(RequestStatusChecker.class);
|
||||
|
||||
private LockMetrics origLockMetrics;
|
||||
|
||||
@@ -52,7 +48,7 @@ public class LockTest extends EntityTestCase {
|
||||
private static Optional<Lock> acquire(
|
||||
String tld, Duration leaseLength, LockState expectedLockState) {
|
||||
Lock.lockMetrics = mock(LockMetrics.class);
|
||||
Optional<Lock> lock = Lock.acquire(RESOURCE_NAME, tld, leaseLength, requestStatusChecker, true);
|
||||
Optional<Lock> lock = Lock.acquire(RESOURCE_NAME, tld, leaseLength);
|
||||
verify(Lock.lockMetrics).recordAcquire(RESOURCE_NAME, tld, expectedLockState);
|
||||
verifyNoMoreInteractions(Lock.lockMetrics);
|
||||
Lock.lockMetrics = null;
|
||||
@@ -72,8 +68,6 @@ public class LockTest extends EntityTestCase {
|
||||
void beforeEach() {
|
||||
origLockMetrics = Lock.lockMetrics;
|
||||
Lock.lockMetrics = null;
|
||||
when(requestStatusChecker.getLogId()).thenReturn("current-request-id");
|
||||
when(requestStatusChecker.isRunning("current-request-id")).thenReturn(true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -111,9 +105,6 @@ public class LockTest extends EntityTestCase {
|
||||
assertThat(acquire("", ONE_DAY, FREE)).isPresent();
|
||||
// We can't get it again while request is active
|
||||
assertThat(acquire("", ONE_DAY, IN_USE)).isEmpty();
|
||||
// But if request is finished, we can get it.
|
||||
when(requestStatusChecker.isRunning("current-request-id")).thenReturn(false);
|
||||
assertThat(acquire("", ONE_DAY, OWNER_DIED)).isPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -134,9 +125,7 @@ public class LockTest extends EntityTestCase {
|
||||
@Test
|
||||
void testFailure_emptyResourceName() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> Lock.acquire("", "", TWO_MILLIS, requestStatusChecker, true));
|
||||
assertThrows(IllegalArgumentException.class, () -> Lock.acquire("", "", TWO_MILLIS));
|
||||
assertThat(thrown).hasMessageThat().contains("resourceName cannot be null or empty");
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user