mirror of
https://github.com/google/nomulus
synced 2026-07-06 16:16:38 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e4f8495d6 | |||
| 6042f77d1f | |||
| 8d180f535f | |||
| 99a31423e0 | |||
| 9dab1e86ec |
@@ -1,16 +0,0 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
@@ -1,27 +1,52 @@
|
||||
# ConsoleWebapp
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.3.
|
||||
A web application for managing [Nomulus](https://github.com/google/nomulus).
|
||||
|
||||
## Status
|
||||
|
||||
Console webapp is currently under active development and some parts of it are
|
||||
expected to change.
|
||||
|
||||
## Deployment
|
||||
|
||||
Webapp is deployed with the nomulus default service war to Google App Engine.
|
||||
During nomulus default service war build task, gradle script triggers the
|
||||
following:
|
||||
|
||||
1) Console webapp build script `buildConsoleWebappProd`, which installs
|
||||
dependencies, assembles a compiled ts -> js, minified, optimized static
|
||||
artifact (html, css, js)
|
||||
2) Artifact assembled in step 1 then gets copied to core project web artifact
|
||||
location, so that it can be deployed with the rest of the core webapp
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
|
||||
Run `npm run start:dev` to start both webapp dev server and API server instance.
|
||||
Navigate to `http://localhost:4200/`. The application will automatically reload
|
||||
if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
Run `ng generate component component-name` to generate a new component. You can
|
||||
also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
Run `ng build` to build the project. The build artifacts will be stored in
|
||||
the `dist/` directory.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
Run `ng test` to execute the unit tests
|
||||
via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To
|
||||
use this command, you need to first add a package that implements end-to-end
|
||||
testing capabilities.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
To get more help on the Angular CLI use `ng help` or go check out
|
||||
the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
|
||||
Generated
+4415
-4012
File diff suppressed because it is too large
Load Diff
+16
-15
@@ -13,25 +13,26 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^14.2.0",
|
||||
"@angular/cdk": "^14.2.2",
|
||||
"@angular/common": "^14.2.0",
|
||||
"@angular/compiler": "^14.2.0",
|
||||
"@angular/core": "^14.2.0",
|
||||
"@angular/forms": "^14.2.0",
|
||||
"@angular/material": "^14.2.2",
|
||||
"@angular/platform-browser": "^14.2.0",
|
||||
"@angular/platform-browser-dynamic": "^14.2.0",
|
||||
"@angular/router": "^14.2.0",
|
||||
"@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",
|
||||
"rxjs": "~7.5.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^14.2.3",
|
||||
"@angular/cli": "~14.2.3",
|
||||
"@angular/compiler-cli": "^14.2.0",
|
||||
"@angular-devkit/build-angular": "^15.1.0",
|
||||
"@angular/cli": "~15.1.0",
|
||||
"@angular/compiler-cli": "^15.1.0",
|
||||
"@types/jasmine": "~4.0.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"concurrently": "^7.6.0",
|
||||
"jasmine-core": "~4.3.0",
|
||||
"karma": "~6.4.0",
|
||||
@@ -39,6 +40,6 @@
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"typescript": "~4.7.2"
|
||||
"typescript": "~4.9.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,20 +7,8 @@ import {
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(path: string, deep?: boolean, filter?: RegExp): {
|
||||
<T>(id: string): T;
|
||||
keys(): string[];
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting(),
|
||||
);
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().forEach(context);
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2020",
|
||||
"target": "ES2022",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2020",
|
||||
"dom"
|
||||
]
|
||||
],
|
||||
"useDefineForClassFields": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
|
||||
+6
-1
@@ -752,9 +752,14 @@ if (environment == 'alpha') {
|
||||
],
|
||||
invoicing :
|
||||
[
|
||||
mainClass: 'google.registry.beam.invoicing.InvoicingPipeline',
|
||||
mainClass: 'google.registry.beam.billing.InvoicingPipeline',
|
||||
metaData : 'google/registry/beam/invoicing_pipeline_metadata.json'
|
||||
],
|
||||
expandBilling :
|
||||
[
|
||||
mainClass: 'google.registry.beam.billing.ExpandRecurringBillingEventsPipeline',
|
||||
metaData : 'google/registry/beam/expand_recurring_billing_events_pipeline_metadata.json'
|
||||
],
|
||||
rde :
|
||||
[
|
||||
mainClass: 'google.registry.beam.rde.RdePipeline',
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.invoicing;
|
||||
package google.registry.beam.billing;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.Joiner;
|
||||
+460
@@ -0,0 +1,460 @@
|
||||
// Copyright 2022 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.beam.billing;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
||||
import static google.registry.model.domain.Period.Unit.YEARS;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.union;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.earliestOf;
|
||||
import static google.registry.util.DateTimeUtils.latestOf;
|
||||
import static org.apache.beam.sdk.values.TypeDescriptors.voids;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Range;
|
||||
import dagger.Component;
|
||||
import google.registry.beam.common.RegistryJpaIO;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
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.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingEvent.Cancellation;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.common.Cursor;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.SystemClock;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Set;
|
||||
import javax.inject.Singleton;
|
||||
import org.apache.beam.sdk.Pipeline;
|
||||
import org.apache.beam.sdk.PipelineResult;
|
||||
import org.apache.beam.sdk.coders.KvCoder;
|
||||
import org.apache.beam.sdk.coders.VarIntCoder;
|
||||
import org.apache.beam.sdk.coders.VarLongCoder;
|
||||
import org.apache.beam.sdk.metrics.Counter;
|
||||
import org.apache.beam.sdk.metrics.Metrics;
|
||||
import org.apache.beam.sdk.options.PipelineOptionsFactory;
|
||||
import org.apache.beam.sdk.transforms.Create;
|
||||
import org.apache.beam.sdk.transforms.DoFn;
|
||||
import org.apache.beam.sdk.transforms.GroupIntoBatches;
|
||||
import org.apache.beam.sdk.transforms.MapElements;
|
||||
import org.apache.beam.sdk.transforms.ParDo;
|
||||
import org.apache.beam.sdk.transforms.Wait;
|
||||
import org.apache.beam.sdk.values.KV;
|
||||
import org.apache.beam.sdk.values.PCollection;
|
||||
import org.apache.beam.sdk.values.PDone;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Definition of a Dataflow Flex pipeline template, which expands {@link Recurring} to {@link
|
||||
* OneTime} when an autorenew occurs within the given time frame.
|
||||
*
|
||||
* <p>This pipeline works in three stages:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Gather the {@link Recurring}s that are in scope for expansion. The exact condition of
|
||||
* {@link Recurring}s to include can be found in {@link #getRecurringsInScope(Pipeline)}.
|
||||
* <li>Expand the {@link Recurring}s to {@link OneTime} (and corresponding {@link DomainHistory})
|
||||
* that fall within the [{@link #startTime}, {@link #endTime}) window, excluding those that
|
||||
* are already present (to make this pipeline idempotent when running with the same parameters
|
||||
* multiple times, either in parallel or in sequence). The {@link Recurring} is also updated
|
||||
* with the information on when it was last expanded, so it would not be in scope for
|
||||
* expansion until at least a year later.
|
||||
* <li>If the cursor for billing events should be advanced, advance it to {@link #endTime} after
|
||||
* all of the expansions in the previous step is done, only when it is currently at {@link
|
||||
* #startTime}.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note that the creation of new {@link OneTime} and {@link DomainHistory} is done speculatively
|
||||
* as soon as its event time is in scope for expansion (i.e. within the window of operation). If a
|
||||
* domain is subsequently cancelled during the autorenew grace period, a {@link Cancellation} would
|
||||
* have been created to cancel the {@link OneTime} out. Similarly, a {@link DomainHistory} for the
|
||||
* delete will be created which negates the effect of the speculatively created {@link
|
||||
* DomainHistory}, specifically for the transaction records. Both the {@link OneTime} and {@link
|
||||
* DomainHistory} will only be used (and cancelled out) when the billing time becomes effective,
|
||||
* which is after the grace period, when the cancellations would have been written, if need be. This
|
||||
* is no different from what we do with manual renewals or normal creates, where entities are always
|
||||
* created for the action regardless of whether their effects will be negated later due to
|
||||
* subsequent actions within respective grace periods.
|
||||
*
|
||||
* <p>To stage this template locally, run {@code ./nom_build :core:sBP --environment=alpha \
|
||||
* --pipeline=expandBilling}.
|
||||
*
|
||||
* <p>Then, you can run the staged template via the API client library, gCloud or a raw REST call.
|
||||
*
|
||||
* @see Cancellation#forGracePeriod
|
||||
* @see google.registry.flows.domain.DomainFlowUtils#createCancelingRecords
|
||||
* @see <a href="https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates">Using
|
||||
* Flex Templates</a>
|
||||
*/
|
||||
public class ExpandRecurringBillingEventsPipeline implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5827984301386630194L;
|
||||
|
||||
private static final DomainPricingLogic domainPricingLogic;
|
||||
|
||||
private static final int batchSize;
|
||||
|
||||
static {
|
||||
PipelineComponent pipelineComponent =
|
||||
DaggerExpandRecurringBillingEventsPipeline_PipelineComponent.create();
|
||||
domainPricingLogic = pipelineComponent.domainPricingLogic();
|
||||
batchSize = pipelineComponent.batchSize();
|
||||
}
|
||||
|
||||
// Inclusive lower bound of the expansion window.
|
||||
private final DateTime startTime;
|
||||
// Exclusive lower bound of the expansion window.
|
||||
private final DateTime endTime;
|
||||
private final boolean isDryRun;
|
||||
private final boolean advanceCursor;
|
||||
private final Counter recurringsInScopeCounter =
|
||||
Metrics.counter("ExpandBilling", "RecurringsInScope");
|
||||
private final Counter expandedOneTimeCounter =
|
||||
Metrics.counter("ExpandBilling", "ExpandedOneTime");
|
||||
|
||||
ExpandRecurringBillingEventsPipeline(
|
||||
ExpandRecurringBillingEventsPipelineOptions options, Clock clock) {
|
||||
startTime = DateTime.parse(options.getStartTime());
|
||||
endTime = DateTime.parse(options.getEndTime());
|
||||
checkArgument(
|
||||
!endTime.isAfter(clock.nowUtc()),
|
||||
String.format("End time %s must be on or before now.", endTime));
|
||||
checkArgument(
|
||||
startTime.isBefore(endTime),
|
||||
String.format("[%s, %s) is not a valid window of operation.", startTime, endTime));
|
||||
isDryRun = options.getIsDryRun();
|
||||
advanceCursor = options.getAdvanceCursor();
|
||||
}
|
||||
|
||||
private PipelineResult run(Pipeline pipeline) {
|
||||
setupPipeline(pipeline);
|
||||
return pipeline.run();
|
||||
}
|
||||
|
||||
void setupPipeline(Pipeline pipeline) {
|
||||
PCollection<KV<Integer, Long>> recurringIds = getRecurringsInScope(pipeline);
|
||||
PCollection<Void> expanded = expandRecurrings(recurringIds);
|
||||
if (!isDryRun && advanceCursor) {
|
||||
advanceCursor(expanded);
|
||||
}
|
||||
}
|
||||
|
||||
PCollection<KV<Integer, Long>> getRecurringsInScope(Pipeline pipeline) {
|
||||
return pipeline.apply(
|
||||
"Read all Recurrings in scope",
|
||||
// Use native query because JPQL does not support timestamp arithmetics.
|
||||
RegistryJpaIO.read(
|
||||
"SELECT billing_recurrence_id "
|
||||
+ "FROM \"BillingRecurrence\" "
|
||||
// Recurrence should not close before the first event time.
|
||||
+ "WHERE event_time < recurrence_end_time "
|
||||
// First event time should be before end time.
|
||||
+ "AND event_Time < :endTime "
|
||||
// Recurrence should not close before start time.
|
||||
+ "AND :startTime < recurrence_end_time "
|
||||
// Last expansion should happen at least one year before start time.
|
||||
+ "AND recurrence_last_expansion < :oneYearAgo "
|
||||
// The recurrence should not close before next expansion time.
|
||||
+ "AND recurrence_last_expansion + INTERVAL '1 YEAR' < recurrence_end_time",
|
||||
ImmutableMap.of(
|
||||
"endTime",
|
||||
endTime,
|
||||
"startTime",
|
||||
startTime,
|
||||
"oneYearAgo",
|
||||
endTime.minusYears(1)),
|
||||
true,
|
||||
(BigInteger id) -> {
|
||||
// Note that because all elements are mapped to the same dummy key, the next
|
||||
// batching transform will effectively be serial. This however does not matter for
|
||||
// our use case because the elements were obtained from a SQL read query, which
|
||||
// are returned sequentially already. Therefore, having a sequential step to group
|
||||
// them does not reduce overall parallelism of the pipeline, and the batches can
|
||||
// then be distributed to all available workers for further processing, where the
|
||||
// main benefit of parallelism shows. In benchmarking, turning the distribution
|
||||
// of elements in this step resulted in marginal improvement in overall
|
||||
// performance at best without clear indication on why or to which degree. If the
|
||||
// runtime becomes a concern later on, we could consider fine-tuning the sharding
|
||||
// of output elements in this step.
|
||||
//
|
||||
// See: https://stackoverflow.com/a/44956702/791306
|
||||
return KV.of(0, id.longValue());
|
||||
})
|
||||
.withCoder(KvCoder.of(VarIntCoder.of(), VarLongCoder.of())));
|
||||
}
|
||||
|
||||
private PCollection<Void> expandRecurrings(PCollection<KV<Integer, Long>> recurringIds) {
|
||||
return recurringIds
|
||||
.apply(
|
||||
"Group into batches",
|
||||
GroupIntoBatches.<Integer, Long>ofSize(batchSize).withShardedKey())
|
||||
.apply(
|
||||
"Expand and save Recurrings into OneTimes and corresponding DomainHistories",
|
||||
MapElements.into(voids())
|
||||
.via(
|
||||
element -> {
|
||||
Iterable<Long> ids = element.getValue();
|
||||
tm().transact(
|
||||
() -> {
|
||||
ImmutableSet.Builder<ImmutableObject> results =
|
||||
new ImmutableSet.Builder<>();
|
||||
ids.forEach(id -> expandOneRecurring(id, results));
|
||||
if (!isDryRun) {
|
||||
tm().putAll(results.build());
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}));
|
||||
}
|
||||
|
||||
private void expandOneRecurring(Long recurringId, ImmutableSet.Builder<ImmutableObject> results) {
|
||||
Recurring recurring = tm().loadByKey(Recurring.createVKey(recurringId));
|
||||
recurringsInScopeCounter.inc();
|
||||
Domain domain = tm().loadByKey(Domain.createVKey(recurring.getDomainRepoId()));
|
||||
Registry tld = Registry.get(domain.getTld());
|
||||
|
||||
// Determine the complete set of EventTimes this recurring event should expand to within
|
||||
// [max(recurrenceLastExpansion + 1 yr, startTime), min(recurrenceEndTime, endTime)).
|
||||
ImmutableSet<DateTime> eventTimes =
|
||||
ImmutableSet.copyOf(
|
||||
recurring
|
||||
.getRecurrenceTimeOfYear()
|
||||
.getInstancesInRange(
|
||||
Range.closedOpen(
|
||||
latestOf(recurring.getRecurrenceLastExpansion().plusYears(1), startTime),
|
||||
earliestOf(recurring.getRecurrenceEndTime(), endTime))));
|
||||
|
||||
// Find the times for which the OneTime billing event are already created, making this expansion
|
||||
// idempotent. There is no need to match to the domain repo ID as the cancellation matching
|
||||
// billing event itself can only be for a single domain.
|
||||
ImmutableSet<DateTime> existingEventTimes =
|
||||
ImmutableSet.copyOf(
|
||||
tm().query(
|
||||
"SELECT eventTime FROM BillingEvent WHERE cancellationMatchingBillingEvent ="
|
||||
+ " :key",
|
||||
DateTime.class)
|
||||
.setParameter("key", recurring.createVKey())
|
||||
.getResultList());
|
||||
|
||||
Set<DateTime> eventTimesToExpand = difference(eventTimes, existingEventTimes);
|
||||
|
||||
if (eventTimesToExpand.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DateTime recurrenceLastExpansionTime = recurring.getRecurrenceLastExpansion();
|
||||
|
||||
// Create new OneTime and DomainHistory for EventTimes that needs to be expanded.
|
||||
for (DateTime eventTime : eventTimesToExpand) {
|
||||
recurrenceLastExpansionTime = latestOf(recurrenceLastExpansionTime, eventTime);
|
||||
expandedOneTimeCounter.inc();
|
||||
DateTime billingTime = eventTime.plus(tld.getAutoRenewGracePeriodLength());
|
||||
// Note that the DomainHistory is created as of transaction time, as opposed to event time.
|
||||
// This might be counterintuitive because other DomainHistories are created at the time
|
||||
// mutation events occur, such as in DomainDeleteFlow or DomainRenewFlow. Therefore, it is
|
||||
// possible to have a DomainHistory for a delete during the autorenew grace period with a
|
||||
// modification time before that of the DomainHistory for the autorenew itself. This is not
|
||||
// ideal, but necessary because we save the **current** state of the domain (as of transaction
|
||||
// time) to the DomainHistory , instead of the state of the domain as of event time (which
|
||||
// would required loading the domain from DomainHistory at event time).
|
||||
//
|
||||
// Even though doing the loading is seemly possible, it generally is a bad idea to create
|
||||
// DomainHistories retroactively and in all instances that we create a HistoryEntry we always
|
||||
// set the modification time to the transaction time. It would also violate the invariance
|
||||
// that a DomainHistory with a higher revision ID (which is always allocated with monotonic
|
||||
// increase) always has a later modification time.
|
||||
//
|
||||
// Lastly because the domain entity itself did not change as part of the expansion, we should
|
||||
// not project it to transaction time before saving it in the history, which would require us
|
||||
// to save the projected domain as well. Any changes to the domain itself are handled when
|
||||
// the domain is actually used or explicitly projected and saved. The DomainHistory created
|
||||
// here does not actually affect anything materially (e.g. RDE). We can understand it in such
|
||||
// a way that this history represents not when the domain is autorenewed (at event time), but
|
||||
// when its autorenew billing event is created (at transaction time).
|
||||
DomainHistory historyEntry =
|
||||
new DomainHistory.Builder()
|
||||
.setBySuperuser(false)
|
||||
.setRegistrarId(recurring.getRegistrarId())
|
||||
.setModificationTime(tm().getTransactionTime())
|
||||
.setDomain(domain)
|
||||
.setPeriod(Period.create(1, YEARS))
|
||||
.setReason("Domain autorenewal by ExpandRecurringBillingEventsPipeline")
|
||||
.setRequestedByRegistrar(false)
|
||||
.setType(DOMAIN_AUTORENEW)
|
||||
.setDomainTransactionRecords(
|
||||
// Don't write a domain transaction record if the domain is deleted before billing
|
||||
// time (i.e. within the autorenew grace period). We cannot rely on a negating
|
||||
// DomainHistory created by DomainDeleteFlow because it only cancels transaction
|
||||
// records already present. In this case the domain was deleted before this
|
||||
// pipeline runs to expand the OneTime (which should be rare because this pipeline
|
||||
// should run every day), and no negating transaction records would have been
|
||||
// created when the deletion occurred. Again, there is no need to project the
|
||||
// domain, because if it were deleted before this transaction, its updated delete
|
||||
// time would have already been loaded here.
|
||||
//
|
||||
// We don't compare recurrence end time with billing time because the recurrence
|
||||
// could be caused for other reasons during the grace period, like a manual
|
||||
// renewal, in which case we still want to write the transaction record. Also,
|
||||
// the expansion happens when event time is in scope, which means the billing time
|
||||
// is still 45 days in the future, and the recurrence could have been closed
|
||||
// between now and then.
|
||||
//
|
||||
// A side effect of this logic is that if a transfer occurs within the ARGP, it
|
||||
// would have recorded both a TRANSFER_SUCCESSFUL and a NET_RENEWS_1_YEAR, even
|
||||
// though the transfer would have subsumed the autorenew. There is no perfect
|
||||
// solution for this because even if we expand the recurrence when the billing
|
||||
// event is in scope (as was the case in the old action), we still cannot use
|
||||
// recurrence end time < billing time as an indicator for if a transfer had
|
||||
// occurred during ARGP (see last paragraph, renewals during ARGP also close the
|
||||
// recurrence),therefore we still cannot always be correct when constructing the
|
||||
// transaction records that way (either we miss transfers, or we miss renewals
|
||||
// during ARGP).
|
||||
//
|
||||
// See: DomainFlowUtils#createCancellingRecords
|
||||
domain.getDeletionTime().isBefore(billingTime)
|
||||
? ImmutableSet.of()
|
||||
: ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
tld.getTldStr(),
|
||||
// We report this when the autorenew grace period ends.
|
||||
billingTime,
|
||||
TransactionReportField.netRenewsFieldFromYears(1),
|
||||
1)))
|
||||
.build();
|
||||
results.add(historyEntry);
|
||||
|
||||
// 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();
|
||||
results.add(oneTime);
|
||||
}
|
||||
results.add(
|
||||
recurring.asBuilder().setRecurrenceLastExpansion(recurrenceLastExpansionTime).build());
|
||||
}
|
||||
|
||||
private PDone advanceCursor(PCollection<Void> persisted) {
|
||||
return PDone.in(
|
||||
persisted
|
||||
.getPipeline()
|
||||
.apply("Create one dummy element", Create.of((Void) null))
|
||||
.apply("Wait for all saves to finish", Wait.on(persisted))
|
||||
// Because only one dummy element is created in the start PCollection, this
|
||||
// transform is guaranteed to only process one element and therefore only run once.
|
||||
// Because the previous step waits for all emissions of voids from the expansion step to
|
||||
// finish, this transform is guaranteed to run only after all expansions are done and
|
||||
// persisted.
|
||||
.apply(
|
||||
"Advance cursor",
|
||||
ParDo.of(
|
||||
new DoFn<Void, Void>() {
|
||||
@ProcessElement
|
||||
public void processElement() {
|
||||
tm().transact(
|
||||
() -> {
|
||||
DateTime currentCursorTime =
|
||||
tm().loadByKeyIfPresent(
|
||||
Cursor.createGlobalVKey(RECURRING_BILLING))
|
||||
.orElse(
|
||||
Cursor.createGlobal(RECURRING_BILLING, START_OF_TIME))
|
||||
.getCursorTime();
|
||||
if (!currentCursorTime.equals(startTime)) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"Current cursor position %s does not match start time"
|
||||
+ " %s.",
|
||||
currentCursorTime, startTime));
|
||||
}
|
||||
tm().put(Cursor.createGlobal(RECURRING_BILLING, endTime));
|
||||
});
|
||||
}
|
||||
}))
|
||||
.getPipeline());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
PipelineOptionsFactory.register(ExpandRecurringBillingEventsPipelineOptions.class);
|
||||
ExpandRecurringBillingEventsPipelineOptions options =
|
||||
PipelineOptionsFactory.fromArgs(args)
|
||||
.withValidation()
|
||||
.as(ExpandRecurringBillingEventsPipelineOptions.class);
|
||||
// Hardcode the transaction level to be at serializable we do not want concurrent runs of the
|
||||
// pipeline for the same window to create duplicate OneTimes. This ensures that the set of
|
||||
// existing OneTimes do not change by the time new OneTimes are inserted within a transaction.
|
||||
//
|
||||
// Per PostgreSQL, serializable isolation level does not introduce any blocking beyond that
|
||||
// present in repeatable read other than some overhead related to monitoring possible
|
||||
// serializable anomalies. Therefore, in most cases, since each worker of the same job works on
|
||||
// a different set of recurrings, it is not possible for their execution order to affect
|
||||
// serialization outcome, and the performance penalty should be minimum when using serializable
|
||||
// compared to using repeatable read.
|
||||
//
|
||||
// We should pay some attention to the runtime of the job and logs when we run this job daily on
|
||||
// production to check the actual performance impact for using this isolation level (i.e. check
|
||||
// the frequency of occurrence of retried transactions due to serialization errors) to assess
|
||||
// the actual parallelism of the job.
|
||||
//
|
||||
// See: https://www.postgresql.org/docs/current/transaction-iso.html
|
||||
options.setIsolationOverride(TransactionIsolationLevel.TRANSACTION_SERIALIZABLE);
|
||||
Pipeline pipeline = Pipeline.create(options);
|
||||
new ExpandRecurringBillingEventsPipeline(options, new SystemClock()).run(pipeline);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Component(
|
||||
modules = {CustomLogicModule.class, CustomLogicFactoryModule.class, ConfigModule.class})
|
||||
interface PipelineComponent {
|
||||
|
||||
DomainPricingLogic domainPricingLogic();
|
||||
|
||||
@Config("jdbcBatchSize")
|
||||
int batchSize();
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
// Copyright 2022 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.beam.billing;
|
||||
|
||||
import google.registry.beam.common.RegistryPipelineOptions;
|
||||
import org.apache.beam.sdk.options.Default;
|
||||
import org.apache.beam.sdk.options.Description;
|
||||
|
||||
public interface ExpandRecurringBillingEventsPipelineOptions extends RegistryPipelineOptions {
|
||||
@Description(
|
||||
"The inclusive lower bound of on the range of event times that will be expanded, in ISO 8601"
|
||||
+ " format")
|
||||
String getStartTime();
|
||||
|
||||
void setStartTime(String startTime);
|
||||
|
||||
@Description(
|
||||
"The exclusive upper bound of on the range of event times that will be expanded, in ISO 8601"
|
||||
+ " format")
|
||||
String getEndTime();
|
||||
|
||||
void setEndTime(String endTime);
|
||||
|
||||
@Description("If true, the expanded billing events and history entries will not be saved.")
|
||||
@Default.Boolean(false)
|
||||
boolean getIsDryRun();
|
||||
|
||||
void setIsDryRun(boolean isDryRun);
|
||||
|
||||
@Description(
|
||||
"If true, set the RECURRING_BILLING global cursor to endTime after saving all expanded"
|
||||
+ " billing events and history entries.")
|
||||
@Default.Boolean(true)
|
||||
boolean getAdvanceCursor();
|
||||
|
||||
void setAdvanceCursor(boolean advanceCursor);
|
||||
}
|
||||
+3
-3
@@ -12,16 +12,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.invoicing;
|
||||
package google.registry.beam.billing;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static org.apache.beam.sdk.values.TypeDescriptors.strings;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.beam.billing.BillingEvent.InvoiceGroupingKey;
|
||||
import google.registry.beam.billing.BillingEvent.InvoiceGroupingKey.InvoiceGroupingKeyCoder;
|
||||
import google.registry.beam.common.RegistryJpaIO;
|
||||
import google.registry.beam.common.RegistryJpaIO.Read;
|
||||
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey;
|
||||
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey.InvoiceGroupingKeyCoder;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.invoicing;
|
||||
package google.registry.beam.billing;
|
||||
|
||||
import google.registry.beam.common.RegistryPipelineOptions;
|
||||
import org.apache.beam.sdk.options.Description;
|
||||
@@ -71,7 +71,7 @@ public final class RegistryJpaIO {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Read} connector based on the given {@code jpql} query string.
|
||||
* Returns a {@link Read} connector based on the given native or {@code jpql} query string.
|
||||
*
|
||||
* <p>User should take care to prevent sql-injection attacks.
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package google.registry.beam.common;
|
||||
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.model.annotations.DeleteAfterMigration;
|
||||
import google.registry.persistence.PersistenceModule.JpaTransactionManagerType;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import java.util.Objects;
|
||||
@@ -57,17 +56,6 @@ public interface RegistryPipelineOptions extends GcpOptions {
|
||||
|
||||
void setSqlWriteBatchSize(int sqlWriteBatchSize);
|
||||
|
||||
@DeleteAfterMigration
|
||||
@Description(
|
||||
"Whether to use self allocated primary IDs when building entities. This should only be used"
|
||||
+ " when the IDs are not significant and the resulting entities are not persisted back to"
|
||||
+ " the database. Use with caution as self allocated IDs are not unique across workers,"
|
||||
+ " and persisting entities with these IDs can be dangerous.")
|
||||
@Default.Boolean(false)
|
||||
boolean getUseSelfAllocatedId();
|
||||
|
||||
void setUseSelfAllocatedId(boolean useSelfAllocatedId);
|
||||
|
||||
static RegistryPipelineComponent toRegistryPipelineComponent(RegistryPipelineOptions options) {
|
||||
return DaggerRegistryPipelineComponent.builder()
|
||||
.isolationOverride(options.getIsolationOverride())
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.google.common.flogger.FluentLogger;
|
||||
import dagger.Lazy;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.config.SystemPropertySetter;
|
||||
import google.registry.model.IdService;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
import org.apache.beam.sdk.harness.JvmInitializer;
|
||||
@@ -63,15 +62,5 @@ public class RegistryPipelineWorkerInitializer implements JvmInitializer {
|
||||
}
|
||||
TransactionManagerFactory.setJpaTmOnBeamWorker(transactionManagerLazy::get);
|
||||
SystemPropertySetter.PRODUCTION_IMPL.setProperty(PROPERTY, "true");
|
||||
// Use self-allocated IDs if requested. Note that this inevitably results in duplicate IDs from
|
||||
// multiple workers, which can also collide with existing IDs in the database. So they cannot be
|
||||
// dependent upon for comparison or anything significant. The resulting entities can never be
|
||||
// persisted back into the database. This is a stop-gap measure that should only be used when
|
||||
// you need to create Buildables in Beam, but do not have control over how the IDs are
|
||||
// allocated, and you don't care about the generated IDs as long
|
||||
// as you can build the entities.
|
||||
if (registryOptions.getUseSelfAllocatedId()) {
|
||||
IdService.setForceUseSelfAllocatedId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Interface for query instances used by {@link RegistryJpaIO.Read}. */
|
||||
public interface RegistryQuery<T> extends Serializable {
|
||||
@@ -57,7 +59,14 @@ public interface RegistryQuery<T> extends Serializable {
|
||||
Query query =
|
||||
nativeQuery ? entityManager.createNativeQuery(sql) : entityManager.createQuery(sql);
|
||||
if (parameters != null) {
|
||||
parameters.forEach(query::setParameter);
|
||||
parameters.forEach(
|
||||
(key, value) -> {
|
||||
if (value instanceof DateTime) {
|
||||
query.setParameter(key, ((DateTime) value).toDate(), TemporalType.TIMESTAMP);
|
||||
} else {
|
||||
query.setParameter(key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
JpaTransactionManager.setQueryFetchSize(query, QUERY_FETCH_SIZE);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -170,7 +170,6 @@ import org.joda.time.DateTime;
|
||||
* @see <a href="https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates">Using
|
||||
* Flex Templates</a>
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
@Singleton
|
||||
public class RdePipeline implements Serializable {
|
||||
|
||||
@@ -688,13 +687,6 @@ public class RdePipeline implements Serializable {
|
||||
RdePipelineOptions options =
|
||||
PipelineOptionsFactory.fromArgs(args).withValidation().as(RdePipelineOptions.class);
|
||||
|
||||
// We need to self allocate the IDs because the pipeline creates EPP resources from history
|
||||
// entries and projects them to watermark. These buildable entities would otherwise request an
|
||||
// ID from datastore, which Beam does not have access to. The IDs are not included in the
|
||||
// deposits or are these entities persisted back to the database, so it is OK to use a self
|
||||
// allocated ID to get around the limitations of beam.
|
||||
options.setUseSelfAllocatedId(true);
|
||||
|
||||
RegistryPipelineOptions.validateRegistryPipelineOptions(options);
|
||||
options.setIsolationOverride(TransactionIsolationLevel.TRANSACTION_READ_COMMITTED);
|
||||
DaggerRdePipeline_RdePipelineComponent.builder().options(options).build().rdePipeline().run();
|
||||
|
||||
@@ -575,9 +575,9 @@ public final class RegistryConfig {
|
||||
/**
|
||||
* Returns the default job region to run Apache Beam (Cloud Dataflow) jobs in.
|
||||
*
|
||||
* @see google.registry.beam.invoicing.InvoicingPipeline
|
||||
* @see google.registry.beam.billing.InvoicingPipeline
|
||||
* @see google.registry.beam.spec11.Spec11Pipeline
|
||||
* @see google.registry.beam.invoicing.InvoicingPipeline
|
||||
* @see google.registry.beam.billing.InvoicingPipeline
|
||||
*/
|
||||
@Provides
|
||||
@Config("defaultJobRegion")
|
||||
@@ -655,7 +655,7 @@ public final class RegistryConfig {
|
||||
/**
|
||||
* Returns the URL of the GCS bucket we store invoices and detail reports in.
|
||||
*
|
||||
* @see google.registry.beam.invoicing.InvoicingPipeline
|
||||
* @see google.registry.beam.billing.InvoicingPipeline
|
||||
*/
|
||||
@Provides
|
||||
@Config("billingBucketUrl")
|
||||
@@ -691,7 +691,7 @@ public final class RegistryConfig {
|
||||
/**
|
||||
* Returns the file prefix for the invoice CSV file.
|
||||
*
|
||||
* @see google.registry.beam.invoicing.InvoicingPipeline
|
||||
* @see google.registry.beam.billing.InvoicingPipeline
|
||||
* @see google.registry.reporting.billing.BillingEmailUtils
|
||||
*/
|
||||
@Provides
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
<datastore-indexes autoGenerate="false">
|
||||
<!-- For finding contact resources by registrar. -->
|
||||
<datastore-index kind="Contact" ancestor="false" source="manual">
|
||||
<property name="currentSponsorClientId" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
<property name="searchName" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For finding domain resources by registrar. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="currentSponsorClientId" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For finding domain resources by TLD. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="tld" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For finding domain resources by registrar. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="currentSponsorClientId" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For finding the most recently created domain resources. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="tld" direction="asc"/>
|
||||
<property name="creationTime" direction="desc"/>
|
||||
</datastore-index>
|
||||
<!-- For finding host resources by registrar. -->
|
||||
<datastore-index kind="Host" ancestor="false" source="manual">
|
||||
<property name="currentSponsorClientId" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
<property name="fullyQualifiedHostName" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For determining the active domains linked to a given contact. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="allContacts.contact" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For determining the active domains linked to a given host. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="nsHosts" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For deleting expired not-previously-deleted domains. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
<property name="autorenewEndTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For RDAP searches by linked nameserver. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="nsHosts" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For WHOIS IP address lookup -->
|
||||
<datastore-index kind="Host" ancestor="false" source="manual">
|
||||
<property name="inetAddresses" direction="asc"/>
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For Poll -->
|
||||
<datastore-index kind="PollMessage" ancestor="false" source="manual">
|
||||
<property name="clientId" direction="asc"/>
|
||||
<property name="eventTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<datastore-index kind="PollMessage" ancestor="true" source="manual">
|
||||
<property name="clientId" direction="asc"/>
|
||||
<property name="eventTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For querying HistoryEntries. -->
|
||||
<datastore-index kind="HistoryEntry" ancestor="true" source="manual">
|
||||
<property name="modificationTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<datastore-index kind="HistoryEntry" ancestor="false" source="manual">
|
||||
<property name="clientId" direction="asc"/>
|
||||
<property name="modificationTime" direction="asc"/>
|
||||
</datastore-index>
|
||||
<!-- For RDAP. -->
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="currentSponsorClientId" direction="asc"/>
|
||||
<property name="fullyQualifiedDomainName" direction="asc"/>
|
||||
</datastore-index>
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="currentSponsorClientId" direction="asc"/>
|
||||
<property name="tld" direction="asc"/>
|
||||
<property name="fullyQualifiedDomainName" direction="asc"/>
|
||||
</datastore-index>
|
||||
<datastore-index kind="Domain" ancestor="false" source="manual">
|
||||
<property name="tld" direction="asc"/>
|
||||
<property name="fullyQualifiedDomainName" direction="asc"/>
|
||||
</datastore-index>
|
||||
<datastore-index kind="Host" ancestor="false" source="manual">
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
<property name="fullyQualifiedHostName" direction="asc"/>
|
||||
</datastore-index>
|
||||
<datastore-index kind="Contact" ancestor="false" source="manual">
|
||||
<property name="deletionTime" direction="asc"/>
|
||||
<property name="searchName" direction="asc"/>
|
||||
</datastore-index>
|
||||
</datastore-indexes>
|
||||
@@ -258,7 +258,7 @@
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateInvoices?shouldPublish=true&runInEmpty]]></url>
|
||||
<description>
|
||||
Starts the beam/invoicing/InvoicingPipeline Dataflow template, which creates the overall invoice and
|
||||
Starts the beam/billing/InvoicingPipeline Dataflow template, which creates the overall invoice and
|
||||
detail report CSVs for last month, storing them in gs://[PROJECT-ID]-billing/invoices/yyyy-MM.
|
||||
Upon success, sends an e-mail copy of the invoice to billing personnel, and copies detail
|
||||
reports to the associated registrars' drive folders.
|
||||
|
||||
@@ -1131,7 +1131,7 @@ public class DomainFlowUtils {
|
||||
* hasn't been reported yet and b) matches the predicate 3. Return the transactionRecords under
|
||||
* the most recent HistoryEntry that fits the above criteria, with negated reportAmounts.
|
||||
*/
|
||||
static ImmutableSet<DomainTransactionRecord> createCancelingRecords(
|
||||
public static ImmutableSet<DomainTransactionRecord> createCancelingRecords(
|
||||
Domain domain,
|
||||
final DateTime now,
|
||||
Duration maxSearchPeriod,
|
||||
|
||||
@@ -14,62 +14,25 @@
|
||||
//
|
||||
package google.registry.model;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.appengine.api.datastore.DatastoreServiceFactory;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.beam.common.RegistryPipelineWorkerInitializer;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import java.math.BigInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Supplier;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Allocates a {@link long} to use as a {@code @Id}, (part) of the primary SQL key for an entity.
|
||||
* Allocates a {@code long} to use as a {@code @Id}, (part) of the primary SQL key for an entity.
|
||||
*/
|
||||
public final class IdService {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private IdService() {}
|
||||
|
||||
// TODO(ptkach): remove once the Cloud SQL sequence-based method is live in production
|
||||
private static boolean forceUseSelfAllocateId = false;
|
||||
|
||||
public static void setForceUseSelfAllocatedId() {
|
||||
checkState(
|
||||
"true".equals(System.getProperty(RegistryPipelineWorkerInitializer.PROPERTY, "false")),
|
||||
"Can only set ID supplier in a Beam pipeline");
|
||||
logger.atWarning().log("Using ID supplier override!");
|
||||
IdService.forceUseSelfAllocateId = true;
|
||||
}
|
||||
|
||||
private static class SelfAllocatedIdSupplier implements Supplier<Long> {
|
||||
|
||||
private static final SelfAllocatedIdSupplier INSTANCE = new SelfAllocatedIdSupplier();
|
||||
|
||||
/** Counts of used ids for self allocating IDs. */
|
||||
private static final AtomicLong nextSelfAllocatedId = new AtomicLong(1); // ids cannot be zero
|
||||
|
||||
private static SelfAllocatedIdSupplier getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long get() {
|
||||
return nextSelfAllocatedId.getAndIncrement();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A SQL Sequence based ID allocator that generates an ID from a monotonically increasing atomic
|
||||
* {@link long}
|
||||
* A SQL Sequence based ID allocator that generates an ID from a monotonically increasing {@link
|
||||
* AtomicLong}
|
||||
*
|
||||
* <p>The generated IDs are project-wide unique
|
||||
* <p>The generated IDs are project-wide unique.
|
||||
*/
|
||||
private static Long getSequenceBasedId() {
|
||||
public static long allocateId() {
|
||||
return tm().transact(
|
||||
() ->
|
||||
(BigInteger)
|
||||
@@ -78,32 +41,4 @@ public final class IdService {
|
||||
.getSingleResult())
|
||||
.longValue();
|
||||
}
|
||||
|
||||
// TODO(ptkach): Remove once all instances switch to sequenceBasedId
|
||||
/**
|
||||
* A Datastore based ID allocator that generates an ID from a monotonically increasing atomic
|
||||
* {@link long}
|
||||
*
|
||||
* <p>The generated IDs are project-wide unique
|
||||
*/
|
||||
private static Long getDatastoreBasedId() {
|
||||
return DatastoreServiceFactory.getDatastoreService()
|
||||
.allocateIds("common", 1)
|
||||
.iterator()
|
||||
.next()
|
||||
.getId();
|
||||
}
|
||||
|
||||
private IdService() {}
|
||||
|
||||
public static long allocateId() {
|
||||
if (DatabaseMigrationStateSchedule.getValueAtTime(DateTime.now(UTC))
|
||||
.equals(MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
|
||||
|| RegistryEnvironment.UNITTEST.equals(RegistryEnvironment.get())) {
|
||||
return getSequenceBasedId();
|
||||
} else if (IdService.forceUseSelfAllocateId) {
|
||||
return SelfAllocatedIdSupplier.getInstance().get();
|
||||
}
|
||||
return getDatastoreBasedId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,6 +469,7 @@ public abstract class BillingEvent extends ImmutableObject
|
||||
@Index(columnList = "eventTime"),
|
||||
@Index(columnList = "domainRepoId"),
|
||||
@Index(columnList = "recurrenceEndTime"),
|
||||
@Index(columnList = "recurrenceLastExpansion"),
|
||||
@Index(columnList = "recurrence_time_of_year")
|
||||
})
|
||||
@AttributeOverride(name = "id", column = @Column(name = "billing_recurrence_id"))
|
||||
@@ -481,6 +482,16 @@ public abstract class BillingEvent extends ImmutableObject
|
||||
*/
|
||||
DateTime recurrenceEndTime;
|
||||
|
||||
/**
|
||||
* The most recent {@link DateTime} when this recurrence was expanded.
|
||||
*
|
||||
* <p>We only bother checking recurrences for potential expansion if this is at least one year
|
||||
* in the past. If it's more recent than that, it means that the recurrence was already expanded
|
||||
* too recently to need to be checked again (as domains autorenew each year).
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
DateTime recurrenceLastExpansion;
|
||||
|
||||
/**
|
||||
* The eventTime recurs every year on this [month, day, time] between {@link #eventTime} and
|
||||
* {@link #recurrenceEndTime}, inclusive of the start but not of the end.
|
||||
@@ -519,6 +530,10 @@ public abstract class BillingEvent extends ImmutableObject
|
||||
return recurrenceEndTime;
|
||||
}
|
||||
|
||||
public DateTime getRecurrenceLastExpansion() {
|
||||
return recurrenceLastExpansion;
|
||||
}
|
||||
|
||||
public TimeOfYear getRecurrenceTimeOfYear() {
|
||||
return recurrenceTimeOfYear;
|
||||
}
|
||||
@@ -559,6 +574,11 @@ public abstract class BillingEvent extends ImmutableObject
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRecurrenceLastExpansion(DateTime recurrenceLastExpansion) {
|
||||
getInstance().recurrenceLastExpansion = recurrenceLastExpansion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRenewalPriceBehavior(RenewalPriceBehavior renewalPriceBehavior) {
|
||||
getInstance().renewalPriceBehavior = renewalPriceBehavior;
|
||||
return this;
|
||||
@@ -574,6 +594,12 @@ public abstract class BillingEvent extends ImmutableObject
|
||||
Recurring instance = getInstance();
|
||||
checkNotNull(instance.eventTime);
|
||||
checkNotNull(instance.reason);
|
||||
// Don't require recurrenceLastExpansion to be individually set on every new Recurrence.
|
||||
// The correct default value if not otherwise set is the event time of the recurrence minus
|
||||
// 1 year.
|
||||
instance.recurrenceLastExpansion =
|
||||
Optional.ofNullable(instance.recurrenceLastExpansion)
|
||||
.orElse(instance.eventTime.minusYears(1));
|
||||
checkArgument(
|
||||
instance.renewalPriceBehavior == RenewalPriceBehavior.SPECIFIED
|
||||
^ instance.renewalPrice == null,
|
||||
|
||||
+1
-1
@@ -602,7 +602,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
DateTime transactionTime;
|
||||
|
||||
// The set of entity objects that have been either persisted (via insert()) or merged (via
|
||||
// put()/update()). If the entity manager returns these as a result of a find() or query
|
||||
// put()/update()). If the entity manager returns these as a result of a find() or query
|
||||
// operation, we can not detach them -- detaching removes them from the transaction and causes
|
||||
// them to not be saved to the database -- so we throw an exception instead.
|
||||
Set<Object> objectsToSave = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
|
||||
@@ -52,7 +52,7 @@ import org.joda.time.YearMonth;
|
||||
* Invokes the {@code InvoicingPipeline} beam template via the REST api, and enqueues the {@link
|
||||
* PublishInvoicesAction} to publish the subsequent output.
|
||||
*
|
||||
* <p>This action runs the {@link google.registry.beam.invoicing.InvoicingPipeline} beam flex
|
||||
* <p>This action runs the {@link google.registry.beam.billing.InvoicingPipeline} beam flex
|
||||
* template. The pipeline then generates invoices for the month and stores them on GCS.
|
||||
*/
|
||||
@Action(
|
||||
|
||||
@@ -39,7 +39,7 @@ import javax.inject.Inject;
|
||||
import org.joda.time.YearMonth;
|
||||
|
||||
/**
|
||||
* Uploads the results of the {@link google.registry.beam.invoicing.InvoicingPipeline}.
|
||||
* Uploads the results of the {@link google.registry.beam.billing.InvoicingPipeline}.
|
||||
*
|
||||
* <p>This relies on the retry semantics in {@code queue.xml} to ensure proper upload, in spite of
|
||||
* fluctuations in generation timing.
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "Expand Recurring Billings Events for Implicit Auto-Renewals",
|
||||
"description": "An Apache Beam batch pipeline that finds all auto-renewals that have implicitly occurred between the given window and creates the corresponding billing events and hisotry entries.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "registryEnvironment",
|
||||
"label": "The Registry environment.",
|
||||
"helpText": "The Registry environment.",
|
||||
"is_optional": false,
|
||||
"regexes": [
|
||||
"^PRODUCTION|SANDBOX|CRASH|QA|ALPHA$"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "startTime",
|
||||
"label": "The inclusive lower bound of the operation window.",
|
||||
"helpText": "The inclusive lower bound of the operation window, in ISO 8601 format.",
|
||||
"is_optional": false
|
||||
},
|
||||
{
|
||||
"name": "endTime",
|
||||
"label": "The exclusive upper bound of the operation window.",
|
||||
"helpText": "The exclusive upper bound of the operation window, in ISO 8601 format.",
|
||||
"is_optional": false
|
||||
},
|
||||
{
|
||||
"name": "shard",
|
||||
"label": "The exclusive upper bound of the operation window.",
|
||||
"helpText": "The exclusive upper bound of the operation window, in ISO 8601 format.",
|
||||
"is_optional": true
|
||||
},
|
||||
{
|
||||
"name": "isDryRun",
|
||||
"label": "Whether this job is a dry run.",
|
||||
"helpText": "If true, no changes will be saved to the database.",
|
||||
"is_optional": true,
|
||||
"regexes": [
|
||||
"^true|false$"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "advanceCursor",
|
||||
"label": "Whether the BILLING_TIME global cursor should be advanced.",
|
||||
"helpText": "If true, after all expansions are persisted, the cursor will be changed from startTime to endTime.",
|
||||
"is_optional": true,
|
||||
"regexes": [
|
||||
"^true|false$"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -24,7 +24,8 @@ import static google.registry.testing.TestLogHandlerUtils.assertLogMessage;
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import google.registry.model.contact.Contact;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
@@ -47,8 +48,8 @@ import org.mockito.quality.Strictness;
|
||||
public class AsyncTaskEnqueuerTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
private final CapturingLogHandler logHandler = new CapturingLogHandler();
|
||||
|
||||
@@ -33,7 +33,8 @@ import google.registry.model.contact.Contact;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenType;
|
||||
import google.registry.model.domain.token.PackagePromotion;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
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.ui.server.SendEmailUtils;
|
||||
@@ -67,8 +68,8 @@ public class CheckPackagesComplianceActionTest {
|
||||
private static final String SUPPORT_EMAIL = "registry@test.com";
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withClock(clock).build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
private CheckPackagesComplianceAction action;
|
||||
private AllocationToken token;
|
||||
|
||||
@@ -36,12 +36,14 @@ import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.persistence.transaction.QueryComposer.Comparator;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeLockHandler;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -54,8 +56,10 @@ class DeleteExpiredDomainsActionTest {
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2016-06-13T20:21:22Z"));
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private DeleteExpiredDomainsAction action;
|
||||
|
||||
@@ -44,10 +44,12 @@ import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.Registry.TldType;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
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.SystemPropertyExtension;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.money.Money;
|
||||
@@ -63,8 +65,10 @@ class DeleteProberDataActionTest {
|
||||
private static final DateTime DELETION_TIME = DateTime.parse("2010-01-01T00:00:00.000Z");
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withLocalModules().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
@RegisterExtension
|
||||
final SystemPropertyExtension systemPropertyExtension = new SystemPropertyExtension();
|
||||
|
||||
+4
-3
@@ -51,7 +51,8 @@ import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
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.FakeResponse;
|
||||
@@ -68,8 +69,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public class ExpandRecurringBillingEventsActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withLocalModules().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private DateTime currentTestTime = DateTime.parse("1999-01-05T00:00:00Z");
|
||||
private final FakeClock clock = new FakeClock(currentTestTime);
|
||||
|
||||
@@ -38,14 +38,14 @@ import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.RegistryLock;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.UserInfo;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.SendEmailService;
|
||||
@@ -72,7 +72,7 @@ public class RelockDomainActionTest {
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2015-05-18T12:34:56Z"));
|
||||
private CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
|
||||
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
|
||||
private final DomainLockUtils domainLockUtils =
|
||||
new DomainLockUtils(
|
||||
new DeterministicStringGenerator(Alphabets.BASE_58),
|
||||
@@ -80,12 +80,8 @@ public class RelockDomainActionTest {
|
||||
cloudTasksHelper.getTestCloudTasksUtils());
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngineExtension =
|
||||
AppEngineExtension.builder()
|
||||
.withCloudSql()
|
||||
.withTaskQueue()
|
||||
.withUserService(UserInfo.create(POC_ID))
|
||||
.build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private Domain domain;
|
||||
private RegistryLock oldLock;
|
||||
|
||||
@@ -26,17 +26,12 @@ import com.google.api.services.dataflow.model.LaunchFlexTemplateRequest;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.beam.BeamActionTestBase;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link ResaveAllEppResourcesPipelineAction}. */
|
||||
public class ResaveAllEppResourcesPipelineActionTest extends BeamActionTestBase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
private ResaveAllEppResourcesPipelineAction createAction(boolean isFast) {
|
||||
|
||||
@@ -34,8 +34,9 @@ import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
@@ -55,8 +56,8 @@ import org.mockito.quality.Strictness;
|
||||
public class ResaveEntityActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Mock private Response response;
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2016-02-11T10:00:00Z"));
|
||||
|
||||
+5
-4
@@ -15,7 +15,7 @@
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.AppEngineExtension.makeRegistrar1;
|
||||
import static google.registry.persistence.transaction.JpaTransactionManagerExtension.makeRegistrar1;
|
||||
import static google.registry.testing.DatabaseHelper.loadByEntity;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DatabaseHelper.persistSimpleResources;
|
||||
@@ -36,7 +36,8 @@ import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.model.registrar.RegistrarPoc.Type;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.util.SelfSignedCaCertificate;
|
||||
@@ -70,8 +71,8 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||
private static final String EXPIRATION_WARNING_EMAIL_SUBJECT_TEXT = "Expiration Warning Email";
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2021-05-24T20:21:22Z"));
|
||||
private final SendEmailService sendEmailService = mock(SendEmailService.class);
|
||||
|
||||
@@ -34,7 +34,8 @@ import google.registry.model.contact.PostalInfo;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.PresenceMarker;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
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.FakeResponse;
|
||||
@@ -98,8 +99,8 @@ class WipeOutContactHistoryPiiActionTest {
|
||||
.build();
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2021-08-26T20:21:22Z"));
|
||||
|
||||
|
||||
+3
-3
@@ -12,12 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.invoicing;
|
||||
package google.registry.beam.billing;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey;
|
||||
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey.InvoiceGroupingKeyCoder;
|
||||
import google.registry.beam.billing.BillingEvent.InvoiceGroupingKey;
|
||||
import google.registry.beam.billing.BillingEvent.InvoiceGroupingKey.InvoiceGroupingKeyCoder;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
+549
@@ -0,0 +1,549 @@
|
||||
// Copyright 2022 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.beam.billing;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.ImmutableObjectSubject.immutableObjectCorrespondence;
|
||||
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
||||
import static google.registry.model.domain.Period.Unit.YEARS;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
|
||||
import static google.registry.model.reporting.HistoryEntryDao.loadHistoryObjectsForResource;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.assertBillingEventsForResource;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.beam.TestPipelineExtension;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.common.Cursor;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import org.apache.beam.runners.direct.DirectOptions;
|
||||
import org.apache.beam.sdk.Pipeline.PipelineExecutionException;
|
||||
import org.apache.beam.sdk.options.PipelineOptionsFactory;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
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;
|
||||
|
||||
/** Unit tests for {@link ExpandRecurringBillingEventsPipeline}. */
|
||||
public class ExpandRecurringBillingEventsPipelineTest {
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER =
|
||||
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2021-02-02T00:00:05Z"));
|
||||
|
||||
private final DateTime startTime = DateTime.parse("2021-02-01TZ");
|
||||
|
||||
private DateTime endTime = DateTime.parse("2021-02-02TZ");
|
||||
|
||||
private final Cursor cursor = Cursor.createGlobal(RECURRING_BILLING, startTime);
|
||||
|
||||
private Domain domain;
|
||||
|
||||
private Recurring recurring;
|
||||
|
||||
private final TestOptions options = PipelineOptionsFactory.create().as(TestOptions.class);
|
||||
|
||||
@RegisterExtension
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder()
|
||||
.withClock(clock)
|
||||
.withProperty(
|
||||
AvailableSettings.ISOLATION,
|
||||
TransactionIsolationLevel.TRANSACTION_SERIALIZABLE.name())
|
||||
.buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension
|
||||
final TestPipelineExtension pipeline =
|
||||
TestPipelineExtension.create().enableAbandonedNodeEnforcement(true);
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
// Set up the pipeline.
|
||||
options.setStartTime(DATE_TIME_FORMATTER.print(startTime));
|
||||
options.setEndTime(DATE_TIME_FORMATTER.print(endTime));
|
||||
options.setIsDryRun(false);
|
||||
options.setAdvanceCursor(true);
|
||||
tm().transact(() -> tm().put(cursor));
|
||||
|
||||
// Set up the database.
|
||||
createTld("tld");
|
||||
recurring = createDomainAtTime("example.tld", startTime.minusYears(1).plusHours(12));
|
||||
domain = loadByForeignKey(Domain.class, "example.tld", clock.nowUtc()).get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_endTimeAfterNow() {
|
||||
options.setEndTime(DATE_TIME_FORMATTER.print(clock.nowUtc().plusMillis(1)));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(IllegalArgumentException.class, this::runPipeline);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.contains("End time 2021-02-02T00:00:05.001Z must be on or before now");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_endTimeBeforeStartTime() {
|
||||
options.setEndTime(DATE_TIME_FORMATTER.print(startTime.minusMillis(1)));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(IllegalArgumentException.class, this::runPipeline);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.contains("[2021-02-01T00:00:00.000Z, 2021-01-31T23:59:59.999Z)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_expandSingleEvent() {
|
||||
runPipeline();
|
||||
|
||||
// Assert about DomainHistory.
|
||||
assertAutoRenewDomainHistories(defaultDomainHistory());
|
||||
|
||||
// Assert about BillingEvents.
|
||||
assertBillingEventsForResource(
|
||||
domain,
|
||||
defaultOneTime(getOnlyAutoRenewHistory()),
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
|
||||
// Assert about Cursor.
|
||||
assertCursorAt(endTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_expandSingleEvent_deletedDuringGracePeriod() {
|
||||
domain = persistResource(domain.asBuilder().setDeletionTime(endTime.minusHours(2)).build());
|
||||
recurring =
|
||||
persistResource(recurring.asBuilder().setRecurrenceEndTime(endTime.minusHours(2)).build());
|
||||
runPipeline();
|
||||
|
||||
// Assert about DomainHistory, no transaction record should have been written.
|
||||
assertAutoRenewDomainHistories(
|
||||
defaultDomainHistory().asBuilder().setDomainTransactionRecords(ImmutableSet.of()).build());
|
||||
|
||||
// Assert about BillingEvents.
|
||||
assertBillingEventsForResource(
|
||||
domain,
|
||||
defaultOneTime(getOnlyAutoRenewHistory()),
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
|
||||
// Assert about Cursor.
|
||||
assertCursorAt(endTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_expandSingleEvent_cursorNotAtStartTime() {
|
||||
tm().transact(() -> tm().put(Cursor.createGlobal(RECURRING_BILLING, startTime.plusMillis(1))));
|
||||
|
||||
PipelineExecutionException thrown =
|
||||
assertThrows(PipelineExecutionException.class, this::runPipeline);
|
||||
|
||||
assertThat(thrown).hasCauseThat().hasMessageThat().contains("Current cursor position");
|
||||
|
||||
// Assert about DomainHistory.
|
||||
assertAutoRenewDomainHistories(defaultDomainHistory());
|
||||
|
||||
// Assert about BillingEvents.
|
||||
assertBillingEventsForResource(
|
||||
domain,
|
||||
defaultOneTime(getOnlyAutoRenewHistory()),
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
|
||||
// Assert that the cursor did not change.
|
||||
assertCursorAt(startTime.plusMillis(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noExpansion_recurrenceClosedBeforeEventTime() {
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceEndTime(recurring.getEventTime().minusDays(1))
|
||||
.build());
|
||||
runPipeline();
|
||||
assertNoExpansionsHappened();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noExpansion_recurrenceClosedBeforeStartTime() {
|
||||
recurring =
|
||||
persistResource(recurring.asBuilder().setRecurrenceEndTime(startTime.minusDays(1)).build());
|
||||
runPipeline();
|
||||
assertNoExpansionsHappened();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noExpansion_recurrenceClosedBeforeNextExpansion() {
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setEventTime(recurring.getEventTime().minusYears(1))
|
||||
.setRecurrenceEndTime(startTime.plusHours(6))
|
||||
.build());
|
||||
runPipeline();
|
||||
assertNoExpansionsHappened();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noExpansion_eventTimeAfterEndTime() {
|
||||
recurring = persistResource(recurring.asBuilder().setEventTime(endTime.plusDays(1)).build());
|
||||
runPipeline();
|
||||
assertNoExpansionsHappened();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noExpansion_LastExpansionLessThanAYearAgo() {
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(startTime.minusYears(1).plusDays(1))
|
||||
.build());
|
||||
runPipeline();
|
||||
assertNoExpansionsHappened();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noExpansion_oneTimeAlreadyExists() {
|
||||
DomainHistory history = persistResource(defaultDomainHistory());
|
||||
OneTime oneTime = persistResource(defaultOneTime(history));
|
||||
runPipeline();
|
||||
|
||||
// Assert about DomainHistory.
|
||||
assertAutoRenewDomainHistories(history);
|
||||
|
||||
// Assert about BillingEvents. No expansion happened, so last recurrence expansion time is
|
||||
// unchanged.
|
||||
assertBillingEventsForResource(domain, oneTime, recurring);
|
||||
|
||||
// Assert about Cursor.
|
||||
assertCursorAt(endTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_expandSingleEvent_dryRun() {
|
||||
options.setIsDryRun(true);
|
||||
runPipeline();
|
||||
assertNoExpansionsHappened(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_expandSingleEvent_doesNotAdvanceCursor() {
|
||||
options.setAdvanceCursor(false);
|
||||
|
||||
runPipeline();
|
||||
// Assert about DomainHistory.
|
||||
assertAutoRenewDomainHistories(defaultDomainHistory());
|
||||
|
||||
// Assert about BillingEvents.
|
||||
assertBillingEventsForResource(
|
||||
domain,
|
||||
defaultOneTime(getOnlyAutoRenewHistory()),
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
|
||||
// Assert that the cursor did not move.
|
||||
assertCursorAt(startTime);
|
||||
}
|
||||
|
||||
// We control the number of threads used in the pipeline to test if the batching behavior works
|
||||
// properly. When two threads are used, the two recurrings are processed in different workers and
|
||||
// should be processed in parallel.
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {1, 2})
|
||||
void testSuccess_expandMultipleEvents_multipleDomains(int numOfThreads) {
|
||||
createTld("test");
|
||||
persistResource(
|
||||
Registry.get("test")
|
||||
.asBuilder()
|
||||
.setPremiumList(persistPremiumList("premium", USD, "other,USD 100"))
|
||||
.build());
|
||||
DateTime otherCreateTime = startTime.minusYears(1).plusHours(5);
|
||||
Recurring otherRecurring = createDomainAtTime("other.test", otherCreateTime);
|
||||
Domain otherDomain = loadByForeignKey(Domain.class, "other.test", clock.nowUtc()).get();
|
||||
|
||||
options.setTargetParallelism(numOfThreads);
|
||||
runPipeline();
|
||||
|
||||
// Assert about DomainHistory.
|
||||
DomainHistory history = defaultDomainHistory();
|
||||
DomainHistory otherHistory = defaultDomainHistory(otherDomain);
|
||||
assertAutoRenewDomainHistories(domain, history);
|
||||
assertAutoRenewDomainHistories(otherDomain, otherHistory);
|
||||
|
||||
// Assert about BillingEvents.
|
||||
assertBillingEventsForResource(
|
||||
domain,
|
||||
defaultOneTime(getOnlyAutoRenewHistory()),
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
assertBillingEventsForResource(
|
||||
otherDomain,
|
||||
defaultOneTime(otherDomain, getOnlyAutoRenewHistory(otherDomain), otherRecurring, 100),
|
||||
otherRecurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(otherDomain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
|
||||
// Assert about Cursor.
|
||||
assertCursorAt(endTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_expandMultipleEvents_multipleEventTime() {
|
||||
clock.advanceBy(Duration.standardDays(365));
|
||||
endTime = endTime.plusYears(1);
|
||||
options.setEndTime(DATE_TIME_FORMATTER.print(endTime));
|
||||
|
||||
runPipeline();
|
||||
// Assert about DomainHistory.
|
||||
assertAutoRenewDomainHistories(
|
||||
defaultDomainHistory(),
|
||||
defaultDomainHistory()
|
||||
.asBuilder()
|
||||
.setDomainTransactionRecords(
|
||||
ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
domain.getTld(),
|
||||
// We report this when the autorenew grace period ends.
|
||||
domain
|
||||
.getCreationTime()
|
||||
.plusYears(2)
|
||||
.plus(Registry.DEFAULT_AUTO_RENEW_GRACE_PERIOD),
|
||||
TransactionReportField.netRenewsFieldFromYears(1),
|
||||
1)))
|
||||
.build());
|
||||
|
||||
// Assert about BillingEvents.
|
||||
ImmutableList<DomainHistory> histories =
|
||||
loadHistoryObjectsForResource(domain.createVKey(), DomainHistory.class).stream()
|
||||
.filter(domainHistory -> DOMAIN_AUTORENEW.equals(domainHistory.getType()))
|
||||
.sorted(
|
||||
Comparator.comparing(
|
||||
h ->
|
||||
h.getDomainTransactionRecords().stream()
|
||||
.findFirst()
|
||||
.get()
|
||||
.getReportingTime()))
|
||||
.collect(toImmutableList());
|
||||
assertBillingEventsForResource(
|
||||
domain,
|
||||
defaultOneTime(histories.get(0)),
|
||||
defaultOneTime(histories.get(1))
|
||||
.asBuilder()
|
||||
.setEventTime(domain.getCreationTime().plusYears(2))
|
||||
.setBillingTime(
|
||||
domain
|
||||
.getCreationTime()
|
||||
.plusYears(2)
|
||||
.plus(Registry.DEFAULT_AUTO_RENEW_GRACE_PERIOD))
|
||||
.build(),
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceLastExpansion(domain.getCreationTime().plusYears(2))
|
||||
.build());
|
||||
|
||||
// Assert about Cursor.
|
||||
assertCursorAt(endTime);
|
||||
}
|
||||
|
||||
private void runPipeline() {
|
||||
ExpandRecurringBillingEventsPipeline expandRecurringBillingEventsPipeline =
|
||||
new ExpandRecurringBillingEventsPipeline(options, clock);
|
||||
expandRecurringBillingEventsPipeline.setupPipeline(pipeline);
|
||||
pipeline.run(options).waitUntilFinish();
|
||||
}
|
||||
|
||||
void assertNoExpansionsHappened() {
|
||||
assertNoExpansionsHappened(false);
|
||||
}
|
||||
|
||||
void assertNoExpansionsHappened(boolean dryRun) {
|
||||
// Only the original domain create history entry is present.
|
||||
List<DomainHistory> persistedHistory =
|
||||
loadHistoryObjectsForResource(domain.createVKey(), DomainHistory.class);
|
||||
assertThat(persistedHistory.size()).isEqualTo(1);
|
||||
assertThat(persistedHistory.get(0).getType()).isEqualTo(DOMAIN_CREATE);
|
||||
|
||||
// Only the original recurrence is present.
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
|
||||
// If this is not a dry run, the cursor should still be moved even though expansions happened,
|
||||
// because we still successfully processed all the needed expansions (none in this case) in the
|
||||
// window. Therefore,
|
||||
// the cursor should be up-to-date as of end time.
|
||||
assertCursorAt(dryRun ? startTime : endTime);
|
||||
}
|
||||
|
||||
private DomainHistory defaultDomainHistory() {
|
||||
return defaultDomainHistory(domain);
|
||||
}
|
||||
|
||||
private DomainHistory defaultDomainHistory(Domain domain) {
|
||||
return new DomainHistory.Builder()
|
||||
.setBySuperuser(false)
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setModificationTime(clock.nowUtc())
|
||||
.setDomain(domain)
|
||||
.setPeriod(Period.create(1, YEARS))
|
||||
.setReason("Domain autorenewal by ExpandRecurringBillingEventsPipeline")
|
||||
.setRequestedByRegistrar(false)
|
||||
.setType(DOMAIN_AUTORENEW)
|
||||
.setDomainTransactionRecords(
|
||||
ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
domain.getTld(),
|
||||
// We report this when the autorenew grace period ends.
|
||||
domain
|
||||
.getCreationTime()
|
||||
.plusYears(1)
|
||||
.plus(Registry.DEFAULT_AUTO_RENEW_GRACE_PERIOD),
|
||||
TransactionReportField.netRenewsFieldFromYears(1),
|
||||
1)))
|
||||
.build();
|
||||
}
|
||||
|
||||
private OneTime defaultOneTime(DomainHistory history) {
|
||||
return defaultOneTime(domain, history, recurring, 11);
|
||||
}
|
||||
|
||||
private OneTime defaultOneTime(
|
||||
Domain domain, DomainHistory history, Recurring recurring, int cost) {
|
||||
return new BillingEvent.OneTime.Builder()
|
||||
.setBillingTime(
|
||||
domain.getCreationTime().plusYears(1).plus(Registry.DEFAULT_AUTO_RENEW_GRACE_PERIOD))
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setCost(Money.of(USD, cost))
|
||||
.setEventTime(domain.getCreationTime().plusYears(1))
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
||||
.setPeriodYears(1)
|
||||
.setReason(Reason.RENEW)
|
||||
.setSyntheticCreationTime(endTime)
|
||||
.setCancellationMatchingBillingEvent(recurring)
|
||||
.setTargetId(domain.getDomainName())
|
||||
.setDomainHistory(history)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void assertAutoRenewDomainHistories(DomainHistory... expected) {
|
||||
assertAutoRenewDomainHistories(domain, expected);
|
||||
}
|
||||
|
||||
private static void assertAutoRenewDomainHistories(Domain domain, DomainHistory... expected) {
|
||||
ImmutableList<DomainHistory> actuals =
|
||||
loadHistoryObjectsForResource(domain.createVKey(), DomainHistory.class).stream()
|
||||
.filter(domainHistory -> DOMAIN_AUTORENEW.equals(domainHistory.getType()))
|
||||
.collect(toImmutableList());
|
||||
assertThat(actuals)
|
||||
.comparingElementsUsing(immutableObjectCorrespondence("resource", "revisionId"))
|
||||
.containsExactlyElementsIn(Arrays.asList(expected));
|
||||
assertThat(
|
||||
actuals.stream()
|
||||
.map(history -> history.getDomainBase().get())
|
||||
.collect(toImmutableList()))
|
||||
.comparingElementsUsing(immutableObjectCorrespondence("nsHosts", "updateTimestamp"))
|
||||
.containsExactlyElementsIn(
|
||||
Arrays.stream(expected)
|
||||
.map(history -> history.getDomainBase().get())
|
||||
.collect(toImmutableList()));
|
||||
}
|
||||
|
||||
private static DomainHistory getOnlyAutoRenewHistory(Domain domain) {
|
||||
return getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
}
|
||||
|
||||
private DomainHistory getOnlyAutoRenewHistory() {
|
||||
return getOnlyAutoRenewHistory(domain);
|
||||
}
|
||||
|
||||
private static void assertCursorAt(DateTime expectedCursorTime) {
|
||||
Cursor cursor = tm().transact(() -> tm().loadByKey(Cursor.createGlobalVKey(RECURRING_BILLING)));
|
||||
assertThat(cursor).isNotNull();
|
||||
assertThat(cursor.getCursorTime()).isEqualTo(expectedCursorTime);
|
||||
}
|
||||
|
||||
private static Recurring createDomainAtTime(String domainName, DateTime createTime) {
|
||||
Domain domain = persistActiveDomain(domainName, createTime);
|
||||
DomainHistory domainHistory =
|
||||
persistResource(
|
||||
new DomainHistory.Builder()
|
||||
.setRegistrarId(domain.getCreationRegistrarId())
|
||||
.setType(DOMAIN_CREATE)
|
||||
.setModificationTime(createTime)
|
||||
.setDomain(domain)
|
||||
.build());
|
||||
return persistResource(
|
||||
new Recurring.Builder()
|
||||
.setDomainHistory(domainHistory)
|
||||
.setRegistrarId(domain.getCreationRegistrarId())
|
||||
.setEventTime(createTime.plusYears(1))
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setTargetId(domain.getDomainName())
|
||||
.build());
|
||||
}
|
||||
|
||||
public interface TestOptions extends ExpandRecurringBillingEventsPipelineOptions, DirectOptions {}
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.invoicing;
|
||||
package google.registry.beam.billing;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
package google.registry.beam.common;
|
||||
|
||||
import static google.registry.testing.AppEngineExtension.makeRegistrar1;
|
||||
import static google.registry.persistence.transaction.JpaTransactionManagerExtension.makeRegistrar1;
|
||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||
import static google.registry.testing.DatabaseHelper.newContact;
|
||||
import static google.registry.testing.DatabaseHelper.newRegistry;
|
||||
@@ -42,7 +42,6 @@ import google.registry.model.transfer.ContactTransferData;
|
||||
import google.registry.persistence.transaction.CriteriaQueryBuilder;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.apache.beam.sdk.coders.StringUtf8Coder;
|
||||
import org.apache.beam.sdk.testing.PAssert;
|
||||
@@ -60,7 +59,7 @@ public class RegistryJpaReadTest {
|
||||
private final FakeClock fakeClock = new FakeClock(START_TIME);
|
||||
|
||||
@RegisterExtension
|
||||
final transient JpaIntegrationTestExtension database =
|
||||
final transient JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder()
|
||||
.withClock(fakeClock)
|
||||
.withoutCannedData()
|
||||
@@ -74,7 +73,7 @@ public class RegistryJpaReadTest {
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
Registrar ofyRegistrar = AppEngineExtension.makeRegistrar2();
|
||||
Registrar ofyRegistrar = JpaIntegrationTestExtension.makeRegistrar2();
|
||||
insertInDb(ofyRegistrar);
|
||||
|
||||
ImmutableList.Builder<Contact> builder = new ImmutableList.Builder<>();
|
||||
|
||||
@@ -27,7 +27,7 @@ import google.registry.beam.TestPipelineExtension;
|
||||
import google.registry.model.contact.Contact;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.io.Serializable;
|
||||
import org.apache.beam.sdk.Pipeline.PipelineExecutionException;
|
||||
@@ -43,7 +43,7 @@ class RegistryJpaWriteTest implements Serializable {
|
||||
private final FakeClock fakeClock = new FakeClock(DateTime.parse("2000-01-01T00:00:00.0Z"));
|
||||
|
||||
@RegisterExtension
|
||||
final transient JpaIntegrationTestExtension database =
|
||||
final transient JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(fakeClock).buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension
|
||||
@@ -52,7 +52,7 @@ class RegistryJpaWriteTest implements Serializable {
|
||||
|
||||
@Test
|
||||
void writeToSql_twoWriters() {
|
||||
tm().transact(() -> tm().put(AppEngineExtension.makeRegistrar2()));
|
||||
tm().transact(() -> tm().put(JpaTransactionManagerExtension.makeRegistrar2()));
|
||||
ImmutableList.Builder<Contact> contactsBuilder = new ImmutableList.Builder<>();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
contactsBuilder.add(newContact("contact_" + i));
|
||||
@@ -76,7 +76,7 @@ class RegistryJpaWriteTest implements Serializable {
|
||||
// causing a race condition
|
||||
tm().transact(
|
||||
() -> {
|
||||
tm().put(AppEngineExtension.makeRegistrar2());
|
||||
tm().put(JpaTransactionManagerExtension.makeRegistrar2());
|
||||
tm().put(newContact("contact"));
|
||||
});
|
||||
Contact contact = Iterables.getOnlyElement(loadAllOf(Contact.class));
|
||||
|
||||
@@ -22,13 +22,13 @@ import static google.registry.beam.rde.RdePipeline.encodePendingDeposits;
|
||||
import static google.registry.model.common.Cursor.CursorType.RDE_STAGING;
|
||||
import static google.registry.model.rde.RdeMode.FULL;
|
||||
import static google.registry.model.rde.RdeMode.THIN;
|
||||
import static google.registry.persistence.transaction.JpaTransactionManagerExtension.makeRegistrar1;
|
||||
import static google.registry.persistence.transaction.JpaTransactionManagerExtension.makeRegistrar2;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.rde.RdeResourceType.CONTACT;
|
||||
import static google.registry.rde.RdeResourceType.DOMAIN;
|
||||
import static google.registry.rde.RdeResourceType.HOST;
|
||||
import static google.registry.rde.RdeResourceType.REGISTRAR;
|
||||
import static google.registry.testing.AppEngineExtension.makeRegistrar1;
|
||||
import static google.registry.testing.AppEngineExtension.makeRegistrar2;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.insertSimpleResources;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveContact;
|
||||
|
||||
+7
-1
@@ -36,12 +36,14 @@ import google.registry.model.contact.Contact;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.apache.beam.sdk.options.PipelineOptionsFactory;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -60,7 +62,11 @@ public class ResaveAllEppResourcesPipelineTest {
|
||||
|
||||
@RegisterExtension
|
||||
final JpaIntegrationTestExtension database =
|
||||
new JpaTestExtensions.Builder().withClock(fakeClock).buildIntegrationTestExtension();
|
||||
new JpaTestExtensions.Builder()
|
||||
.withClock(fakeClock)
|
||||
.withProperty(
|
||||
Environment.ISOLATION, TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ.name())
|
||||
.buildIntegrationTestExtension();
|
||||
|
||||
private final ResaveAllEppResourcesPipelineOptions options =
|
||||
PipelineOptionsFactory.create().as(ResaveAllEppResourcesPipelineOptions.class);
|
||||
|
||||
@@ -17,8 +17,8 @@ package google.registry.beam.spec11;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.immutableObjectCorrespondence;
|
||||
import static google.registry.persistence.transaction.JpaTransactionManagerExtension.makeRegistrar1;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.AppEngineExtension.makeRegistrar1;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
|
||||
|
||||
@@ -27,7 +27,8 @@ import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.Registry.TldType;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
@@ -48,7 +49,8 @@ class TldFanoutActionTest {
|
||||
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(new FakeClock());
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private static ImmutableListMultimap<String, String> getParamsMap(String... keysAndValues) {
|
||||
ImmutableListMultimap.Builder<String, String> params = new ImmutableListMultimap.Builder<>();
|
||||
|
||||
@@ -24,11 +24,13 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
import google.registry.request.RequestModule;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.CloudTasksHelper.CloudTasksHelperModule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -42,8 +44,10 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public final class DnsInjectionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private final HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
|
||||
|
||||
@@ -20,8 +20,10 @@ import static google.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -32,8 +34,10 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public class DnsQueueTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private DnsQueue dnsQueue;
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2010-01-01T10:00:00Z"));
|
||||
|
||||
@@ -48,9 +48,10 @@ import google.registry.dns.DnsMetrics.PublishStatus;
|
||||
import google.registry.dns.writer.DnsWriter;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.HttpException.ServiceUnavailableException;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
@@ -73,8 +74,8 @@ import org.mockito.ArgumentCaptor;
|
||||
public class PublishDnsUpdatesActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("1971-01-01TZ"));
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.google.appengine.api.taskqueue.QueueFactory;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.cloud.tasks.v2.Task;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
@@ -42,10 +41,12 @@ import com.google.common.net.InternetDomainName;
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.Registry.TldType;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import google.registry.testing.TaskQueueHelper;
|
||||
import google.registry.testing.UriParameters;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -70,21 +71,10 @@ public class ReadDnsQueueActionTest {
|
||||
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder()
|
||||
.withCloudSql()
|
||||
.withTaskQueue(
|
||||
Joiner.on('\n')
|
||||
.join(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
|
||||
"<queue-entries>",
|
||||
" <queue>",
|
||||
" <name>dns-pull</name>",
|
||||
" <mode>pull</mode>",
|
||||
" </queue>",
|
||||
"</queue-entries>"))
|
||||
.withClock(clock)
|
||||
.build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
@@ -26,9 +26,10 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import google.registry.dns.DnsConstants.TargetType;
|
||||
import google.registry.model.domain.Domain;
|
||||
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.AppEngineExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -38,8 +39,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public class RefreshDnsActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final DnsQueue dnsQueue = mock(DnsQueue.class);
|
||||
private final FakeClock clock = new FakeClock();
|
||||
|
||||
@@ -43,7 +43,8 @@ import google.registry.model.domain.secdns.DomainDsData;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.SystemClock;
|
||||
@@ -70,7 +71,8 @@ import org.mockito.quality.Strictness;
|
||||
public class CloudDnsWriterTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private static final Inet4Address IPv4 = (Inet4Address) InetAddresses.forString("127.0.0.1");
|
||||
private static final Inet6Address IPv6 = (Inet6Address) InetAddresses.forString("::1");
|
||||
|
||||
@@ -39,7 +39,8 @@ import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.secdns.DomainDsData;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.ArrayList;
|
||||
@@ -72,8 +73,8 @@ import org.xbill.DNS.Update;
|
||||
public class DnsUpdateWriterTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
public final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Mock private DnsMessageTransport mockResolver;
|
||||
@Captor private ArgumentCaptor<Update> updateCaptor;
|
||||
|
||||
@@ -35,8 +35,9 @@ import com.google.common.net.MediaType;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.Registry.TldType;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.storage.drive.DriveConnection;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -54,8 +55,8 @@ class ExportDomainListsActionTest {
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2020-02-02T02:02:02Z"));
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withLocalModules().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
@@ -39,9 +39,10 @@ import com.google.common.net.MediaType;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.label.PremiumList;
|
||||
import google.registry.model.tld.label.PremiumListDao;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.storage.drive.DriveConnection;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -58,7 +59,8 @@ public class ExportPremiumTermsActionTest {
|
||||
DISCLAIMER_WITH_NEWLINE + "0, 549.00\n" + "2048, 549.00\n";
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final DriveConnection driveConnection = mock(DriveConnection.class);
|
||||
private final Response response = mock(Response.class);
|
||||
|
||||
@@ -34,9 +34,10 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.storage.drive.DriveConnection;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -46,7 +47,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public class ExportReservedTermsActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
JpaIntegrationTestExtension jpa = new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final DriveConnection driveConnection = mock(DriveConnection.class);
|
||||
private final Response response = mock(Response.class);
|
||||
|
||||
@@ -21,7 +21,8 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -29,7 +30,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
class ExportUtilsTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Test
|
||||
void test_exportReservedTerms() {
|
||||
|
||||
@@ -38,8 +38,9 @@ import google.registry.groups.DirectoryGroupsConnection;
|
||||
import google.registry.groups.GroupsConnection.Role;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.util.Retrier;
|
||||
@@ -51,12 +52,13 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
* Unit tests for {@link SyncGroupMembersAction}.
|
||||
*
|
||||
* <p>Note that this relies on the registrars NewRegistrar and TheRegistrar created by default in
|
||||
* {@link AppEngineExtension}.
|
||||
* {@link JpaIntegrationTestExtension}.
|
||||
*/
|
||||
public class SyncGroupMembersActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final DirectoryGroupsConnection connection = mock(DirectoryGroupsConnection.class);
|
||||
private final Response response = mock(Response.class);
|
||||
|
||||
@@ -23,7 +23,6 @@ import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.FakeLockHandler;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import java.util.Optional;
|
||||
@@ -31,15 +30,10 @@ import javax.annotation.Nullable;
|
||||
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 SyncRegistrarsSheetAction}. */
|
||||
public class SyncRegistrarsSheetActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final SyncRegistrarsSheet syncRegistrarsSheet = mock(SyncRegistrarsSheet.class);
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ import google.registry.model.common.Cursor;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -56,7 +57,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
public class SyncRegistrarsSheetTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Captor private ArgumentCaptor<ImmutableList<ImmutableMap<String, String>>> rowsCaptor;
|
||||
@Mock private SheetSynchronizer sheetSynchronizer;
|
||||
@@ -73,9 +75,8 @@ public class SyncRegistrarsSheetTest {
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
createTld("example");
|
||||
// Remove Registrar entities created by AppEngineExtension (and RegistrarContact's, for jpa).
|
||||
tm().transact(() -> tm().loadAllOf(RegistrarPoc.class))
|
||||
.forEach(DatabaseHelper::deleteResource);
|
||||
// Remove Registrar entities created by JpaTransactionManagerExtension.
|
||||
tm().transact(() -> tm().loadAllOf(RegistrarPoc.class)).forEach(DatabaseHelper::deleteResource);
|
||||
Registrar.loadAll().forEach(DatabaseHelper::deleteResource);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ import google.registry.monitoring.whitebox.CheckApiMetric;
|
||||
import google.registry.monitoring.whitebox.CheckApiMetric.Availability;
|
||||
import google.registry.monitoring.whitebox.CheckApiMetric.Status;
|
||||
import google.registry.monitoring.whitebox.CheckApiMetric.Tier;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import java.util.Map;
|
||||
@@ -55,7 +56,8 @@ class CheckApiActionTest {
|
||||
private static final DateTime START_TIME = DateTime.parse("2000-01-01T00:00:00.0Z");
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Mock private CheckApiMetrics checkApiMetrics;
|
||||
@Captor private ArgumentCaptor<CheckApiMetric> metricCaptor;
|
||||
|
||||
@@ -40,7 +40,8 @@ import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.eppoutput.Result;
|
||||
import google.registry.model.eppoutput.Result.Code;
|
||||
import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.xml.ValidationMode;
|
||||
@@ -67,7 +68,8 @@ import org.mockito.quality.Strictness;
|
||||
class EppControllerTest {
|
||||
|
||||
@RegisterExtension
|
||||
AppEngineExtension appEngineExtension = new AppEngineExtension.Builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Mock SessionMetadata sessionMetadata;
|
||||
@Mock TransportCredentials transportCredentials;
|
||||
|
||||
@@ -20,7 +20,8 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_NO_MESSAG
|
||||
import static google.registry.testing.EppMetricSubject.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -28,8 +29,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
class EppLifecycleContactTest extends EppTestCase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@Test
|
||||
void testContactLifecycle() throws Exception {
|
||||
|
||||
@@ -46,7 +46,9 @@ import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.reporting.HistoryEntry.Type;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.Registry.TldState;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -63,8 +65,10 @@ class EppLifecycleDomainTest extends EppTestCase {
|
||||
"EXDATE", "2003-06-01T00:04:00Z");
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
@@ -25,7 +25,9 @@ import static google.registry.testing.HostSubject.assertAboutHosts;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
@@ -34,8 +36,10 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
class EppLifecycleHostTest extends EppTestCase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
@Test
|
||||
void testLifecycle() throws Exception {
|
||||
|
||||
@@ -18,7 +18,8 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS_AND_CLOSE;
|
||||
import static google.registry.testing.EppMetricSubject.assertThat;
|
||||
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -26,8 +27,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
class EppLifecycleLoginTest extends EppTestCase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Test
|
||||
void testLoginAndLogout_recordsEppMetric() throws Exception {
|
||||
|
||||
@@ -18,17 +18,12 @@ import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Test flows without login. */
|
||||
class EppLoggedOutTest extends EppTestCase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
|
||||
@Test
|
||||
void testHello() throws Exception {
|
||||
DateTime now = DateTime.now(UTC);
|
||||
|
||||
@@ -24,7 +24,8 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.CertificateSamples;
|
||||
import google.registry.testing.SystemPropertyExtension;
|
||||
import google.registry.util.SelfSignedCaCertificate;
|
||||
@@ -44,7 +45,8 @@ import org.testcontainers.shaded.org.bouncycastle.util.io.pem.PemWriter;
|
||||
class EppLoginTlsTest extends EppTestCase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension
|
||||
@Order(value = Integer.MAX_VALUE)
|
||||
|
||||
@@ -31,10 +31,12 @@ import com.google.common.collect.Iterables;
|
||||
import google.registry.flows.EppTestComponent.FakesAndMocksModule;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.EppLoader;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
import google.registry.testing.TaskQueueExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -46,8 +48,10 @@ class EppPointInTimeTest {
|
||||
private final FakeClock clock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private EppLoader eppLoader;
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
package google.registry.flows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -23,7 +24,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
class EppXxeAttackTest extends EppTestCase {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Test
|
||||
void testRemoteXmlExternalEntity() throws Exception {
|
||||
|
||||
@@ -34,19 +34,14 @@ import google.registry.model.domain.superuser.DomainTransferRequestSuperuserExte
|
||||
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
import google.registry.util.TypeUtils;
|
||||
import java.util.logging.LogRecord;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link ExtensionManager}. */
|
||||
class ExtensionManagerTest {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
|
||||
@Test
|
||||
void testDuplicateExtensionsForbidden() {
|
||||
ExtensionManager manager =
|
||||
@@ -245,7 +240,8 @@ class ExtensionManagerTest {
|
||||
@Override
|
||||
public ImmutableList<CommandExtension> getExtensions() {
|
||||
return suppliedExtensions;
|
||||
}};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.eppoutput.EppOutput.ResponseOrGreeting;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
@@ -51,8 +52,8 @@ import org.mockito.Mockito;
|
||||
class FlowRunnerTest {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngineExtension =
|
||||
new AppEngineExtension.Builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final FlowRunner flowRunner = new FlowRunner();
|
||||
private final EppMetric.Builder eppMetricBuilder = EppMetric.builderForRequest(new FakeClock());
|
||||
|
||||
@@ -41,7 +41,8 @@ import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.reporting.HistoryEntryDao;
|
||||
import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
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.EppLoader;
|
||||
@@ -87,8 +88,8 @@ public abstract class FlowTestCase<F extends Flow> {
|
||||
private EppMetric.Builder eppMetricBuilder;
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withClock(clock).withCloudSql().withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEachFlowTestCase() {
|
||||
|
||||
@@ -31,7 +31,8 @@ import google.registry.flows.TlsCredentials.MissingRegistrarCertificateException
|
||||
import google.registry.flows.TlsCredentials.RegistrarCertificateNotConfiguredException;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import google.registry.util.ProxyHttpHeaders;
|
||||
@@ -45,9 +46,10 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
final class TlsCredentialsTest {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
protected final FakeClock clock = new FakeClock();
|
||||
private final FakeClock clock = new FakeClock();
|
||||
|
||||
private final CertificateChecker certificateChecker =
|
||||
new CertificateChecker(
|
||||
|
||||
@@ -25,7 +25,7 @@ import google.registry.model.EppResource;
|
||||
import google.registry.model.contact.Contact;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -59,7 +59,10 @@ abstract class ContactTransferFlowTestCase<F extends Flow, R extends EppResource
|
||||
// Registrar ClientZ is used in tests that need another registrar that definitely doesn't own
|
||||
// the resources in question.
|
||||
persistResource(
|
||||
AppEngineExtension.makeRegistrar1().asBuilder().setRegistrarId("ClientZ").build());
|
||||
JpaTransactionManagerExtension.makeRegistrar1()
|
||||
.asBuilder()
|
||||
.setRegistrarId("ClientZ")
|
||||
.build());
|
||||
}
|
||||
|
||||
/** Adds a contact that has a pending transfer on it from TheRegistrar to NewRegistrar. */
|
||||
|
||||
@@ -178,6 +178,7 @@ import google.registry.model.tld.Registry.TldType;
|
||||
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 java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
@@ -188,10 +189,13 @@ 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 DomainCreateFlow}. */
|
||||
class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain> {
|
||||
|
||||
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
|
||||
|
||||
private static final String CLAIMS_KEY = "2013041500/2/6/9/rJ1NrDO92vDsAzf7EQzgjX4R0000000001";
|
||||
|
||||
private AllocationToken allocationToken;
|
||||
|
||||
@@ -101,16 +101,20 @@ 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;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.TrailingDashException;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.tld.Registry.TldType;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -51,7 +51,7 @@ class DomainFlowUtilsTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
|
||||
void setup() {
|
||||
setEppInput("domain_info.xml");
|
||||
createTld("tld");
|
||||
persistResource(AppEngineExtension.makeRegistrar1().asBuilder().build());
|
||||
persistResource(JpaTransactionManagerExtension.makeRegistrar1().asBuilder().build());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -74,7 +74,7 @@ import google.registry.model.host.Host;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -115,7 +115,10 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
|
||||
sessionMetadata.setRegistrarId("NewRegistrar");
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
AppEngineExtension.makeRegistrar1().asBuilder().setRegistrarId("ClientZ").build());
|
||||
JpaTransactionManagerExtension.makeRegistrar1()
|
||||
.asBuilder()
|
||||
.setRegistrarId("ClientZ")
|
||||
.build());
|
||||
}
|
||||
|
||||
private void persistTestEntities(String domainName, boolean inactive) {
|
||||
|
||||
@@ -46,7 +46,8 @@ import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
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.FakeHttpSession;
|
||||
@@ -65,7 +66,8 @@ public class DomainPricingLogicTest {
|
||||
DomainPricingLogic domainPricingLogic;
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Inject Clock clock = new FakeClock(DateTime.now(UTC));
|
||||
@Mock EppInput eppInput;
|
||||
|
||||
@@ -75,16 +75,20 @@ 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 =
|
||||
|
||||
@@ -302,6 +302,8 @@ class DomainTransferApproveFlowTest
|
||||
getGainingClientAutorenewEvent()
|
||||
.asBuilder()
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setRecurrenceLastExpansion(
|
||||
domain.getRegistrationExpirationTime().minusYears(1))
|
||||
.setDomainHistory(historyEntryTransferApproved)
|
||||
.build()))
|
||||
.toArray(BillingEvent[]::new));
|
||||
@@ -338,6 +340,8 @@ class DomainTransferApproveFlowTest
|
||||
getGainingClientAutorenewEvent()
|
||||
.asBuilder()
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setRecurrenceLastExpansion(
|
||||
domain.getRegistrationExpirationTime().minusYears(1))
|
||||
.setDomainHistory(historyEntryTransferApproved)
|
||||
.build()))
|
||||
.toArray(BillingEvent[]::new));
|
||||
@@ -835,7 +839,7 @@ class DomainTransferApproveFlowTest
|
||||
"tld",
|
||||
"domain_transfer_approve.xml",
|
||||
"domain_transfer_approve_response_zero_period.xml",
|
||||
domain.getRegistrationExpirationTime().plusYears(0));
|
||||
domain.getRegistrationExpirationTime());
|
||||
assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -86,7 +86,10 @@ abstract class DomainTransferFlowTestCase<F extends Flow, R extends EppResource>
|
||||
// Registrar ClientZ is used in tests that need another registrar that definitely doesn't own
|
||||
// the resources in question.
|
||||
persistResource(
|
||||
AppEngineExtension.makeRegistrar1().asBuilder().setRegistrarId("ClientZ").build());
|
||||
JpaTransactionManagerExtension.makeRegistrar1()
|
||||
.asBuilder()
|
||||
.setRegistrarId("ClientZ")
|
||||
.build());
|
||||
}
|
||||
|
||||
static Domain persistWithPendingTransfer(Domain domain) {
|
||||
|
||||
@@ -296,7 +296,11 @@ class DomainTransferRequestFlowTest
|
||||
.setRecurrenceEndTime(implicitTransferTime)
|
||||
.build();
|
||||
BillingEvent.Recurring gainingClientAutorenew =
|
||||
getGainingClientAutorenewEvent().asBuilder().setEventTime(expectedExpirationTime).build();
|
||||
getGainingClientAutorenewEvent()
|
||||
.asBuilder()
|
||||
.setEventTime(expectedExpirationTime)
|
||||
.setRecurrenceLastExpansion(expectedExpirationTime.minusYears(1))
|
||||
.build();
|
||||
// Construct extra billing events expected by the specific test.
|
||||
ImmutableSet<BillingEvent> extraBillingEvents =
|
||||
Stream.of(extraExpectedBillingEvents)
|
||||
|
||||
@@ -106,15 +106,19 @@ 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,
|
||||
|
||||
+4
-2
@@ -49,7 +49,8 @@ import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -64,7 +65,8 @@ class AllocationTokenFlowUtilsTest {
|
||||
new AllocationTokenFlowUtils(new AllocationTokenCustomLogic());
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private final AllocationTokenExtension allocationTokenExtension =
|
||||
mock(AllocationTokenExtension.class);
|
||||
|
||||
@@ -54,12 +54,16 @@ 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",
|
||||
|
||||
@@ -48,13 +48,17 @@ 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"));
|
||||
|
||||
@@ -25,7 +25,8 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -33,7 +34,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
class HostFlowUtilsTest {
|
||||
|
||||
@RegisterExtension
|
||||
final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Test
|
||||
void test_validExternalHostName_validates() throws Exception {
|
||||
|
||||
@@ -81,13 +81,17 @@ 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(
|
||||
|
||||
@@ -16,9 +16,13 @@ package google.registry.model;
|
||||
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaEntityCoverageExtension;
|
||||
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.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Base class of all unit tests for entities which are persisted to SQL. */
|
||||
@@ -36,18 +40,29 @@ public abstract class EntityTestCase {
|
||||
|
||||
protected FakeClock fakeClock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
@RegisterExtension public final AppEngineExtension appEngine;
|
||||
@Order(Order.DEFAULT)
|
||||
@RegisterExtension
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(fakeClock).buildIntegrationTestExtension();
|
||||
|
||||
@Order(Order.DEFAULT + 1)
|
||||
@RegisterExtension
|
||||
final JpaEntityCoverageExtension coverage;
|
||||
|
||||
protected EntityTestCase() {
|
||||
this(JpaEntityCoverageCheck.DISABLED);
|
||||
}
|
||||
|
||||
protected EntityTestCase(JpaEntityCoverageCheck jpaEntityCoverageCheck) {
|
||||
appEngine =
|
||||
AppEngineExtension.builder()
|
||||
.withCloudSql()
|
||||
.enableJpaEntityCoverageCheck(jpaEntityCoverageCheck == JpaEntityCoverageCheck.ENABLED)
|
||||
.withClock(fakeClock)
|
||||
.build();
|
||||
coverage =
|
||||
jpaEntityCoverageCheck == JpaEntityCoverageCheck.ENABLED
|
||||
? new JpaEntityCoverageExtension()
|
||||
: new JpaEntityCoverageExtension() {
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) {}
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext context) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
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;
|
||||
@@ -37,8 +38,8 @@ class EppResourceUtilsTest {
|
||||
private final FakeClock clock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder().withCloudSql().withClock(clock).withTaskQueue().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
@@ -26,7 +26,8 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaUnitTestExtension;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayDeque;
|
||||
@@ -46,11 +47,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public class ImmutableObjectTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder()
|
||||
.withCloudSql()
|
||||
.withJpaUnitTestEntities(ValueObject.class)
|
||||
.build();
|
||||
final JpaUnitTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withEntityClass(ValueObject.class).buildUnitTestExtension();
|
||||
|
||||
/** Simple subclass of ImmutableObject. */
|
||||
public static class SimpleObject extends ImmutableObject {
|
||||
|
||||
@@ -17,19 +17,14 @@ package google.registry.model;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link ModelUtils}. */
|
||||
public class ModelUtilsTest {
|
||||
|
||||
@RegisterExtension
|
||||
public AppEngineExtension appEngineExtension = new AppEngineExtension.Builder().build();
|
||||
|
||||
/** Test class for reflection methods. */
|
||||
public static class TestClass extends ImmutableObject implements Buildable {
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.model.tld.Registry.TldState.GENERAL_AVAILABILITY;
|
||||
import static google.registry.model.tld.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.testing.AppEngineExtension.makeRegistrar1;
|
||||
import static google.registry.persistence.transaction.JpaTransactionManagerExtension.makeRegistrar1;
|
||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT;
|
||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT_HASH;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
@@ -33,7 +33,8 @@ import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.model.tld.Registry.TldState;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import google.registry.util.SystemClock;
|
||||
import org.joda.money.Money;
|
||||
@@ -47,7 +48,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public final class OteAccountBuilderTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@Test
|
||||
void testGetRegistrarToTldMap() {
|
||||
|
||||
@@ -18,7 +18,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
|
||||
import google.registry.model.OteStats.StatType;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
@@ -26,7 +27,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public final class OteStatsTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
@@ -28,18 +28,12 @@ import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.host.HostCommand;
|
||||
import google.registry.model.host.HostInfoData;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.EppLoader;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
public class StatusValueAdapterTest {
|
||||
|
||||
// Needed to create Hosts.
|
||||
@RegisterExtension
|
||||
public AppEngineExtension appEngine = new AppEngineExtension.Builder().withCloudSql().build();
|
||||
|
||||
@Test
|
||||
void testMarshalling() throws Exception {
|
||||
// Mangle the status value through marshalling by stuffing it in a host info response and then
|
||||
|
||||
@@ -774,6 +774,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(recurringEvent.getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
assertThat(recurringEvent.getRecurrenceLastExpansion()).isEqualTo(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -25,17 +25,12 @@ import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.contact.ContactCommand.Update;
|
||||
import google.registry.model.contact.ContactCommand.Update.Change;
|
||||
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.EppLoader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Test xml roundtripping of commands. */
|
||||
public class ContactCommandTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build();
|
||||
|
||||
private void doXmlRoundtripTest(String inputFilename) throws Exception {
|
||||
EppLoader eppLoader = new EppLoader(this, inputFilename);
|
||||
// JAXB can unmarshal a "name" or an "id" into the "targetId" field, but when marshaling it
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user