1
0
mirror of https://github.com/google/nomulus synced 2026-07-07 00:27:12 +00:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Pavlo Tkach c9ac9437fd Add java code for RegitrarPoc id (#2770) 2025-06-14 17:37:11 +00:00
gbrodman 1f6a09182d Add some changes related to RDAP Feb 2024 profile (#2759)
This implements two type of changes:
1. changing the link type for things like the terms of service
2. adding the request URL to each and every link with the "value" field.
   This is a bit tricky to implement because the links are generated in
various places, but we can implement it by adding it to the results
after generation.

See b/418782147 for more information
2025-06-11 20:30:15 +00:00
Weimin Yu a0eff00031 Add an aggregate module for DNS writers (#2769)
Add a new DnsWritersModule for use by the component classes.

To override the set of writers installed, we can easily overwrite this
file with a private version.
2025-06-09 14:46:54 +00:00
gbrodman 89698c6ed6 Update version of google-java-format (#2766)
This picks up a few changes including aligning the placement of quotes
in text blocks with the Google style guide.
2025-06-06 18:11:54 +00:00
gbrodman a7696c3fac Add console action test base case (#2762)
We can probably improve on this in the future if we want, but there's a
lot of boilerplate that we don't need to repeat over and over
2025-06-04 15:36:22 +00:00
Weimin Yu 7ec599f849 Fix create_cdns_tld command (#2760)
The Cloud DNS rest api is now case-sensitive about enum names (must be
lower case, counterintuitively).
2025-06-03 15:17:43 +00:00
Pavlo Tkach 70291af9ad Add RegistrarPoc id column (#2761) 2025-06-02 15:43:03 +00:00
gbrodman 5fb95f38ed Don't always require contacts in CreateDomainCommand (#2755)
If contacts are optional, they should be optional in the command too.
2025-05-15 20:22:07 +00:00
gbrodman dfe8e24761 Add registrar_id col to password reset requests (#2756)
This is just so that we can add an additional layer of security on
verification
2025-05-15 20:13:27 +00:00
Juan Celhay bd30fcc81c Remove registrar id from invoice grouping key (#2749)
* Remove registrar id from invoice grouping key

* Fix formatting issues

* Update BillingEventTests
2025-05-13 20:29:25 +00:00
gbrodman 8cecc8d3a8 Use the primary DB for DomainInfoFlow (#2750)
This avoids potential replication lag issues when requesting info on
domains that were just created.
2025-05-13 18:00:30 +00:00
Pavlo Tkach c5a39bccc5 Add Console POC reminder front-end (#2754) 2025-05-12 20:14:56 +00:00
gbrodman a90a117341 Add SQL table for password resets (#2751)
We plan on using this for EPP password resets and registry lock password
resets for now.
2025-05-08 19:16:08 +00:00
Weimin Yu b40ad54daf Hardcode beam pipelines to use GKE for tasks (#2753) 2025-05-08 17:29:30 +00:00
134 changed files with 4988 additions and 4195 deletions
+98 -10
View File
@@ -14,30 +14,71 @@
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
import { MaterialModule } from './material.module';
import { BackendService } from './shared/services/backend.service';
import { AppRoutingModule } from './app-routing.module';
import { routes } from './app-routing.module';
import { AppModule } from './app.module';
import { PocReminderComponent } from './shared/components/pocReminder/pocReminder.component';
import { RouterModule } from '@angular/router';
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
import { UserData, UserDataService } from './shared/services/userData.service';
import { Registrar, RegistrarService } from './registrar/registrar.service';
import { MatSidenavModule } from '@angular/material/sidenav';
import { signal, WritableSignal } from '@angular/core';
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let mockRegistrarService: {
registrar: WritableSignal<Partial<Registrar> | null | undefined>;
registrarId: WritableSignal<string>;
registrars: WritableSignal<Array<Partial<Registrar>>>;
};
let mockUserDataService: { userData: WritableSignal<Partial<UserData>> };
let mockSnackBar: jasmine.SpyObj<MatSnackBar>;
const dummyPocReminderComponent = class {}; // Dummy class for type checking
beforeEach(async () => {
mockRegistrarService = {
registrar: signal<Registrar | null | undefined>(undefined),
registrarId: signal('123'),
registrars: signal([]),
};
mockUserDataService = {
userData: signal({
globalRole: 'NONE',
}),
};
mockSnackBar = jasmine.createSpyObj('MatSnackBar', ['openFromComponent']);
await TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [
MaterialModule,
BrowserAnimationsModule,
AppRoutingModule,
MatSidenavModule,
NoopAnimationsModule,
MatSnackBarModule,
AppModule,
RouterModule.forRoot(routes),
],
providers: [
BackendService,
{ provide: RegistrarService, useValue: mockRegistrarService },
{ provide: UserDataService, useValue: mockUserDataService },
{ provide: MatSnackBar, useValue: mockSnackBar },
{ provide: PocReminderComponent, useClass: dummyPocReminderComponent },
provideHttpClient(),
provideHttpClientTesting(),
],
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('should create the app', () => {
@@ -46,4 +87,51 @@ describe('AppComponent', () => {
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
describe('PoC Verification Reminder', () => {
beforeEach(() => {
jasmine.clock().install();
});
it('should open snackbar if lastPocVerificationDate is older than one year', fakeAsync(() => {
const MOCK_TODAY = new Date('2024-07-15T10:00:00.000Z');
jasmine.clock().mockDate(MOCK_TODAY);
const twoYearsAgo = new Date(MOCK_TODAY);
twoYearsAgo.setFullYear(MOCK_TODAY.getFullYear() - 2);
mockRegistrarService.registrar.set({
lastPocVerificationDate: twoYearsAgo.toISOString(),
});
fixture.detectChanges();
TestBed.flushEffects();
expect(mockSnackBar.openFromComponent).toHaveBeenCalledWith(
PocReminderComponent,
{
horizontalPosition: 'center',
verticalPosition: 'top',
duration: 1000000000,
}
);
}));
it('should NOT open snackbar if lastPocVerificationDate is within last year', fakeAsync(() => {
const MOCK_TODAY = new Date('2024-07-15T10:00:00.000Z');
jasmine.clock().mockDate(MOCK_TODAY);
const sixMonthsAgo = new Date(MOCK_TODAY);
sixMonthsAgo.setMonth(MOCK_TODAY.getMonth() - 6);
mockRegistrarService.registrar.set({
lastPocVerificationDate: sixMonthsAgo.toISOString(),
});
fixture.detectChanges();
TestBed.flushEffects();
expect(mockSnackBar.openFromComponent).not.toHaveBeenCalled();
}));
});
});
+25 -3
View File
@@ -12,13 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { AfterViewInit, Component, effect, ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { NavigationEnd, Router } from '@angular/router';
import { RegistrarService } from './registrar/registrar.service';
import { BreakPointObserverService } from './shared/services/breakPoint.service';
import { GlobalLoaderService } from './shared/services/globalLoader.service';
import { UserDataService } from './shared/services/userData.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { PocReminderComponent } from './shared/components/pocReminder/pocReminder.component';
@Component({
selector: 'app-root',
@@ -35,8 +37,28 @@ export class AppComponent implements AfterViewInit {
protected userDataService: UserDataService,
protected globalLoader: GlobalLoaderService,
protected breakpointObserver: BreakPointObserverService,
private router: Router
) {}
private router: Router,
private _snackBar: MatSnackBar
) {
effect(() => {
const registrar = this.registrarService.registrar();
const oneYearAgo = new Date();
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
oneYearAgo.setHours(0, 0, 0, 0);
if (
registrar &&
registrar.lastPocVerificationDate &&
new Date(registrar.lastPocVerificationDate) < oneYearAgo &&
this.userDataService?.userData()?.globalRole === 'NONE'
) {
this._snackBar.openFromComponent(PocReminderComponent, {
horizontalPosition: 'center',
verticalPosition: 'top',
duration: 1000000000,
});
}
});
}
ngAfterViewInit() {
this.router.events.subscribe((event) => {
+2
View File
@@ -60,6 +60,7 @@ import { TldsComponent } from './tlds/tlds.component';
import { ForceFocusDirective } from './shared/directives/forceFocus.directive';
import RdapComponent from './settings/rdap/rdap.component';
import RdapEditComponent from './settings/rdap/rdapEdit.component';
import { PocReminderComponent } from './shared/components/pocReminder/pocReminder.component';
@NgModule({
declarations: [SelectedRegistrarWrapper],
@@ -86,6 +87,7 @@ export class SelectedRegistrarModule {}
RdapComponent,
RdapEditComponent,
ReasonDialogComponent,
PocReminderComponent,
RegistrarComponent,
RegistrarDetailsComponent,
RegistrarSelectorComponent,
@@ -57,7 +57,7 @@ export class NavigationComponent {
}
ngOnDestroy() {
this.subscription.unsubscribe();
this.subscription && this.subscription.unsubscribe();
}
getElementId(node: RouteWithIcon) {
@@ -71,6 +71,7 @@ export interface Registrar
registrarName: string;
registryLockAllowed?: boolean;
type?: string;
lastPocVerificationDate?: string;
}
@Injectable({
@@ -24,7 +24,7 @@ export type contactType =
| 'LEGAL'
| 'MARKETING'
| 'TECH'
| 'RDAP';
| 'WHOIS';
type contactTypesToUserFriendlyTypes = { [type in contactType]: string };
@@ -35,7 +35,7 @@ export const contactTypeToTextMap: contactTypesToUserFriendlyTypes = {
LEGAL: 'Legal contact',
MARKETING: 'Marketing contact',
TECH: 'Technical contact',
RDAP: 'RDAP-Inquiry contact',
WHOIS: 'RDAP-Inquiry contact',
};
type UserFriendlyType = (typeof contactTypeToTextMap)[contactType];
@@ -59,7 +59,10 @@ export interface ViewReadyContact extends Contact {
export function contactTypeToViewReadyContact(c: Contact): ViewReadyContact {
return {
...c,
userFriendlyTypes: c.types?.map((cType) => contactTypeToTextMap[cType]),
userFriendlyTypes: (c.types || []).map(
(cType) => contactTypeToTextMap[cType]
),
types: c.types || [],
};
}
@@ -98,19 +101,21 @@ export class ContactService {
);
}
saveContacts(contacts: ViewReadyContact[]): Observable<Contact[]> {
updateContact(contact: ViewReadyContact) {
return this.backend
.postContacts(this.registrarService.registrarId(), contacts)
.updateContact(this.registrarService.registrarId(), contact)
.pipe(switchMap((_) => this.fetchContacts()));
}
addContact(contact: ViewReadyContact) {
const newContacts = this.contacts().concat([contact]);
return this.saveContacts(newContacts);
return this.backend
.createContact(this.registrarService.registrarId(), contact)
.pipe(switchMap((_) => this.fetchContacts()));
}
deleteContact(contact: ViewReadyContact) {
const newContacts = this.contacts().filter((c) => c !== contact);
return this.saveContacts(newContacts);
return this.backend
.deleteContact(this.registrarService.registrarId(), contact)
.pipe(switchMap((_) => this.fetchContacts()));
}
}
@@ -69,9 +69,13 @@ export class ContactDetailsComponent {
save(e: SubmitEvent) {
e.preventDefault();
if ((this.contactService.contactInEdit.types || []).length === 0) {
this._snackBar.open('Required to select contact type');
return;
}
const request = this.contactService.isContactNewView
? this.contactService.addContact(this.contactService.contactInEdit)
: this.contactService.saveContacts(this.contactService.contacts());
: this.contactService.updateContact(this.contactService.contactInEdit);
request.subscribe({
complete: () => {
this.goBack();
@@ -0,0 +1,14 @@
<div class="console-app__pocReminder">
<p class="">
Please take a moment to complete annual review of
<a routerLink="/settings">contacts</a>.
</p>
<span matSnackBarActions>
<button mat-button matSnackBarAction (click)="confirmReviewed()">
Confirm reviewed
</button>
<button mat-button matSnackBarAction (click)="snackBarRef.dismiss()">
Close
</button>
</span>
</div>
@@ -0,0 +1,5 @@
.console-app__pocReminder {
a {
color: white !important;
}
}
@@ -0,0 +1,53 @@
// Copyright 2025 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.
import { Component } from '@angular/core';
import { MatSnackBar, MatSnackBarRef } from '@angular/material/snack-bar';
import { RegistrarService } from '../../../registrar/registrar.service';
import { HttpErrorResponse } from '@angular/common/http';
@Component({
selector: 'app-poc-reminder',
templateUrl: './pocReminder.component.html',
styleUrls: ['./pocReminder.component.scss'],
standalone: false,
})
export class PocReminderComponent {
constructor(
public snackBarRef: MatSnackBarRef<PocReminderComponent>,
private registrarService: RegistrarService,
private _snackBar: MatSnackBar
) {}
confirmReviewed() {
if (this.registrarService.registrar()) {
const todayMidnight = new Date();
todayMidnight.setHours(0, 0, 0, 0);
this.registrarService
// @ts-ignore - if check above won't allow empty object to be submitted
.updateRegistrar({
...this.registrarService.registrar(),
lastPocVerificationDate: todayMidnight.toISOString(),
})
.subscribe({
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error || err.message);
},
next: () => {
this.snackBarRef.dismiss();
},
});
}
}
}
@@ -70,13 +70,26 @@ export class BackendService {
.pipe(catchError((err) => this.errorCatcher<Contact[]>(err)));
}
postContacts(
registrarId: string,
contacts: Contact[]
): Observable<Contact[]> {
return this.http.post<Contact[]>(
updateContact(registrarId: string, contact: Contact): Observable<Contact> {
return this.http.put<Contact>(
`/console-api/settings/contacts?registrarId=${registrarId}`,
contacts
contact
);
}
createContact(registrarId: string, contact: Contact): Observable<Contact> {
return this.http.post<Contact>(
`/console-api/settings/contacts?registrarId=${registrarId}`,
contact
);
}
deleteContact(registrarId: string, contact: Contact): Observable<Contact> {
return this.http.delete<Contact>(
`/console-api/settings/contacts?registrarId=${registrarId}`,
{
body: JSON.stringify(contact),
}
);
}
+1
View File
@@ -61,6 +61,7 @@ def fragileTestPatterns = [
// Currently changes a global configuration parameter that for some reason
// results in timestamp inversions for other tests. TODO(mmuller): fix.
"google/registry/flows/host/HostInfoFlowTest.*",
"google/registry/beam/common/RegistryPipelineWorkerInitializerTest.*",
] + dockerIncompatibleTestPatterns
sourceSets {
@@ -172,7 +172,7 @@ public record BillingEvent(
.minusDays(1)
.toString(),
billingId(),
registrarId(),
"",
String.format("%s | TLD: %s | TERM: %d-year", action(), tld(), years()),
amount(),
currency(),
@@ -40,6 +40,8 @@ public class RegistryPipelineWorkerInitializer implements JvmInitializer {
@Override
public void beforeProcessing(PipelineOptions options) {
// TODO(b/416299900): remove next line after GAE is removed.
System.setProperty("google.registry.jetty", "true");
RegistryPipelineOptions registryOptions = options.as(RegistryPipelineOptions.class);
RegistryEnvironment environment = registryOptions.getRegistryEnvironment();
if (environment == null || environment.equals(RegistryEnvironment.UNITTEST)) {
@@ -0,0 +1,29 @@
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.dns.writer;
import dagger.Module;
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
/**
* Groups all {@link DnsWriter} implementations to be installed.
*
* <p>To cherry-pick the DNS writers to install, overwrite this file with your private version in
* the release process.
*/
@Module(
includes = {CloudDnsWriterModule.class, DnsUpdateWriterModule.class, VoidDnsWriterModule.class})
public class DnsWritersModule {}
@@ -31,6 +31,7 @@ import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.RegistrarId;
import google.registry.flows.FlowModule.Superuser;
import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.MutatingFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.custom.DomainInfoFlowCustomLogic;
@@ -53,6 +54,8 @@ import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.persistence.IsolationLevel;
import google.registry.persistence.PersistenceModule;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.util.Optional;
@@ -62,8 +65,12 @@ import org.joda.time.DateTime;
* An EPP flow that returns information about a domain.
*
* <p>The registrar that owns the domain, and any registrar presenting a valid authInfo for the
* domain, will get a rich result with all of the domain's fields. All other requests will be
* answered with a minimal result containing only basic information about the domain.
* domain, will get a rich result with all the domain's fields. All other requests will be answered
* with a minimal result containing only basic information about the domain.
*
* <p>This implements {@link MutatingFlow} instead of {@link TransactionalFlow} as a workaround so
* that the common workflow of "create domain, then immediately get domain info" does not run into
* replication lag issues where the info command claims the domain does not exist.
*
* @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
* @error {@link google.registry.flows.FlowUtils.UnknownCurrencyEppException}
@@ -76,7 +83,8 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.TransfersAreAlwaysForOneYearException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_INFO)
public final class DomainInfoFlow implements TransactionalFlow {
@IsolationLevel(PersistenceModule.TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ)
public final class DomainInfoFlow implements MutatingFlow {
@Inject ExtensionManager extensionManager;
@Inject ResourceCommand resourceCommand;
@@ -93,6 +93,10 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
}
}
@Expose
@Column(insertable = false, updatable = false)
protected Long id;
/** The name of the contact. */
@Expose String name;
@@ -179,6 +183,10 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
tm().putAll(contacts);
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
@@ -295,6 +303,7 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
.put("visibleInDomainWhoisAsAbuse", visibleInDomainWhoisAsAbuse)
.put("allowedToSetRegistryLockPassword", allowedToSetRegistryLockPassword)
.put("registryLockAllowed", isRegistryLockAllowed())
.put("id", getId())
.build();
}
@@ -38,10 +38,8 @@ import google.registry.dns.PublishDnsUpdatesAction;
import google.registry.dns.ReadDnsRefreshRequestsAction;
import google.registry.dns.RefreshDnsAction;
import google.registry.dns.RefreshDnsOnHostRenameAction;
import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
import google.registry.dns.writer.DnsWritersModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateConfigModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
import google.registry.export.ExportDomainListsAction;
import google.registry.export.ExportPremiumTermsAction;
import google.registry.export.ExportReservedTermsAction;
@@ -140,14 +138,13 @@ import google.registry.whois.WhoisModule;
BatchModule.class,
BillingModule.class,
CheckApiModule.class,
CloudDnsWriterModule.class,
ConsoleModule.class,
CronModule.class,
CustomLogicModule.class,
DnsCountQueryCoordinatorModule.class,
DnsModule.class,
DnsUpdateConfigModule.class,
DnsUpdateWriterModule.class,
DnsWritersModule.class,
EppTlsModule.class,
EppToolModule.class,
IcannReportingModule.class,
@@ -160,7 +157,6 @@ import google.registry.whois.WhoisModule;
Spec11Module.class,
TmchModule.class,
ToolsServerModule.class,
VoidDnsWriterModule.class,
WhiteboxModule.class,
WhoisModule.class,
})
@@ -22,7 +22,6 @@ import google.registry.bigquery.BigqueryModule;
import google.registry.config.CloudTasksUtilsModule;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.export.DriveModule;
import google.registry.export.sheet.SheetsServiceModule;
import google.registry.flows.ServerTridProviderModule;
@@ -73,7 +72,6 @@ import jakarta.inject.Singleton;
SheetsServiceModule.class,
StackdriverModule.class,
UrlConnectionServiceModule.class,
VoidDnsWriterModule.class,
UtilsModule.class
})
interface BackendComponent {
@@ -34,10 +34,8 @@ import google.registry.dns.PublishDnsUpdatesAction;
import google.registry.dns.ReadDnsRefreshRequestsAction;
import google.registry.dns.RefreshDnsAction;
import google.registry.dns.RefreshDnsOnHostRenameAction;
import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
import google.registry.dns.writer.DnsWritersModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateConfigModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
import google.registry.export.ExportDomainListsAction;
import google.registry.export.ExportPremiumTermsAction;
import google.registry.export.ExportReservedTermsAction;
@@ -82,13 +80,12 @@ import google.registry.tmch.TmchSmdrlAction;
modules = {
BatchModule.class,
BillingModule.class,
CloudDnsWriterModule.class,
CronModule.class,
CustomLogicModule.class,
DnsCountQueryCoordinatorModule.class,
DnsModule.class,
DnsUpdateConfigModule.class,
DnsUpdateWriterModule.class,
DnsWritersModule.class,
IcannReportingModule.class,
RdeModule.class,
ReportingModule.class,
@@ -96,7 +93,6 @@ import google.registry.tmch.TmchSmdrlAction;
SheetModule.class,
Spec11Module.class,
TmchModule.class,
VoidDnsWriterModule.class,
WhiteboxModule.class,
})
public interface BackendRequestComponent {
@@ -336,7 +336,7 @@ abstract class AbstractJsonableObject implements Jsonable {
// According to RFC 9083 section 3, the syntax of dates and times is defined in RFC3339.
//
// According to RFC3339, we should use ISO8601, which is what DateTime.toString does!
return new JsonPrimitive(((DateTime) object).toString());
return new JsonPrimitive(object.toString());
}
if (object == null) {
return JsonNull.INSTANCE;
@@ -24,10 +24,14 @@ import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.EppResource;
import google.registry.model.registrar.Registrar;
@@ -41,6 +45,7 @@ import google.registry.request.HttpException;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.RequestPath;
import google.registry.request.RequestUrl;
import google.registry.request.Response;
import google.registry.util.Clock;
import jakarta.inject.Inject;
@@ -75,6 +80,7 @@ public abstract class RdapActionBase implements Runnable {
@Inject Response response;
@Inject @RequestMethod Action.Method requestMethod;
@Inject @RequestPath String requestPath;
@Inject @RequestUrl String requestUrl;
@Inject RdapAuthorization rdapAuthorization;
@Inject RdapJsonFormatter rdapJsonFormatter;
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
@@ -198,7 +204,9 @@ public abstract class RdapActionBase implements Runnable {
TopLevelReplyObject topLevelObject =
TopLevelReplyObject.create(replyObject, rdapJsonFormatter.createTosNotice());
Gson gson = formatOutputParam.orElse(false) ? FORMATTED_OUTPUT_GSON : GSON;
response.setPayload(gson.toJson(topLevelObject.toJson()));
JsonObject jsonResult = topLevelObject.toJson();
addLinkValuesRecursively(jsonResult);
response.setPayload(gson.toJson(jsonResult));
}
/**
@@ -264,4 +272,34 @@ public abstract class RdapActionBase implements Runnable {
return rdapJsonFormatter.getRequestTime();
}
/**
* Adds a request-referencing "value" to each link object.
*
* <p>This is the "context URI" as described in RFC 8288. Basically, this contains a reference to
* the request URL that generated this RDAP response.
*
* <p>This is required per the RDAP February 2024 response profile sections 2.6.3 and 2.10, and
* the technical implementation guide sections 3.2 and 3.3.2.
*
* <p>We must do this here (instead of where the links are generated) because many of the links
* (e.g. terms of service) are static constants, and thus cannot by default know what the request
* URL was.
*/
private void addLinkValuesRecursively(JsonElement jsonElement) {
if (jsonElement instanceof JsonArray jsonArray) {
jsonArray.forEach(this::addLinkValuesRecursively);
} else if (jsonElement instanceof JsonObject jsonObject) {
if (jsonObject.get("links") instanceof JsonArray linksArray) {
addLinkValues(linksArray);
}
jsonObject.entrySet().forEach(entry -> addLinkValuesRecursively(entry.getValue()));
}
}
private void addLinkValues(JsonArray linksArray) {
Streams.stream(linksArray)
.map(JsonElement::getAsJsonObject)
.filter(o -> !o.has("value"))
.forEach(o -> o.addProperty("value", requestUrl));
}
}
@@ -44,7 +44,7 @@ public class RdapIcannStandardInformation {
+ " https://icann.org/epp")
.addLink(
Link.builder()
.setRel("alternate")
.setRel("glossary")
.setHref("https://icann.org/epp")
.setType("text/html")
.build())
@@ -57,7 +57,7 @@ public class RdapIcannStandardInformation {
.setDescription("URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf")
.addLink(
Link.builder()
.setRel("alternate")
.setRel("help")
.setHref("https://icann.org/wicf")
.setType("text/html")
.build())
@@ -271,7 +271,7 @@ public class RdapJsonFormatter {
URI htmlUri = htmlBaseURI.resolve(rdapTosStaticUrl);
noticeBuilder.addLink(
Link.builder()
.setRel("alternate")
.setRel("terms-of-service")
.setHref(htmlUri.toString())
.setType("text/html")
.build());
@@ -31,7 +31,6 @@ import google.registry.request.HttpException.BadRequestException;
import google.registry.request.HttpException.UnprocessableEntityException;
import google.registry.request.Parameter;
import google.registry.request.ParameterMap;
import google.registry.request.RequestUrl;
import jakarta.inject.Inject;
import jakarta.persistence.criteria.CriteriaBuilder;
import java.io.UnsupportedEncodingException;
@@ -54,7 +53,6 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
private static final int RESULT_SET_SIZE_SCALING_FACTOR = 30;
@Inject @RequestUrl String requestUrl;
@Inject @ParameterMap ImmutableListMultimap<String, String> parameterMap;
@Inject @Parameter("cursor") Optional<String> cursorTokenParam;
@Inject @Parameter("registrar") Optional<String> registrarParam;
@@ -72,11 +72,11 @@ final class CreateCdnsTld extends ConfirmingCommand {
.setDescription(description)
.setNameServerSet(
RegistryToolEnvironment.get() == RegistryToolEnvironment.PRODUCTION
? "cloud-dns-registry"
: "cloud-dns-registry-test")
? "cloud-dns-registry"
: "cloud-dns-registry-test")
.setDnsName(dnsName)
.setName((name != null) ? name : dnsName)
.setDnssecConfig(new ManagedZoneDnsSecConfig().setNonExistence("NSEC").setState("ON"));
.setDnssecConfig(new ManagedZoneDnsSecConfig().setNonExistence("nsec").setState("on"));
}
@Override
@@ -16,6 +16,7 @@ package google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import static org.joda.time.DateTimeZone.UTC;
@@ -23,6 +24,7 @@ import static org.joda.time.DateTimeZone.UTC;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.template.soy.data.SoyMapData;
import google.registry.model.common.FeatureFlag;
import google.registry.model.pricing.PremiumPricingEngine.DomainPrices;
import google.registry.tools.soy.DomainCreateSoyInfo;
import google.registry.util.StringGenerator;
@@ -58,9 +60,15 @@ final class CreateDomainCommand extends CreateOrUpdateDomainCommand {
@Override
protected void initMutatingEppToolCommand() {
checkArgumentNotNull(registrant, "Registrant must be specified");
checkArgument(!admins.isEmpty(), "At least one admin must be specified");
checkArgument(!techs.isEmpty(), "At least one tech must be specified");
tm().transact(
() -> {
if (!FeatureFlag.isActiveNowOrElse(
FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL, false)) {
checkArgumentNotNull(registrant, "Registrant must be specified");
checkArgument(!admins.isEmpty(), "At least one admin must be specified");
checkArgument(!techs.isEmpty(), "At least one tech must be specified");
}
});
if (isNullOrEmpty(password)) {
password = passwordGenerator.createString(PASSWORD_LENGTH);
}
@@ -23,9 +23,7 @@ import google.registry.config.CloudTasksUtilsModule;
import google.registry.config.CredentialModule.LocalCredentialJson;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
import google.registry.dns.writer.DnsWritersModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.model.ModelModule;
@@ -56,9 +54,8 @@ import javax.annotation.Nullable;
BatchModule.class,
BigqueryModule.class,
ConfigModule.class,
CloudDnsWriterModule.class,
CloudTasksUtilsModule.class,
DnsUpdateWriterModule.class,
DnsWritersModule.class,
GsonModule.class,
KeyModule.class,
KeyringModule.class,
@@ -71,7 +68,6 @@ import javax.annotation.Nullable;
SecretManagerModule.class,
UrlConnectionServiceModule.class,
UtilsModule.class,
VoidDnsWriterModule.class,
NonCachingWhoisModule.class
})
interface RegistryToolComponent {
@@ -19,7 +19,6 @@ import static google.registry.request.RequestParameters.extractOptionalIntParame
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import dagger.Module;
@@ -192,10 +191,10 @@ public final class ConsoleModule {
}
@Provides
@Parameter("contacts")
public static Optional<ImmutableSet<RegistrarPoc>> provideContacts(
@Parameter("contact")
public static Optional<RegistrarPoc> provideContacts(
Gson gson, @OptionalJsonPayload Optional<JsonElement> payload) {
return payload.map(s -> ImmutableSet.copyOf(gson.fromJson(s, RegistrarPoc[].class)));
return payload.map(s -> gson.fromJson(s, RegistrarPoc.class));
}
@Provides
@@ -17,6 +17,7 @@ package google.registry.ui.server.console;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
import static org.apache.http.HttpStatus.SC_OK;
@@ -37,6 +38,7 @@ import google.registry.util.RegistryEnvironment;
import jakarta.inject.Inject;
import java.util.Optional;
import java.util.stream.Collectors;
import org.joda.time.DateTime;
@Action(
service = GaeService.DEFAULT,
@@ -88,18 +90,35 @@ public class ConsoleUpdateRegistrarAction extends ConsoleApiAction {
}
}
Registrar updatedRegistrar =
DateTime now = tm().getTransactionTime();
DateTime newLastPocVerificationDate =
registrarParam.getLastPocVerificationDate() == null
? START_OF_TIME
: registrarParam.getLastPocVerificationDate();
checkArgument(
newLastPocVerificationDate.isBefore(now),
"Invalid value of LastPocVerificationDate - value is in the future");
var updatedRegistrarBuilder =
existingRegistrar
.get()
.asBuilder()
.setAllowedTlds(
registrarParam.getAllowedTlds().stream()
.map(DomainNameUtils::canonicalizeHostname)
.collect(Collectors.toSet()))
.setRegistryLockAllowed(registrarParam.isRegistryLockAllowed())
.setLastPocVerificationDate(registrarParam.getLastPocVerificationDate())
.build();
.setLastPocVerificationDate(newLastPocVerificationDate);
if (user.getUserRoles()
.hasGlobalPermission(ConsolePermission.EDIT_REGISTRAR_DETAILS)) {
updatedRegistrarBuilder =
updatedRegistrarBuilder
.setAllowedTlds(
registrarParam.getAllowedTlds().stream()
.map(DomainNameUtils::canonicalizeHostname)
.collect(Collectors.toSet()))
.setRegistryLockAllowed(registrarParam.isRegistryLockAllowed())
.setLastPocVerificationDate(newLastPocVerificationDate);
}
var updatedRegistrar = updatedRegistrarBuilder.build();
tm().put(updatedRegistrar);
finishAndPersistConsoleUpdateHistory(
new ConsoleUpdateHistory.Builder()
@@ -19,8 +19,10 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.difference;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.DELETE;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.Action.Method.PUT;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import com.google.common.collect.HashMultimap;
@@ -40,59 +42,123 @@ import google.registry.request.Action.GkeService;
import google.registry.request.Parameter;
import google.registry.request.auth.Auth;
import google.registry.ui.forms.FormException;
import google.registry.ui.server.RegistrarFormFields;
import google.registry.ui.server.console.ConsoleApiAction;
import google.registry.ui.server.console.ConsoleApiParams;
import jakarta.inject.Inject;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
@Action(
service = GaeService.DEFAULT,
gkeService = GkeService.CONSOLE,
path = ContactAction.PATH,
method = {GET, POST},
method = {GET, POST, DELETE, PUT},
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class ContactAction extends ConsoleApiAction {
static final String PATH = "/console-api/settings/contacts";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final Optional<ImmutableSet<RegistrarPoc>> contacts;
private final Optional<RegistrarPoc> contact;
private final String registrarId;
@Inject
public ContactAction(
ConsoleApiParams consoleApiParams,
@Parameter("registrarId") String registrarId,
@Parameter("contacts") Optional<ImmutableSet<RegistrarPoc>> contacts) {
@Parameter("contact") Optional<RegistrarPoc> contact) {
super(consoleApiParams);
this.registrarId = registrarId;
this.contacts = contacts;
this.contact = contact;
}
@Override
protected void getHandler(User user) {
checkPermission(user, registrarId, ConsolePermission.VIEW_REGISTRAR_DETAILS);
ImmutableList<RegistrarPoc> am =
ImmutableList<RegistrarPoc> contacts =
tm().transact(
() ->
tm()
.createQueryComposer(RegistrarPoc.class)
.where("registrarId", Comparator.EQ, registrarId)
.stream()
.filter(r -> !r.getTypes().isEmpty())
.collect(toImmutableList()));
consoleApiParams.response().setStatus(SC_OK);
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(am));
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(contacts));
}
@Override
protected void deleteHandler(User user) {
updateContacts(
user,
(registrar, oldContacts) ->
oldContacts.stream()
.filter(
oldContact ->
!oldContact.getEmailAddress().equals(contact.get().getEmailAddress()))
.collect(toImmutableSet()));
}
@Override
protected void postHandler(User user) {
updateContacts(
user,
(registrar, oldContacts) -> {
RegistrarPoc newContact = contact.get();
return ImmutableSet.<RegistrarPoc>builder()
.addAll(oldContacts)
.add(
new RegistrarPoc()
.asBuilder()
.setTypes(newContact.getTypes())
.setVisibleInWhoisAsTech(newContact.getVisibleInWhoisAsTech())
.setVisibleInWhoisAsAdmin(newContact.getVisibleInWhoisAsAdmin())
.setVisibleInDomainWhoisAsAbuse(newContact.getVisibleInDomainWhoisAsAbuse())
.setFaxNumber(newContact.getFaxNumber())
.setName(newContact.getName())
.setEmailAddress(newContact.getEmailAddress())
.setPhoneNumber(newContact.getPhoneNumber())
.setRegistrar(registrar)
.build())
.build();
});
}
@Override
protected void putHandler(User user) {
updateContacts(
user,
(registrar, oldContacts) -> {
RegistrarPoc updatedContact = contact.get();
return oldContacts.stream()
.map(
oldContact ->
oldContact.getId().equals(updatedContact.getId())
? oldContact
.asBuilder()
.setTypes(updatedContact.getTypes())
.setVisibleInWhoisAsTech(updatedContact.getVisibleInWhoisAsTech())
.setVisibleInWhoisAsAdmin(updatedContact.getVisibleInWhoisAsAdmin())
.setVisibleInDomainWhoisAsAbuse(
updatedContact.getVisibleInDomainWhoisAsAbuse())
.setFaxNumber(updatedContact.getFaxNumber())
.setName(updatedContact.getName())
.setEmailAddress(updatedContact.getEmailAddress())
.setPhoneNumber(updatedContact.getPhoneNumber())
.build()
: oldContact)
.collect(toImmutableSet());
});
}
private void updateContacts(
User user,
BiFunction<Registrar, ImmutableSet<RegistrarPoc>, ImmutableSet<RegistrarPoc>>
contactsUpdater) {
checkPermission(user, registrarId, ConsolePermission.EDIT_REGISTRAR_DETAILS);
checkArgument(contacts.isPresent(), "Contacts parameter is not present");
checkArgument(contact.isPresent(), "Contact parameter is not present");
Registrar registrar =
Registrar.loadByRegistrarId(registrarId)
.orElseThrow(
@@ -101,20 +167,10 @@ public class ContactAction extends ConsoleApiAction {
String.format("Unknown registrar %s", registrarId)));
ImmutableSet<RegistrarPoc> oldContacts = registrar.getContacts();
ImmutableSet<RegistrarPoc> updatedContacts =
RegistrarFormFields.getRegistrarContactBuilders(
oldContacts,
Collections.singletonMap(
"contacts",
contacts.get().stream()
.map(RegistrarPoc::toJsonMap)
.collect(toImmutableList())))
.stream()
.map(builder -> builder.setRegistrar(registrar).build())
.collect(toImmutableSet());
ImmutableSet<RegistrarPoc> newContacts = contactsUpdater.apply(registrar, oldContacts);
try {
checkContactRequirements(oldContacts, updatedContacts);
checkContactRequirements(oldContacts, newContacts);
} catch (FormException e) {
logger.atWarning().withCause(e).log(
"Error processing contacts post request for registrar: %s", registrarId);
@@ -123,14 +179,13 @@ public class ContactAction extends ConsoleApiAction {
tm().transact(
() -> {
RegistrarPoc.updateContacts(registrar, updatedContacts);
RegistrarPoc.updateContacts(registrar, newContacts);
Registrar updatedRegistrar =
registrar.asBuilder().setContactsRequireSyncing(true).build();
tm().put(updatedRegistrar);
sendExternalUpdatesIfNecessary(
EmailInfo.create(registrar, updatedRegistrar, oldContacts, updatedContacts));
EmailInfo.create(registrar, updatedRegistrar, oldContacts, newContacts));
});
consoleApiParams.response().setStatus(SC_OK);
}
@@ -169,6 +224,7 @@ public class ContactAction extends ConsoleApiAction {
throw new ContactRequirementException(t);
}
}
enforcePrimaryContactRestrictions(oldContactsByType, newContactsByType);
ensurePhoneNumberNotRemovedForContactTypes(oldContactsByType, newContactsByType, Type.TECH);
Optional<RegistrarPoc> domainWhoisAbuseContact =
@@ -20,9 +20,9 @@
{@param domain: string}
{@param period: int}
{@param nameservers: list<string>}
{@param registrant: string}
{@param admins: list<string>}
{@param techs: list<string>}
{@param? registrant: string|null}
{@param? admins: list<string>|null}
{@param? techs: list<string>|null}
{@param password: string}
{@param? currency: string|null}
{@param? price: string|null}
@@ -45,13 +45,19 @@
{/for}
</domain:ns>
{/if}
<domain:registrant>{$registrant}</domain:registrant>
{for $admin in $admins}
<domain:contact type="admin">{$admin}</domain:contact>
{/for}
{for $tech in $techs}
<domain:contact type="tech">{$tech}</domain:contact>
{/for}
{if $registrant != null}
<domain:registrant>{$registrant}</domain:registrant>
{/if}
{if $admins != null}
{for $admin in $admins}
<domain:contact type="admin">{$admin}</domain:contact>
{/for}
{/if}
{if $techs != null}
{for $tech in $techs}
<domain:contact type="tech">{$tech}</domain:contact>
{/for}
{/if}
<domain:authInfo>
<domain:pw>{$password}</domain:pw>
</domain:authInfo>
@@ -85,7 +85,7 @@ class BillingEventTest {
assertThat(invoiceKey.startDate()).isEqualTo("2017-10-01");
assertThat(invoiceKey.endDate()).isEqualTo("2022-09-30");
assertThat(invoiceKey.productAccountKey()).isEqualTo("12345-CRRHELLO");
assertThat(invoiceKey.usageGroupingKey()).isEqualTo("myRegistrar");
assertThat(invoiceKey.usageGroupingKey()).isEqualTo("");
assertThat(invoiceKey.description()).isEqualTo("RENEW | TLD: test | TERM: 5-year");
assertThat(invoiceKey.unitPrice()).isEqualTo(20.5);
assertThat(invoiceKey.unitPriceCurrency()).isEqualTo("USD");
@@ -106,7 +106,7 @@ class BillingEventTest {
assertThat(invoiceKey.toCsv(3L))
.isEqualTo(
"2017-10-01,2022-09-30,12345-CRRHELLO,61.50,USD,10125,1,PURCHASE,"
+ "myRegistrar,3,RENEW | TLD: test | TERM: 5-year,20.50,USD,");
+ ",3,RENEW | TLD: test | TERM: 5-year,20.50,USD,");
}
@Test
@@ -116,7 +116,7 @@ class BillingEventTest {
assertThat(invoiceKey.toCsv(3L))
.isEqualTo(
"2017-10-01,,12345-CRRHELLO,61.50,USD,10125,1,PURCHASE,"
+ "myRegistrar,3,RENEW | TLD: test | TERM: 0-year,20.50,USD,");
+ ",3,RENEW | TLD: test | TERM: 0-year,20.50,USD,");
}
@Test
@@ -199,6 +199,36 @@ class InvoicingPipelineTest {
0,
"USD",
20.0,
""),
google.registry.beam.billing.BillingEvent.create(
15,
DateTime.parse("2017-10-02T00:00:00.0Z"),
DateTime.parse("2017-10-04T00:00:00.0Z"),
"theRegistrarCopy",
"234",
"",
"test",
"CREATE",
"mydomainfromanotherclient.test",
"REPO-ID",
5,
"JPY",
70.0,
""),
google.registry.beam.billing.BillingEvent.create(
16,
DateTime.parse("2017-10-04T00:00:00Z"),
DateTime.parse("2017-10-04T00:00:00Z"),
"theRegistrarCopy",
"234",
"",
"test",
"RENEW",
"mydomain2fromanotherclient.test",
"REPO-ID",
3,
"USD",
20.5,
""));
private static final ImmutableMap<String, ImmutableList<String>> EXPECTED_DETAILED_REPORT_MAP =
@@ -224,18 +254,26 @@ class InvoicingPipelineTest {
"invoice_details_2017-10_anotherRegistrar_test.csv",
ImmutableList.of(
"5,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,anotherRegistrar,789,,"
+ "test,CREATE,mydomain5.test,REPO-ID,1,USD,0.00,SUNRISE ANCHOR_TENANT"));
+ "test,CREATE,mydomain5.test,REPO-ID,1,USD,0.00,SUNRISE ANCHOR_TENANT"),
"invoice_details_2017-10_theRegistrarCopy_test.csv",
ImmutableList.of(
"15,2017-10-02 00:00:00 UTC,2017-10-04 00:00:00"
+ " UTC,theRegistrarCopy,234,,test,CREATE,mydomainfromanotherclient.test,REPO-ID,5,JPY,70.00,",
"16,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00"
+ " UTC,theRegistrarCopy,234,,test,RENEW,mydomain2fromanotherclient.test,REPO-ID,3,USD,20.50,"));
private static final ImmutableList<String> EXPECTED_INVOICE_OUTPUT =
ImmutableList.of(
"2017-10-01,2020-09-30,234,41.00,USD,10125,1,PURCHASE,theRegistrar,2,"
"2017-10-01,2020-09-30,234,61.50,USD,10125,1,PURCHASE,,3,"
+ "RENEW | TLD: test | TERM: 3-year,20.50,USD,",
"2017-10-01,2022-09-30,234,70.00,JPY,10125,1,PURCHASE,theRegistrar,1,"
"2017-10-01,2022-09-30,234,70.00,JPY,10125,1,PURCHASE,,1,"
+ "CREATE | TLD: hello | TERM: 5-year,70.00,JPY,",
"2017-10-01,,234,20.00,USD,10125,1,PURCHASE,theRegistrar,1,"
"2017-10-01,,234,20.00,USD,10125,1,PURCHASE,,1,"
+ "SERVER_STATUS | TLD: test | TERM: 0-year,20.00,USD,",
"2017-10-01,2018-09-30,456,20.50,USD,10125,1,PURCHASE,bestdomains,1,"
+ "RENEW | TLD: test | TERM: 1-year,20.50,USD,116688");
"2017-10-01,2018-09-30,456,20.50,USD,10125,1,PURCHASE,,1,"
+ "RENEW | TLD: test | TERM: 1-year,20.50,USD,116688",
"2017-10-01,2022-09-30,234,70.00,JPY,10125,1,PURCHASE,,1,CREATE | TLD: test | TERM:"
+ " 5-year,70.00,JPY,");
private final InvoicingPipelineOptions options =
PipelineOptionsFactory.create().as(InvoicingPipelineOptions.class);
@@ -355,21 +393,21 @@ class InvoicingPipelineTest {
.isEqualTo(
"""
SELECT b, r FROM BillingEvent b
JOIN Registrar r ON b.clientId = r.registrarId
JOIN Domain d ON b.domainRepoId = d.repoId
JOIN Tld t ON t.tldStr = d.tld
LEFT JOIN BillingCancellation c ON b.id = c.billingEvent
LEFT JOIN BillingCancellation cr ON b.cancellationMatchingBillingEvent = cr.billingRecurrence
WHERE r.billingAccountMap IS NOT NULL
AND r.type = 'REAL'
AND t.invoicingEnabled IS TRUE
AND CAST(b.billingTime AS timestamp)
BETWEEN CAST('2017-10-01T00:00:00Z' AS timestamp)
AND CAST('2017-11-01T00:00:00Z' AS timestamp)
AND c.id IS NULL
AND cr.id IS NULL
""");
SELECT b, r FROM BillingEvent b
JOIN Registrar r ON b.clientId = r.registrarId
JOIN Domain d ON b.domainRepoId = d.repoId
JOIN Tld t ON t.tldStr = d.tld
LEFT JOIN BillingCancellation c ON b.id = c.billingEvent
LEFT JOIN BillingCancellation cr ON b.cancellationMatchingBillingEvent = cr.billingRecurrence
WHERE r.billingAccountMap IS NOT NULL
AND r.type = 'REAL'
AND t.invoicingEnabled IS TRUE
AND CAST(b.billingTime AS timestamp)
BETWEEN CAST('2017-10-01T00:00:00Z' AS timestamp)
AND CAST('2017-11-01T00:00:00Z' AS timestamp)
AND c.id IS NULL
AND cr.id IS NULL
""");
}
/** Returns the text contents of a file under the beamBucket/results directory. */
@@ -391,6 +429,13 @@ class InvoicingPipelineTest {
.setBillingAccountMap(ImmutableMap.of(JPY, "234", USD, "234"))
.build();
persistResource(registrar1);
Registrar registrar11 = persistNewRegistrar("theRegistrarCopy");
registrar11 =
registrar11
.asBuilder()
.setBillingAccountMap(ImmutableMap.of(JPY, "234", USD, "234"))
.build();
persistResource(registrar11);
Registrar registrar2 = persistNewRegistrar("bestdomains");
registrar2 =
registrar2
@@ -547,6 +592,21 @@ class InvoicingPipelineTest {
.setDomainHistory(domainHistoryRecurrence)
.build();
persistResource(cancellationRecurrence);
// Domains created for registrar with = key but != client id.
Domain domain14 = persistActiveDomain("mydomainfromanotherclient.test");
Domain domain15 = persistActiveDomain("mydomain2fromanotherclient.test");
persistBillingEvent(
15,
domain14,
registrar11,
Reason.CREATE,
5,
Money.ofMajor(JPY, 70),
DateTime.parse("2017-10-04T00:00:00.0Z"),
DateTime.parse("2017-10-02T00:00:00.0Z"));
persistBillingEvent(16, domain15, registrar11, Reason.RENEW, 3, Money.of(USD, 20.5));
}
private static DomainHistory persistDomainHistory(Domain domain, Registrar registrar) {
@@ -0,0 +1,36 @@
// Copyright 2025 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.common;
import static com.google.common.truth.Truth.assertThat;
import google.registry.util.RegistryEnvironment;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.junit.jupiter.api.Test;
public class RegistryPipelineWorkerInitializerTest {
@Test
void test() {
RegistryPipelineOptions options =
PipelineOptionsFactory.fromArgs(
"--registryEnvironment=ALPHA", "--isolationOverride=TRANSACTION_SERIALIZABLE")
.withValidation()
.as(RegistryPipelineOptions.class);
new RegistryPipelineWorkerInitializer().beforeProcessing(options);
assertThat(RegistryEnvironment.isOnJetty()).isTrue();
System.clearProperty("google.registry.jetty");
}
}
@@ -58,7 +58,7 @@ public class FlowModuleTest {
@Test
void givenNonMutatingFlow_thenReplicaTmIsUsed() throws EppException {
String eppInputXmlFilename = "domain_info.xml";
String eppInputXmlFilename = "domain_check.xml";
FlowModule flowModule =
new FlowModule.Builder().setEppInput(getEppInput(eppInputXmlFilename)).build();
JpaTransactionManager tm =
@@ -179,7 +179,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
ImmutableMap<String, String> substitutions,
boolean expectHistoryAndBilling)
throws Exception {
assertMutatingFlow(false);
assertMutatingFlow(true);
String expected =
loadFile(expectedXmlFilename, updateSubstitutions(substitutions, "ROID", "2FF-TLD"));
if (inactive) {
@@ -44,6 +44,7 @@ import google.registry.model.registrar.Registrar.Type;
import google.registry.model.tld.Tld;
import google.registry.model.tld.Tld.TldType;
import google.registry.model.tld.Tlds;
import google.registry.testing.DatabaseHelper;
import google.registry.util.CidrAddressBlock;
import google.registry.util.SerializeUtils;
import java.math.BigDecimal;
@@ -340,6 +341,7 @@ class RegistrarTest extends EntityTestCase {
.setFaxNumber("+1.2125551213")
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH, RegistrarPoc.Type.ABUSE))
.build());
abuseAdminContact = DatabaseHelper.loadByKey(abuseAdminContact.createVKey());
ImmutableSortedSet<RegistrarPoc> techContacts =
registrar.getContactsOfType(RegistrarPoc.Type.TECH);
assertThat(techContacts).containsExactly(newTechContact, newTechAbuseContact).inOrder();
@@ -90,12 +90,6 @@ class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTest.RdapT
assertThat(response.getStatus()).isEqualTo(500);
}
@Test
void testValidName_works() {
assertThat(generateActualJson("no.thing")).isEqualTo(loadJsonFile("rdapjson_toplevel.json"));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testContentType_rdapjson_utf8() {
generateActualJson("no.thing");
@@ -22,7 +22,12 @@ import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
import static org.mockito.Mockito.mock;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.transaction.JpaTestExtensions;
@@ -35,6 +40,7 @@ import google.registry.util.Idn;
import google.registry.util.TypeUtils;
import java.util.HashMap;
import java.util.Optional;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -43,6 +49,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
protected final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
@RegisterExtension
final JpaIntegrationTestExtension jpa =
@@ -107,18 +114,13 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
metricRole = ADMINISTRATOR;
}
JsonObject generateActualJson(String domainName) {
action.requestPath = actionPath + domainName;
action.requestMethod = GET;
action.run();
return RdapTestHelper.parseJsonObject(response.getPayload());
JsonObject generateActualJson(String name) {
return RdapTestHelper.parseJsonObject(runAction(name));
}
String generateHeadPayload(String domainName) {
action.requestPath = actionPath + domainName;
String generateHeadPayload(String name) {
action.requestMethod = HEAD;
action.run();
return response.getPayload();
return runAction(name);
}
JsonObject generateExpectedJsonError(String description, int code) {
@@ -138,16 +140,135 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
"TITLE",
title,
"CODE",
String.valueOf(code));
String.valueOf(code),
"REQUEST_URL",
action.requestUrl);
}
static JsonFileBuilder jsonFileBuilder() {
return new JsonFileBuilder();
JsonFileBuilder jsonFileBuilder() {
return new JsonFileBuilder(action.requestUrl);
}
private String runAction(String name) {
action.requestPath = actionPath + name;
action.requestUrl = "https://example.tld" + actionPath + name;
action.run();
return response.getPayload();
}
JsonElement createTosNotice() {
return JsonParser.parseString(
"""
{
"title": "RDAP Terms of Service",
"description": [
"By querying our Domain Database, you are agreeing to comply with these terms so please read \
them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass \
unsolicited, commercial advertising or solicitations.",
"Don't access our Domain Database through the use of high volume, automated electronic \
processes that send queries or data to the systems of any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information contained in the \
Domain Database in its entirety, or in any substantial portion, without our prior written \
permission.",
"We may retain certain details about queries to our Domain Database for the purposes of \
detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we suspect that you \
have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."
],
"links": [
{
"rel": "self",
"href": "https://example.tld/rdap/help/tos",
"type": "application/rdap+json",
"value": "%REQUEST_URL%"
},
{
"rel": "terms-of-service",
"href": "https://www.example.tld/about/rdap/tos.html",
"type": "text/html",
"value": "%REQUEST_URL%"
}
]
}
"""
.replaceAll("%REQUEST_URL%", action.requestUrl));
}
JsonObject addPermanentBoilerplateNotices(JsonObject jsonObject) {
if (!jsonObject.has("notices")) {
jsonObject.add("notices", new JsonArray());
}
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(createTosNotice());
notices.add(
JsonParser.parseString(
"""
{
"description": [
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars \
version 1.0"
]
}
"""));
return jsonObject;
}
JsonObject addDomainBoilerplateNotices(JsonObject jsonObject) {
addPermanentBoilerplateNotices(jsonObject);
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(
JsonParser.parseString(
"""
{
"title": "Status Codes",
"description": [
"For more information on domain status codes, please visit https://icann.org/epp"
],
"links": [
{
"rel": "glossary",
"href": "https://icann.org/epp",
"type": "text/html",
"value": "%REQUEST_URL%"
}
]
}
"""
.replaceAll("%REQUEST_URL%", action.requestUrl)));
notices.add(
JsonParser.parseString(
"""
{
"title": "RDDS Inaccuracy Complaint Form",
"description": [
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"
],
"links": [
{
"rel": "help",
"href": "https://icann.org/wicf",
"type": "text/html",
"value": "%REQUEST_URL%"
}
]
}
"""
.replaceAll("%REQUEST_URL%", action.requestUrl)));
return jsonObject;
}
protected static final class JsonFileBuilder {
private final HashMap<String, String> substitutions = new HashMap<>();
private JsonFileBuilder(String requestUrl) {
substitutions.put("REQUEST_URL", requestUrl);
}
public JsonObject load(String filename) {
return RdapTestHelper.loadJsonFile(filename, substitutions);
}
@@ -158,6 +279,14 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
return this;
}
public JsonFileBuilder putAll(String... keysAndValues) {
checkArgument(keysAndValues.length % 2 == 0);
for (int i = 0; i < keysAndValues.length; i += 2) {
put(keysAndValues[i], keysAndValues[i + 1]);
}
return this;
}
public JsonFileBuilder put(String key, int index, String value) {
return put(String.format("%s%d", key, index), value);
}
@@ -189,10 +318,38 @@ abstract class RdapActionBaseTestCase<A extends RdapActionBase> {
return putNext("REGISTRAR_FULL_NAME_", fullName);
}
JsonFileBuilder addFullRegistrar(
String handle, @Nullable String fullName, String status, @Nullable String address) {
if (fullName != null) {
putNext("REGISTRAR_FULLNAME_", fullName);
}
if (address != null) {
putNext("REGISTRAR_ADDRESS_", address);
}
return putNext("REGISTRAR_HANDLE_", handle, "STATUS_", status);
}
JsonFileBuilder addContact(String handle) {
return putNext("CONTACT_HANDLE_", handle);
}
JsonFileBuilder addFullContact(
String handle,
@Nullable String status,
@Nullable String fullName,
@Nullable String address) {
if (fullName != null) {
putNext("CONTACT_FULLNAME_", fullName);
}
if (address != null) {
putNext("CONTACT_ADDRESS_", address);
}
if (status != null) {
putNext("STATUS_", status);
}
return putNext("CONTACT_HANDLE_", handle);
}
JsonFileBuilder setNextQuery(String nextQuery) {
return put("NEXT_QUERY", nextQuery);
}
@@ -59,9 +59,12 @@ final class RdapDataStructuresTest {
.setRel("myRel")
.setTitle("myTitle")
.setType("myType")
.setValue("myValue")
.build();
assertThat(link.toJson())
.isEqualTo(createJson("{'href':'myHref','rel':'myRel','title':'myTitle','type':'myType'}"));
.isEqualTo(
createJson(
"{'href':'myHref','rel':'myRel','title':'myTitle','type':'myType','value':'myValue'}"));
assertRestrictedNames(link, "links[]");
}
@@ -230,16 +230,11 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
clock.nowUtc().minusMonths(6)));
}
private JsonObject addBoilerplate(JsonObject obj) {
RdapTestHelper.addDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
}
private void assertProperResponseForCatLol(String queryString, String expectedOutputFile) {
assertAboutJson()
.that(generateActualJson(queryString))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.lol", "C-LOL")
.addContact("4-ROID")
@@ -357,7 +352,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.みんな"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.みんな", "1D-Q9JYB4C")
.addContact("19-ROID")
@@ -376,7 +371,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.%E3%81%BF%E3%82%93%E3%81%AA"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.みんな", "1D-Q9JYB4C")
.addContact("19-ROID")
@@ -395,7 +390,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.xn--q9jyb4c"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.みんな", "1D-Q9JYB4C")
.addContact("19-ROID")
@@ -414,7 +409,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("cat.1.tld"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("cat.1.tld", "25-1_TLD")
.addContact("21-ROID")
@@ -473,7 +468,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("dodo.lol"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("dodo.lol", "15-LOL")
.addContact("11-ROID")
@@ -493,7 +488,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("dodo.lol"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder()
.addDomain("dodo.lol", "15-LOL")
.addContact("11-ROID")
@@ -512,7 +507,9 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
"addgraceperiod", "lol", clock.nowUtc(), clock.nowUtc().plusYears(1));
assertAboutJson()
.that(generateActualJson("addgraceperiod.lol"))
.isEqualTo(addBoilerplate(jsonFileBuilder().load("rdap_domain_add_grace_period.json")));
.isEqualTo(
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_add_grace_period.json")));
}
@Test
@@ -522,7 +519,8 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("autorenew.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_auto_renew_grace_period.json")));
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_auto_renew_grace_period.json")));
}
@Test
@@ -545,7 +543,7 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("redemption.lol"))
.isEqualTo(
addBoilerplate(
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_pending_delete_redemption_grace_period.json")));
}
@@ -568,7 +566,8 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("renew.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_explicit_renew_grace_period.json")));
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_explicit_renew_grace_period.json")));
}
@Test
@@ -590,7 +589,8 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
assertAboutJson()
.that(generateActualJson("transfer.lol"))
.isEqualTo(
addBoilerplate(jsonFileBuilder().load("rdap_domain_transfer_grace_period.json")));
addDomainBoilerplateNotices(
jsonFileBuilder().load("rdap_domain_transfer_grace_period.json")));
}
@Test
@@ -631,12 +631,15 @@ class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainAction> {
"rel",
"alternate",
"type",
"text/html")));
"text/html",
"value",
"https://example.tld/rdap/domain/example.lol")));
JsonObject actuaResponse = generateActualJson("example.lol");
JsonObject expectedErrorResponse = generateExpectedJsonError("example.lol blocked by BSA", 404);
expectedErrorResponse
.getAsJsonArray("notices")
.add(RdapTestHelper.GSON.toJsonTree(expectedBsaNotice));
assertAboutJson().that(generateActualJson("example.lol")).isEqualTo(expectedErrorResponse);
assertAboutJson().that(actuaResponse).isEqualTo(expectedErrorResponse);
assertThat(response.getStatus()).isEqualTo(404);
}
@@ -473,8 +473,7 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
private JsonObject wrapInSearchReply(JsonObject obj) {
obj = RdapTestHelper.wrapInSearchReply("domainSearchResults", obj);
RdapTestHelper.addDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
return addDomainBoilerplateNotices(obj);
}
private void runSuccessfulTest(RequestType requestType, String queryString, JsonObject expected) {
@@ -15,7 +15,6 @@
package google.registry.rdap;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.rdap.RdapTestHelper.loadJsonFile;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistSimpleResources;
@@ -28,7 +27,6 @@ import static google.registry.testing.GsonSubject.assertAboutJson;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import google.registry.model.contact.Contact;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
@@ -39,13 +37,15 @@ import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
import google.registry.request.Action;
import google.registry.testing.FullFieldsTestEntityHelper;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link RdapEntityAction}. */
class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
private static final String CONTACT_NAME = "(◕‿◕)";
private static final String CONTACT_ADDRESS = "\"1 Smiley Row\", \"Suite みんな\"";
RdapEntityActionTest() {
super(RdapEntityAction.class);
}
@@ -67,7 +67,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
registrant =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-REG",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -75,7 +75,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
adminContact =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-ADM",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -83,7 +83,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
techContact =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-TEC",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -110,7 +110,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
disconnectedContact =
FullFieldsTestEntityHelper.makeAndPersistContact(
"8372808-DIS",
"(◕‿◕)",
CONTACT_NAME,
"lol@cat.みんな",
ImmutableList.of("1 Smiley Row", "Suite みんな"),
clock.nowUtc(),
@@ -123,186 +123,191 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
clock.nowUtc().minusMonths(6));
}
private JsonObject generateExpectedJson(
String handle,
String fullName,
String status,
@Nullable String address,
String expectedOutputFile) {
return loadJsonFile(
expectedOutputFile,
"NAME", handle,
"FULLNAME", fullName,
"ADDRESS", (address == null) ? "\"1 Smiley Row\", \"Suite みんな\"" : address,
"TYPE", "entity",
"STATUS", status);
}
private JsonObject generateExpectedJsonWithTopLevelEntries(
String handle,
String expectedOutputFile) {
return generateExpectedJsonWithTopLevelEntries(
handle, "(◕‿◕)", "active", null, expectedOutputFile);
}
private JsonObject generateExpectedJsonWithTopLevelEntries(
String handle,
String fullName,
String status,
String address,
String expectedOutputFile) {
JsonObject obj = generateExpectedJson(handle, fullName, status, address, expectedOutputFile);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
}
private void runSuccessfulHandleTest(String handleQuery, String fileName) {
runSuccessfulHandleTest(handleQuery, "(◕‿◕)", "active", null, fileName);
}
private void runSuccessfulHandleTest(String handleQuery, String fullName, String fileName) {
runSuccessfulHandleTest(handleQuery, fullName, "active", null, fileName);
}
private void runSuccessfulHandleTest(
String handleQuery,
String fullName,
String rdapStatus,
String address,
String fileName) {
@Test
void testUnknownEntity_RoidPattern_notFound() {
assertAboutJson()
.that(generateActualJson(handleQuery))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
handleQuery, fullName, rdapStatus, address, fileName));
assertThat(response.getStatus()).isEqualTo(200);
}
private void runNotFoundTest(String handleQuery) {
assertAboutJson()
.that(generateActualJson(handleQuery))
.isEqualTo(generateExpectedJsonError(handleQuery + " not found", 404));
.that(generateActualJson("_MISSING-ENTITY_"))
.isEqualTo(generateExpectedJsonError("_MISSING-ENTITY_ not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testUnknownEntity_RoidPattern_notFound() {
runNotFoundTest("_MISSING-ENTITY_");
}
@Test
void testUnknownEntity_IanaPattern_notFound() {
runNotFoundTest("123");
assertAboutJson()
.that(generateActualJson("123"))
.isEqualTo(generateExpectedJsonError("123 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testUnknownEntity_notRoidNotIana_notFound() {
// Since we allow search by registrar name, every string is a possible name
runNotFoundTest("some,random,string");
assertAboutJson()
.that(generateActualJson("some,random,string"))
.isEqualTo(generateExpectedJsonError("some,random,string not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testValidRegistrantContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(registrant.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidRegistrantContact_found_asAdministrator() {
loginAsAdmin();
runSuccessfulHandleTest(registrant.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidRegistrantContact_found_notLoggedIn() {
runSuccessfulHandleTest(
registrant.getRepoId(),
"(◕‿◕)",
"active",
null,
"rdap_associated_contact_no_personal_data.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), "active", CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact_no_personal_data.json")));
}
@Test
void testValidRegistrantContact_found_loggedInAsOtherRegistrar() {
login("otherregistrar");
runSuccessfulHandleTest(
registrant.getRepoId(),
"(◕‿◕)",
"active",
null,
"rdap_associated_contact_no_personal_data.json");
assertAboutJson()
.that(generateActualJson(registrant.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(registrant.getRepoId(), "active", CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact_no_personal_data.json")));
}
@Test
void testValidAdminContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(adminContact.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(adminContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(adminContact.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidTechContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(techContact.getRepoId(), "rdap_associated_contact.json");
assertAboutJson()
.that(generateActualJson(techContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(techContact.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
}
@Test
void testValidDisconnectedContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(disconnectedContact.getRepoId(), "rdap_contact.json");
assertAboutJson()
.that(generateActualJson(disconnectedContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(
disconnectedContact.getRepoId(), "active", CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_contact.json")));
}
@Test
void testDeletedContact_notFound() {
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_notFound_includeDeletedSetFalse() {
action.includeDeletedParam = Optional.of(false);
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_notFound_notLoggedIn() {
action.includeDeletedParam = Optional.of(true);
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_notFound_loggedInAsDifferentRegistrar() {
login("idnregistrar");
action.includeDeletedParam = Optional.of(true);
runNotFoundTest(deletedContact.getRepoId());
String repoId = deletedContact.getRepoId();
assertAboutJson()
.that(generateActualJson(repoId))
.isEqualTo(generateExpectedJsonError(repoId + " not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testDeletedContact_found_loggedInAsCorrectRegistrar() {
login("evilregistrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
deletedContact.getRepoId(),
"",
"inactive",
"",
"rdap_contact_deleted.json");
assertAboutJson()
.that(generateActualJson(deletedContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addContact(deletedContact.getRepoId())
.load("rdap_contact_deleted.json")));
}
@Test
void testDeletedContact_found_loggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
deletedContact.getRepoId(),
"",
"inactive",
"",
"rdap_contact_deleted.json");
assertAboutJson()
.that(generateActualJson(deletedContact.getRepoId()))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addContact(deletedContact.getRepoId())
.load("rdap_contact_deleted.json")));
}
@Test
void testRegistrar_found() {
runSuccessfulHandleTest("101", "Yes Virginia <script>", "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("101"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("101", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
@@ -310,58 +315,97 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
assertAboutJson()
.that(generateActualJson("IDN%20Registrar"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"102", "IDN Registrar", "active", null, "rdap_registrar.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("102", "IDN Registrar", "active", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar102_works() {
runSuccessfulHandleTest("102", "IDN Registrar", "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("102"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("102", "IDN Registrar", "active", null)
.load("rdap_registrar.json")));
}
@Test
void testRegistrar103_works() {
runSuccessfulHandleTest("103", "Multilevel Registrar", "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("103"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("103", "Multilevel Registrar", "active", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar104_notFound() {
runNotFoundTest("104");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(generateExpectedJsonError("104 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testRegistrar104_notFound_deletedFlagWhenNotLoggedIn() {
action.includeDeletedParam = Optional.of(true);
runNotFoundTest("104");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(generateExpectedJsonError("104 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testRegistrar104_found_deletedFlagWhenLoggedIn() {
login("deletedregistrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("104", "Yes Virginia <script>", "inactive", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar104_notFound_deletedFlagWhenLoggedInAsOther() {
login("1tldregistrar");
action.includeDeletedParam = Optional.of(true);
runNotFoundTest("104");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(generateExpectedJsonError("104 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
void testRegistrar104_found_deletedFlagWhenLoggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
assertAboutJson()
.that(generateActualJson("104"))
.isEqualTo(
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullRegistrar("104", "Yes Virginia <script>", "inactive", null)
.load("rdap_registrar.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testRegistrar105_doesNotExist() {
runNotFoundTest("105");
assertAboutJson()
.that(generateActualJson("105"))
.isEqualTo(generateExpectedJsonError("105 not found", 404));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
@@ -370,8 +414,10 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
assertAboutJson()
.that(generateActualJson(techContact.getRepoId() + "?key=value"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
techContact.getRepoId(), "rdap_associated_contact.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addFullContact(techContact.getRepoId(), null, CONTACT_NAME, CONTACT_ADDRESS)
.load("rdap_associated_contact.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -15,7 +15,6 @@
package google.registry.rdap;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.rdap.RdapTestHelper.loadJsonFile;
import static google.registry.rdap.RdapTestHelper.parseJsonObject;
import static google.registry.request.Action.Method.GET;
import static google.registry.testing.DatabaseHelper.createTld;
@@ -30,7 +29,6 @@ import static google.registry.testing.GsonSubject.assertAboutJson;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -45,13 +43,15 @@ import google.registry.testing.FakeResponse;
import google.registry.testing.FullFieldsTestEntityHelper;
import java.net.URLDecoder;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link RdapEntitySearchAction}. */
class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySearchAction> {
private static final String BINKY_ADDRESS = "\"123 Blinky St\", \"Blinkyland\"";
private static final String BINKY_FULL_NAME = "Blinky (赤ベイ)";
RdapEntitySearchActionTest() {
super(RdapEntitySearchAction.class);
}
@@ -128,7 +128,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
FullFieldsTestEntityHelper.makeAndPersistContact(
"blinky",
"Blinky (赤ベイ)",
BINKY_FULL_NAME,
"blinky@b.tld",
ImmutableList.of("123 Blinky St", "Blinkyland"),
clock.nowUtc(),
@@ -150,45 +150,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
action.subtypeParam = Optional.empty();
}
private JsonObject generateExpectedJson(String expectedOutputFile) {
return loadJsonFile(expectedOutputFile, "TYPE", "entity");
}
private JsonObject generateExpectedJson(
String handle,
String expectedOutputFile) {
return generateExpectedJson(handle, null, "active", null, expectedOutputFile);
}
private JsonObject generateExpectedJson(
String handle,
@Nullable String fullName,
String status,
@Nullable String address,
String expectedOutputFile) {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
builder.put("NAME", handle);
if (fullName != null) {
builder.put("FULLNAME", fullName);
}
if (address != null) {
builder.put("ADDRESS", address);
}
builder.put("TYPE", "entity");
builder.put("STATUS", status);
return loadJsonFile(expectedOutputFile, builder.build());
}
private JsonObject generateExpectedJsonForEntity(
String handle,
String fullName,
String status,
@Nullable String address,
String expectedOutputFile) {
JsonObject obj = generateExpectedJson(handle, fullName, status, address, expectedOutputFile);
obj = RdapTestHelper.wrapInSearchReply("entitySearchResults", obj);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
private JsonObject addBoilerplate(JsonObject jsonObject) {
jsonObject = RdapTestHelper.wrapInSearchReply("entitySearchResults", jsonObject);
return addPermanentBoilerplateNotices(jsonObject);
}
private void createManyContactsAndRegistrars(
@@ -259,38 +223,6 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
verifyMetrics(numContactsRetrieved);
}
private void runSuccessfulNameTestWithBlinky(String queryString, String fileName) {
runSuccessfulNameTest(
queryString,
"2-ROID",
"Blinky (赤ベイ)",
"active",
"\"123 Blinky St\", \"Blinkyland\"",
fileName);
}
private void runSuccessfulNameTest(
String queryString,
String handle,
@Nullable String fullName,
String fileName) {
runSuccessfulNameTest(queryString, handle, fullName, "active", null, fileName);
}
private void runSuccessfulNameTest(
String queryString,
String handle,
@Nullable String fullName,
String status,
@Nullable String address,
String fileName) {
rememberWildcardType(queryString);
assertAboutJson()
.that(generateActualJsonWithFullName(queryString))
.isEqualTo(generateExpectedJsonForEntity(handle, fullName, status, address, fileName));
assertThat(response.getStatus()).isEqualTo(200);
}
private void runNotFoundNameTest(String queryString) {
rememberWildcardType(queryString);
assertAboutJson()
@@ -299,38 +231,6 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertThat(response.getStatus()).isEqualTo(404);
}
private void runSuccessfulHandleTestWithBlinky(String queryString, String fileName) {
runSuccessfulHandleTest(
queryString,
"2-ROID",
"Blinky (赤ベイ)",
"active",
"\"123 Blinky St\", \"Blinkyland\"",
fileName);
}
private void runSuccessfulHandleTest(
String queryString,
String handle,
@Nullable String fullName,
String fileName) {
runSuccessfulHandleTest(queryString, handle, fullName, "active", null, fileName);
}
private void runSuccessfulHandleTest(
String queryString,
String handle,
@Nullable String fullName,
String status,
@Nullable String address,
String fileName) {
rememberWildcardType(queryString);
assertAboutJson()
.that(generateActualJsonWithHandle(queryString))
.isEqualTo(generateExpectedJsonForEntity(handle, fullName, status, address, fileName));
assertThat(response.getStatus()).isEqualTo(200);
}
private void runNotFoundHandleTest(String queryString) {
rememberWildcardType(queryString);
assertAboutJson()
@@ -470,7 +370,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testInvalidSubtype_rejected() {
action.subtypeParam = Optional.of("Space Aliens");
assertAboutJson()
.that(generateActualJsonWithFullName("Blinky (赤ベイ)"))
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
generateExpectedJsonError(
"Subtype parameter must specify contacts, registrars or all", 400));
@@ -482,23 +382,44 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testNameMatchContact_found() {
login("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
rememberWildcardType(BINKY_FULL_NAME);
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testNameMatchContact_found_subtypeAll() {
login("2-RegistrarTest");
rememberWildcardType(BINKY_FULL_NAME);
action.subtypeParam = Optional.of("aLl");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testNameMatchContact_found_subtypeContacts() {
login("2-RegistrarTest");
rememberWildcardType(BINKY_FULL_NAME);
action.subtypeParam = Optional.of("cONTACTS");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -506,15 +427,22 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchContact_notFound_subtypeRegistrars() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("Registrars");
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_found_specifyingSameRegistrar() {
login("2-RegistrarTest");
rememberWildcardType(BINKY_FULL_NAME);
action.registrarParam = Optional.of("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -522,35 +450,48 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchContact_notFound_specifyingOtherRegistrar() {
login("2-RegistrarTest");
action.registrarParam = Optional.of("2-RegistrarInact");
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_found_asAdministrator() {
loginAsAdmin();
rememberWildcardType("Blinky (赤ベイ)");
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
rememberWildcardType(BINKY_FULL_NAME);
assertAboutJson()
.that(generateActualJsonWithFullName(BINKY_FULL_NAME))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testNameMatchContact_notFound_notLoggedIn() {
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_notFound_loggedInAsOtherRegistrar() {
login("2-Registrar");
runNotFoundNameTest("Blinky (赤ベイ)");
runNotFoundNameTest(BINKY_FULL_NAME);
verifyErrorMetrics(0);
}
@Test
void testNameMatchContact_found_wildcard() {
login("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky*", "rdap_contact.json");
rememberWildcardType("Blinky*");
assertAboutJson()
.that(generateActualJsonWithFullName("Blinky*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -558,7 +499,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchContact_found_wildcardSpecifyingSameRegistrar() {
login("2-RegistrarTest");
action.registrarParam = Optional.of("2-RegistrarTest");
runSuccessfulNameTestWithBlinky("Blinky*", "rdap_contact.json");
rememberWildcardType("Blinky*");
assertAboutJson()
.that(generateActualJsonWithFullName("Blinky*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -576,7 +524,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
rememberWildcardType("Blin*");
assertAboutJson()
.that(generateActualJsonWithFullName("Blin*"))
.isEqualTo(generateExpectedJson("rdap_multiple_contacts2.json"));
.isEqualTo(jsonFileBuilder().load("rdap_multiple_contacts2.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(2);
}
@@ -615,8 +563,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testNameMatchRegistrar_found() {
login("2-RegistrarTest");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -624,8 +578,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_subtypeAll() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("all");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -633,8 +593,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_subtypeRegistrars() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("REGISTRARS");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -649,8 +615,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testNameMatchRegistrar_found_specifyingSameRegistrar() {
action.registrarParam = Optional.of("2-Registrar");
runSuccessfulNameTest(
"Yes Virginia <script>", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("Yes Virginia <script>");
assertAboutJson()
.that(generateActualJsonWithFullName("Yes Virginia <script>"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -666,10 +638,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
login("2-RegistrarTest");
createManyContactsAndRegistrars(4, 0, registrarTest);
rememberWildcardType("Entity *");
// JsonObject foo = generateActualJsonWithFullName("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(generateExpectedJson("rdap_nontruncated_contacts.json"));
.isEqualTo(jsonFileBuilder().load("rdap_nontruncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(4);
}
@@ -682,8 +653,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D", "rdap_truncated_contacts.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
}
@@ -696,8 +668,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D", "rdap_truncated_contacts.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
// For contacts, we only need to fetch one result set's worth (plus one).
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
@@ -728,7 +701,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
rememberWildcardType("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(generateExpectedJson("rdap_nontruncated_registrars.json"));
.isEqualTo(jsonFileBuilder().load("rdap_nontruncated_registrars.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(0);
}
@@ -740,8 +713,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_registrars.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_registrars.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
}
@@ -753,8 +727,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_registrars.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_registrars.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
}
@@ -815,8 +790,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
generateExpectedJson(
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_mixed_entities.json"));
jsonFileBuilder()
.put("NAME", "fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D")
.load("rdap_truncated_mixed_entities.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(3, IncompletenessWarningType.TRUNCATED);
}
@@ -845,7 +821,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
rememberWildcardType("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(generateExpectedJson("rdap_nontruncated_contacts.json"));
.isEqualTo(jsonFileBuilder().load("rdap_nontruncated_contacts.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(4);
}
@@ -855,8 +831,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
login("2-RegistrarTest");
action.subtypeParam = Optional.of("registrars");
createManyContactsAndRegistrars(1, 1, registrarTest);
runSuccessfulNameTest(
"Entity *", "301", "Entity 2", "rdap_registrar.json");
rememberWildcardType("Entity *");
assertAboutJson()
.that(generateActualJsonWithFullName("Entity *"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("301", "Entity 2", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -878,7 +860,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_inactiveAsSameRegistrar() {
action.includeDeletedParam = Optional.of(true);
login("2-RegistrarInact");
runSuccessfulNameTest("No Way", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("No Way");
assertAboutJson()
.that(generateActualJsonWithFullName("No Way"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -886,7 +875,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_inactiveAsAdmin() {
action.includeDeletedParam = Optional.of(true);
loginAsAdmin();
runSuccessfulNameTest("No Way", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("No Way");
assertAboutJson()
.that(generateActualJsonWithFullName("No Way"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -908,8 +904,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_testAsSameRegistrar() {
action.includeDeletedParam = Optional.of(true);
login("2-RegistrarTest");
runSuccessfulNameTest(
"Da Test Registrar", "not applicable", "Da Test Registrar", "rdap_registrar_test.json");
rememberWildcardType("Da Test Registrar");
assertAboutJson()
.that(generateActualJsonWithFullName("Da Test Registrar"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("not applicable", "Da Test Registrar", "active", null)
.load("rdap_registrar_test.json")));
verifyMetrics(0);
}
@@ -917,15 +919,28 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testNameMatchRegistrar_found_testAsAdmin() {
action.includeDeletedParam = Optional.of(true);
loginAsAdmin();
runSuccessfulNameTest(
"Da Test Registrar", "not applicable", "Da Test Registrar", "rdap_registrar_test.json");
rememberWildcardType("Da Test Registrar");
assertAboutJson()
.that(generateActualJsonWithFullName("Da Test Registrar"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("not applicable", "Da Test Registrar", "active", null)
.load("rdap_registrar_test.json")));
verifyMetrics(0);
}
@Test
void testHandleMatchContact_found() {
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -933,7 +948,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_subtypeAll() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("all");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -941,7 +963,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_subtypeContacts() {
login("2-RegistrarTest");
action.subtypeParam = Optional.of("contacts");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -956,7 +985,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testHandleMatchContact_found_specifyingSameRegistrar() {
action.registrarParam = Optional.of("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact_no_personal_data_with_remark.json");
rememberWildcardType("2-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("2-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().load("rdap_contact_no_personal_data_with_remark.json")));
verifyMetrics(1);
}
@@ -986,13 +1020,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWhenLoggedInAsSameRegistrar() {
login("2-Registrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROID",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@@ -1000,13 +1033,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWhenLoggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROID",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROID");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROID"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@@ -1029,13 +1061,12 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWildcardWhenLoggedInAsSameRegistrar() {
login("2-Registrar");
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROI*",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROI*");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROI*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@@ -1043,33 +1074,53 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_deletedWildcardWhenLoggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
runSuccessfulHandleTest(
"6-ROI*",
"6-ROID",
"",
"inactive",
"",
"rdap_contact_deleted.json");
rememberWildcardType("6-ROI*");
assertAboutJson()
.that(generateActualJsonWithHandle("6-ROI*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder().addContact("6-ROID").load("rdap_contact_deleted.json")));
verifyMetrics(1);
}
@Test
void testHandleMatchRegistrar_found() {
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@Test
void testHandleMatchRegistrar_found_subtypeAll() {
action.subtypeParam = Optional.of("all");
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@Test
void testHandleMatchRegistrar_found_subtypeRegistrars() {
action.subtypeParam = Optional.of("registrars");
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -1083,7 +1134,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testHandleMatchRegistrar_found_specifyingSameRegistrar() {
action.registrarParam = Optional.of("2-Registrar");
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
rememberWildcardType("20");
assertAboutJson()
.that(generateActualJsonWithHandle("20"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("20", "Yes Virginia <script>", "active", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -1098,14 +1156,28 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_wildcardWithResultSetSizeOne() {
login("2-RegistrarTest");
action.rdapResultSetMaxSize = 1;
runSuccessfulHandleTestWithBlinky("2-R*", "rdap_contact.json");
rememberWildcardType("2-R*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-R*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@Test
void testHandleMatchContact_found_wildcard() {
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
rememberWildcardType("2-R*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-R*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -1113,7 +1185,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchContact_found_wildcardSpecifyingSameRegistrar() {
action.registrarParam = Optional.of("2-RegistrarTest");
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
rememberWildcardType("2-RO*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-RO*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -1128,7 +1207,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
@Test
void testHandleMatchContact_found_deleted() {
login("2-RegistrarTest");
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
rememberWildcardType("2-R*");
assertAboutJson()
.that(generateActualJsonWithHandle("2-R*"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullContact("2-ROID", "active", BINKY_FULL_NAME, BINKY_ADDRESS)
.load("rdap_contact.json")));
verifyMetrics(1);
}
@@ -1245,7 +1331,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchRegistrar_found_inactiveAsSameRegistrar() {
action.includeDeletedParam = Optional.of(true);
login("2-RegistrarInact");
runSuccessfulHandleTest("21", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("21");
assertAboutJson()
.that(generateActualJsonWithHandle("21"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
@@ -1253,7 +1346,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
void testHandleMatchRegistrar_found_inactiveAsAdmin() {
action.includeDeletedParam = Optional.of(true);
loginAsAdmin();
runSuccessfulHandleTest("21", "21", "No Way", "inactive", null, "rdap_registrar.json");
rememberWildcardType("21");
assertAboutJson()
.that(generateActualJsonWithHandle("21"))
.isEqualTo(
addBoilerplate(
jsonFileBuilder()
.addFullRegistrar("21", "No Way", "inactive", null)
.load("rdap_registrar.json")));
verifyMetrics(0);
}
}
@@ -48,13 +48,15 @@ class RdapHelpActionTest extends RdapActionBaseTestCase<RdapHelpAction> {
@Test
void testHelpActionDefault_getsIndex() {
assertThat(generateActualJson("")).isEqualTo(loadJsonFile("rdap_help_index.json"));
assertThat(generateActualJson(""))
.isEqualTo(loadJsonFile("rdap_help_index.json", "POSSIBLE_SLASH", ""));
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
void testHelpActionSlash_getsIndex() {
assertThat(generateActualJson("/")).isEqualTo(loadJsonFile("rdap_help_index.json"));
assertThat(generateActualJson("/"))
.isEqualTo(loadJsonFile("rdap_help_index.json", "POSSIBLE_SLASH", "/"));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -15,15 +15,12 @@
package google.registry.rdap;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.rdap.RdapTestHelper.loadJsonFile;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
import static google.registry.testing.GsonSubject.assertAboutJson;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonObject;
import google.registry.model.registrar.Registrar;
import google.registry.rdap.RdapMetrics.EndpointType;
import google.registry.rdap.RdapMetrics.SearchType;
@@ -32,7 +29,6 @@ import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
import google.registry.request.Action;
import google.registry.testing.FullFieldsTestEntityHelper;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -72,37 +68,6 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
"ns1.domain.external", "9.10.11.12", clock.nowUtc().minusYears(1));
}
private JsonObject generateExpectedJson(
String name,
@Nullable ImmutableMap<String, String> otherSubstitutions,
String expectedOutputFile) {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
builder.put("TYPE", "nameserver");
builder.put("NAME", name);
boolean punycodeSet = false;
if (otherSubstitutions != null) {
builder.putAll(otherSubstitutions);
if (otherSubstitutions.containsKey("PUNYCODENAME")) {
punycodeSet = true;
}
}
if (!punycodeSet) {
builder.put("PUNYCODENAME", name);
}
return loadJsonFile(
expectedOutputFile,
builder.build());
}
private JsonObject generateExpectedJsonWithTopLevelEntries(
String name,
@Nullable ImmutableMap<String, String> otherSubstitutions,
String expectedOutputFile) {
JsonObject obj = generateExpectedJson(name, otherSubstitutions, expectedOutputFile);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
}
@Test
void testInvalidNameserver_returns400() {
assertAboutJson()
@@ -126,14 +91,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.lol"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -142,14 +104,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.lol."))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -158,14 +117,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("Ns1.CaT.lOl."))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -174,14 +130,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.lol?key=value"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.lol",
ImmutableMap.of(
"HANDLE", "2-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -190,15 +143,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.みんな"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.みんな",
ImmutableMap.of(
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
"HANDLE", "5-ROID",
"ADDRESSTYPE", "v6",
"ADDRESS", "bad:f00d:cafe::15:beef",
"STATUS", "active"),
"rdap_host_unicode.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "5-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_unicode.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -207,15 +156,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.cat.xn--q9jyb4c"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.cat.みんな",
ImmutableMap.of(
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
"HANDLE", "5-ROID",
"ADDRESSTYPE", "v6",
"ADDRESS", "bad:f00d:cafe::15:beef",
"STATUS", "active"),
"rdap_host_unicode.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "5-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_unicode.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -224,14 +169,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.domain.1.tld"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.domain.1.tld",
ImmutableMap.of(
"HANDLE", "8-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "5.6.7.8",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.domain.1.tld", "8-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "5.6.7.8", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -240,14 +182,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("ns1.domain.external"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"ns1.domain.external",
ImmutableMap.of(
"HANDLE", "C-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "9.10.11.12",
"STATUS", "active"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("ns1.domain.external", "C-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "9.10.11.12", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -287,14 +226,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("nsdeleted.cat.lol"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"nsdeleted.cat.lol",
ImmutableMap.of(
"HANDLE", "A-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "inactive"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("nsdeleted.cat.lol", "A-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "inactive")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -305,14 +241,11 @@ class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameserverActi
assertAboutJson()
.that(generateActualJson("nsdeleted.cat.lol"))
.isEqualTo(
generateExpectedJsonWithTopLevelEntries(
"nsdeleted.cat.lol",
ImmutableMap.of(
"HANDLE", "A-ROID",
"ADDRESSTYPE", "v4",
"ADDRESS", "1.2.3.4",
"STATUS", "inactive"),
"rdap_host.json"));
addPermanentBoilerplateNotices(
jsonFileBuilder()
.addNameserver("nsdeleted.cat.lol", "A-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4", "STATUS", "inactive")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
}
@@ -158,26 +158,9 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
action.nameParam = Optional.empty();
}
private JsonObject generateExpectedJsonForNameserver(
String name,
String punycodeName,
String handle,
String ipAddressType,
String ipAddress,
String expectedOutputFile) {
JsonObject obj =
loadJsonFile(
expectedOutputFile,
"NAME", name,
"PUNYCODENAME", punycodeName,
"HANDLE", handle,
"ADDRESSTYPE", ipAddressType,
"ADDRESS", ipAddress,
"STATUS", "active",
"TYPE", "nameserver");
obj = RdapTestHelper.wrapInSearchReply("nameserverSearchResults", obj);
RdapTestHelper.addNonDomainBoilerplateNotices(obj, "https://example.tld/rdap/");
return obj;
private JsonObject addBoilerplate(JsonObject jsonObject) {
jsonObject = RdapTestHelper.wrapInSearchReply("nameserverSearchResults", jsonObject);
return addPermanentBoilerplateNotices(jsonObject);
}
private void createManyHosts(int numHosts) {
@@ -318,8 +301,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.lol"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -329,8 +315,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("Ns1.CaT.lOl"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -356,13 +345,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns2.cat.lol"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns2.cat.lol",
null,
"4-ROID",
"v6",
"bad:f00d:cafe::15:beef",
"rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns2.cat.lol", "4-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -380,8 +367,10 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.external"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.external", null, "8-ROID", null, null, "rdap_host_external.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.external", "8-ROID")
.load("rdap_host_external.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -391,13 +380,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.みんな"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.みんな",
"ns1.cat.xn--q9jyb4c",
"B-ROID",
"v4",
"1.2.3.5",
"rdap_host_unicode.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "B-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.5")
.load("rdap_host_unicode.json")));
metricWildcardType = WildcardType.NO_WILDCARD;
metricPrefixLength = 19;
assertThat(response.getStatus()).isEqualTo(200);
@@ -409,13 +396,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.xn--q9jyb4c"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.みんな",
"ns1.cat.xn--q9jyb4c",
"B-ROID",
"v4",
"1.2.3.5",
"rdap_host_unicode.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.みんな", "B-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.5")
.load("rdap_host_unicode.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -425,8 +410,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns1.cat.1.test"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.1.test", null, "E-ROID", "v4", "1.2.3.6", "rdap_host.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.1.test", "E-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.6", "STATUS", "active")
.load("rdap_host.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -553,13 +541,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithName("ns*.cat.lol"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns2.cat.lol",
null,
"4-ROID",
"v6",
"bad:f00d:cafe::15:beef",
"rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns2.cat.lol", "4-ROID")
.putAll("ADDRESSTYPE", "v6", "ADDRESS", "bad:f00d:cafe::15:beef")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(2);
}
@@ -749,8 +735,11 @@ class RdapNameserverSearchActionTest extends RdapSearchActionTestCase<RdapNamese
assertAboutJson()
.that(generateActualJsonWithIp("1.2.3.4"))
.isEqualTo(
generateExpectedJsonForNameserver(
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
addBoilerplate(
jsonFileBuilder()
.addNameserver("ns1.cat.lol", "2-ROID")
.putAll("ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4")
.load("rdap_host_linked.json")));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(1);
}
@@ -45,107 +45,6 @@ class RdapTestHelper {
CONTACT
}
private static JsonObject createTosNotice(String linkBase) {
return GSON.toJsonTree(
ImmutableMap.of(
"title", "RDAP Terms of Service",
"description",
ImmutableList.of(
"By querying our Domain Database, you are agreeing to comply with these"
+ " terms so please read them carefully.",
"Any information provided is 'as is' without any guarantee of accuracy.",
"Please do not misuse the Domain Database. It is intended solely for"
+ " query-based access.",
"Don't use the Domain Database to allow, enable, or otherwise support the"
+ " transmission of mass unsolicited, commercial advertising or"
+ " solicitations.",
"Don't access our Domain Database through the use of high volume, automated"
+ " electronic processes that send queries or data to the systems of"
+ " any ICANN-accredited registrar.",
"You may only use the information contained in the Domain Database for"
+ " lawful purposes.",
"Do not compile, repackage, disseminate, or otherwise use the information"
+ " contained in the Domain Database in its entirety, or in any"
+ " substantial portion, without our prior written permission.",
"We may retain certain details about queries to our Domain Database for the"
+ " purposes of detecting and preventing misuse.",
"We reserve the right to restrict or deny your access to the database if we"
+ " suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time."),
"links",
ImmutableList.of(
ImmutableMap.of(
"rel", "self",
"href", linkBase + "help/tos",
"type", "application/rdap+json"),
ImmutableMap.of(
"rel", "alternate",
"href", "https://www.registry.tld/about/rdap/tos.html",
"type", "text/html"))))
.getAsJsonObject();
}
static void addNonDomainBoilerplateNotices(JsonObject jsonObject, String linkBase) {
if (!jsonObject.has("notices")) {
jsonObject.add("notices", new JsonArray());
}
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(createTosNotice(linkBase));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"description",
ImmutableList.of(
"This response conforms to the RDAP Operational Profile for gTLD"
+ " Registries and Registrars version 1.0"))));
}
static void addDomainBoilerplateNotices(JsonObject jsonObject, String linkBase) {
if (!jsonObject.has("notices")) {
jsonObject.add("notices", new JsonArray());
}
JsonArray notices = jsonObject.getAsJsonArray("notices");
notices.add(createTosNotice(linkBase));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"description",
ImmutableList.of(
"This response conforms to the RDAP Operational Profile for gTLD"
+ " Registries and Registrars version 1.0"))));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"title",
"Status Codes",
"description",
ImmutableList.of(
"For more information on domain status codes, please visit"
+ " https://icann.org/epp"),
"links",
ImmutableList.of(
ImmutableMap.of(
"rel", "alternate",
"href", "https://icann.org/epp",
"type", "text/html")))));
notices.add(
GSON.toJsonTree(
ImmutableMap.of(
"title",
"RDDS Inaccuracy Complaint Form",
"description",
ImmutableList.of(
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf"),
"links",
ImmutableList.of(
ImmutableMap.of(
"rel", "alternate",
"href", "https://icann.org/wicf",
"type", "text/html")))));
}
static RdapJsonFormatter getTestRdapJsonFormatter(Clock clock) {
RdapJsonFormatter rdapJsonFormatter = new RdapJsonFormatter();
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
@@ -174,7 +73,7 @@ class RdapTestHelper {
"We reserve the right to restrict or deny your access to the database if we"
+ " suspect that you have failed to comply with these terms.",
"We reserve the right to modify this agreement at any time.");
rdapJsonFormatter.rdapTosStaticUrl = "https://www.registry.tld/about/rdap/tos.html";
rdapJsonFormatter.rdapTosStaticUrl = "https://www.example.tld/about/rdap/tos.html";
return rdapJsonFormatter;
}
@@ -15,10 +15,10 @@
package google.registry.schema.registrar;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.insertInDb;
import static google.registry.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.SqlHelper.saveRegistrar;
import com.google.common.collect.ImmutableSet;
@@ -63,7 +63,9 @@ class RegistrarPocTest {
@Test
void testPersistence_succeeds() {
insertInDb(testRegistrarPoc);
assertThat(loadByEntity(testRegistrarPoc)).isEqualTo(testRegistrarPoc);
assertAboutImmutableObjects()
.that(testRegistrarPoc)
.isEqualExceptFields(testRegistrarPoc, "id");
}
@Test
@@ -55,7 +55,7 @@ class CreateCdnsTldTest extends CommandTestCase<CreateCdnsTld> {
.setDnsName(dnsName)
.setDescription(description)
.setName(name)
.setDnssecConfig(new ManagedZoneDnsSecConfig().setState("ON").setNonExistence("NSEC"));
.setDnssecConfig(new ManagedZoneDnsSecConfig().setState("on").setNonExistence("nsec"));
}
@Test
@@ -15,16 +15,21 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistPremiumList;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import google.registry.dns.writer.VoidDnsWriter;
import google.registry.model.common.FeatureFlag;
import google.registry.model.pricing.StaticPremiumListPricingEngine;
import google.registry.model.tld.Tld;
import google.registry.model.tld.label.PremiumListDao;
@@ -111,12 +116,15 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
@Test
void testSuccess_minimal() throws Exception {
persistResource(
new FeatureFlag()
.asBuilder()
.setFeatureName(MINIMUM_DATASET_CONTACTS_OPTIONAL)
.setStatusMap(ImmutableSortedMap.of(START_OF_TIME, ACTIVE))
.build());
// Test that each optional field can be omitted. Also tests the auto-gen password.
runCommandForced(
"--client=NewRegistrar",
"--registrant=crr-admin",
"--admins=crr-admin",
"--techs=crr-tech",
"example.tld");
eppVerifier.verifySent("domain_create_minimal.xml");
}
@@ -131,7 +139,9 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
"--techs=crr-tech",
"example.tld",
"example.abc");
eppVerifier.verifySent("domain_create_minimal.xml").verifySent("domain_create_minimal_abc.xml");
eppVerifier
.verifySent("domain_create_contacts.xml")
.verifySent("domain_create_contacts_abc.xml");
}
@Test
@@ -152,8 +162,8 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
"example.tld",
"example.abc");
eppVerifier
.verifySent("domain_create_minimal.xml")
.verifySent("domain_create_minimal_abc.xml");
.verifySent("domain_create_contacts.xml")
.verifySent("domain_create_contacts_abc.xml");
}
@Test
@@ -192,9 +202,9 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
"palladium.tld",
"example.abc");
eppVerifier
.verifySent("domain_create_minimal.xml")
.verifySent("domain_create_contacts.xml")
.verifySent("domain_create_palladium.xml")
.verifySent("domain_create_minimal_abc.xml");
.verifySent("domain_create_contacts_abc.xml");
assertInStdout(
"palladium.tld is premium at USD 877.00 per year; "
+ "sending total cost for 1 year(s) of USD 877.00.");
@@ -227,6 +237,19 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
eppVerifier.verifySent("domain_create_token.xml");
}
@Test
void testSuccess_contactsStillRequired() throws Exception {
// Verify that if contacts are still required, the minimum+contacts request is sent
createTld("tld");
runCommandForced(
"--client=NewRegistrar",
"--registrant=crr-admin",
"--admins=crr-admin",
"--techs=crr-tech",
"example.tld");
eppVerifier.verifySent("domain_create_contacts.xml");
}
@Test
void testFailure_duplicateDomains() {
IllegalArgumentException thrown =
@@ -15,6 +15,7 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
@@ -102,8 +103,9 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
"--visible_in_domain_whois_as_abuse=false",
"NewRegistrar");
RegistrarPoc registrarPoc = loadRegistrar("NewRegistrar").getContacts().asList().get(1);
assertThat(registrarPoc)
.isEqualTo(
assertAboutImmutableObjects()
.that(registrarPoc)
.isEqualExceptFields(
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Judith Registrar")
@@ -115,7 +117,8 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build());
.build(),
"id");
}
@Test
@@ -261,8 +264,9 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
"--visible_in_domain_whois_as_abuse=true",
"NewRegistrar");
RegistrarPoc registrarPoc = loadRegistrar("NewRegistrar").getContacts().asList().get(1);
assertThat(registrarPoc)
.isEqualTo(
assertAboutImmutableObjects()
.that(registrarPoc)
.isEqualExceptFields(
new RegistrarPoc.Builder()
.setRegistrar(registrar)
.setName("Jim Doe")
@@ -272,7 +276,8 @@ class RegistrarPocCommandTest extends CommandTestCase<RegistrarPocCommand> {
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(true)
.build());
.build(),
"id");
}
@Test
@@ -0,0 +1,54 @@
// Copyright 2025 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.ui.server.console;
import static google.registry.testing.DatabaseHelper.createAdminUser;
import static google.registry.testing.DatabaseHelper.createTld;
import com.google.gson.Gson;
import google.registry.model.console.User;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.tools.GsonUtils;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
public abstract class ConsoleActionBaseTestCase {
protected static final Gson GSON = GsonUtils.provideGson();
protected final FakeClock clock = new FakeClock(DateTime.parse("2024-04-15T00:00:00.000Z"));
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
protected ConsoleApiParams consoleApiParams;
protected FakeResponse response;
protected User fteUser;
@BeforeEach
void beforeEachBaseTestCase() {
createTld("tld");
fteUser = createAdminUser("fte@email.tld");
AuthResult authResult = AuthResult.createUser(fteUser);
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
response = (FakeResponse) consoleApiParams.response();
}
}
@@ -15,7 +15,6 @@
package google.registry.ui.server.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
@@ -25,7 +24,6 @@ import com.google.common.collect.ImmutableMap;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
@@ -33,20 +31,12 @@ import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.ConsoleDomainGetAction}. */
public class ConsoleDomainGetActionTest {
private ConsoleApiParams consoleApiParams;
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
public class ConsoleDomainGetActionTest extends ConsoleActionBaseTestCase {
@BeforeEach
void beforeEach() {
createTld("tld");
DatabaseHelper.persistActiveDomain("exists.tld");
}
@@ -62,8 +52,8 @@ public class ConsoleDomainGetActionTest {
.build())),
"exists.tld");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload())
.isEqualTo(
"{\"domainName\":\"exists.tld\",\"adminContact\":{\"key\":\"3-ROID\",\"kind\":"
+ "\"google.registry.model.contact.Contact\"},\"techContact\":{\"key\":\"3-ROID\","
@@ -81,7 +71,7 @@ public class ConsoleDomainGetActionTest {
void testFailure_emptyAuth() {
ConsoleDomainGetAction action = createAction(AuthResult.NOT_AUTHENTICATED, "exists.tld");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_UNAUTHORIZED);
assertThat(response.getStatus()).isEqualTo(SC_UNAUTHORIZED);
}
@Test
@@ -89,7 +79,7 @@ public class ConsoleDomainGetActionTest {
ConsoleDomainGetAction action =
createAction(AuthResult.createApp("service@registry.example"), "exists.tld");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_UNAUTHORIZED);
assertThat(response.getStatus()).isEqualTo(SC_UNAUTHORIZED);
}
@Test
@@ -98,17 +88,14 @@ public class ConsoleDomainGetActionTest {
createAction(
AuthResult.createUser(createUser(new UserRoles.Builder().build())), "exists.tld");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_NOT_FOUND);
assertThat(response.getStatus()).isEqualTo(SC_NOT_FOUND);
}
@Test
void testFailure_nonexistentDomain() {
ConsoleDomainGetAction action =
createAction(
AuthResult.createUser(createUser(new UserRoles.Builder().setIsAdmin(true).build())),
"nonexistent.tld");
ConsoleDomainGetAction action = createAction(AuthResult.createUser(fteUser), "nonexistent.tld");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_NOT_FOUND);
assertThat(response.getStatus()).isEqualTo(SC_NOT_FOUND);
}
private User createUser(UserRoles userRoles) {
@@ -120,6 +107,7 @@ public class ConsoleDomainGetActionTest {
private ConsoleDomainGetAction createAction(AuthResult authResult, String domain) {
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
response = (FakeResponse) consoleApiParams.response();
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.GET.toString());
return new ConsoleDomainGetAction(consoleApiParams, domain);
}
@@ -16,49 +16,31 @@ package google.registry.ui.server.console;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createAdminUser;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted;
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static org.mockito.Mockito.when;
import com.google.common.collect.Iterables;
import com.google.gson.Gson;
import google.registry.model.EppResourceUtils;
import google.registry.model.domain.Domain;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.tools.GsonUtils;
import google.registry.ui.server.console.ConsoleDomainListAction.DomainListResult;
import java.util.Optional;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link ConsoleDomainListAction}. */
public class ConsoleDomainListActionTest {
private static final Gson GSON = GsonUtils.provideGson();
private final FakeClock clock = new FakeClock(DateTime.parse("2023-10-20T00:00:00.000Z"));
private ConsoleApiParams consoleApiParams;
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
public class ConsoleDomainListActionTest extends ConsoleActionBaseTestCase {
@BeforeEach
void beforeEach() {
createTld("tld");
for (int i = 0; i < 10; i++) {
DatabaseHelper.persistActiveDomain(i + "exists.tld", clock.nowUtc());
clock.advanceOneMilli();
@@ -70,9 +52,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_allDomains() {
ConsoleDomainListAction action = createAction("TheRegistrar");
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).hasSize(10);
assertThat(result.totalResults).isEqualTo(10);
assertThat(result.checkpointTime).isEqualTo(clock.nowUtc());
@@ -84,9 +64,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_noDomains() {
ConsoleDomainListAction action = createAction("NewRegistrar");
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).hasSize(0);
assertThat(result.totalResults).isEqualTo(0);
assertThat(result.checkpointTime).isEqualTo(clock.nowUtc());
@@ -97,9 +75,7 @@ public class ConsoleDomainListActionTest {
// Two pages of results should go in reverse chronological order
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, null);
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
.containsExactly("9exists.tld", "8exists.tld", "7exists.tld", "6exists.tld", "5exists.tld");
assertThat(result.totalResults).isEqualTo(10);
@@ -107,9 +83,7 @@ public class ConsoleDomainListActionTest {
// Now do the second page
action = createAction("TheRegistrar", result.checkpointTime, 1, 5, 10L, null);
action.run();
result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
.containsExactly("4exists.tld", "3exists.tld", "2exists.tld", "1exists.tld", "0exists.tld");
}
@@ -118,9 +92,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_partialPage() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 1, 8, null, null);
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
.containsExactly("1exists.tld", "0exists.tld");
}
@@ -130,9 +102,7 @@ public class ConsoleDomainListActionTest {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 10, null, null);
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).hasSize(10);
assertThat(result.totalResults).isEqualTo(10);
@@ -142,9 +112,7 @@ public class ConsoleDomainListActionTest {
// Even though we persisted a new domain, the old checkpoint should return no more results
action = createAction("TheRegistrar", result.checkpointTime, 1, 10, null, null);
action.run();
result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).isEmpty();
assertThat(result.totalResults).isEqualTo(10);
}
@@ -153,9 +121,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_checkpointTime_deletion() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, null);
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
clock.advanceOneMilli();
Domain toDelete =
@@ -165,9 +131,7 @@ public class ConsoleDomainListActionTest {
// Second page should include the domain that is now deleted due to the checkpoint time
action = createAction("TheRegistrar", result.checkpointTime, 1, 5, null, null);
action.run();
result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
.containsExactly("4exists.tld", "3exists.tld", "2exists.tld", "1exists.tld", "0exists.tld");
}
@@ -176,9 +140,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_searchTerm_oneMatch() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "0");
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(Iterables.getOnlyElement(result.domains).getDomainName()).isEqualTo("0exists.tld");
}
@@ -186,9 +148,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_searchTerm_returnsNone() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "deleted");
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).isEmpty();
}
@@ -196,9 +156,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_searchTerm_caseInsensitive() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "eXiStS");
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).hasSize(5);
assertThat(result.totalResults).isEqualTo(10);
}
@@ -207,9 +165,7 @@ public class ConsoleDomainListActionTest {
void testSuccess_searchTerm_tld() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "tld");
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).hasSize(5);
assertThat(result.totalResults).isEqualTo(10);
}
@@ -218,9 +174,7 @@ public class ConsoleDomainListActionTest {
void testPartialSuccess_pastEnd() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 5, 5, null, null);
action.run();
DomainListResult result =
GSON.fromJson(
((FakeResponse) consoleApiParams.response()).getPayload(), DomainListResult.class);
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).isEmpty();
}
@@ -228,14 +182,14 @@ public class ConsoleDomainListActionTest {
void testFailure_invalidResultsPerPage() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 0, null, null);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Results per page must be between 1 and 500 inclusive");
action = createAction("TheRegistrar", null, 0, 501, null, null);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Results per page must be between 1 and 500 inclusive");
}
@@ -243,9 +197,8 @@ public class ConsoleDomainListActionTest {
void testFailure_invalidPageNumber() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, -1, 10, null, null);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("Page number must be non-negative");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("Page number must be non-negative");
}
private ConsoleDomainListAction createAction(String registrarId) {
@@ -259,9 +212,10 @@ public class ConsoleDomainListActionTest {
@Nullable Integer resultsPerPage,
@Nullable Long totalResults,
@Nullable String searchTerm) {
AuthResult authResult = AuthResult.createUser(createAdminUser("email@email.example"));
AuthResult authResult = AuthResult.createUser(fteUser);
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.GET.toString());
response = (FakeResponse) consoleApiParams.response();
return new ConsoleDomainListAction(
consoleApiParams,
registrarId,
@@ -15,7 +15,6 @@
package google.registry.ui.server.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import static org.mockito.Mockito.when;
@@ -24,32 +23,19 @@ import com.google.common.collect.ImmutableList;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import java.io.IOException;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class ConsoleDumDownloadActionTest {
private final FakeClock clock = new FakeClock(DateTime.parse("2024-04-15T00:00:00.000Z"));
private ConsoleApiParams consoleApiParams;
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
class ConsoleDumDownloadActionTest extends ConsoleActionBaseTestCase {
@BeforeEach
void beforeEach() {
createTld("tld");
for (int i = 0; i < 3; i++) {
DatabaseHelper.persistActiveDomain(
i + "exists.tld", clock.nowUtc(), clock.nowUtc().plusDays(300));
@@ -60,13 +46,7 @@ class ConsoleDumDownloadActionTest {
@Test
void testSuccess_returnsCorrectDomains() throws IOException {
User user =
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
AuthResult authResult = AuthResult.createUser(user);
AuthResult authResult = AuthResult.createUser(fteUser);
ConsoleDumDownloadAction action = createAction(authResult);
action.run();
ImmutableList<String> expected =
@@ -75,7 +55,6 @@ class ConsoleDumDownloadActionTest {
"2exists.tld,2024-04-15 00:00:00.002+00,2025-02-09 00:00:00.002+00,{INACTIVE}",
"1exists.tld,2024-04-15 00:00:00.001+00,2025-02-09 00:00:00.001+00,{INACTIVE}",
"0exists.tld,2024-04-15 00:00:00+00,2025-02-09 00:00:00+00,{INACTIVE}");
FakeResponse response = (FakeResponse) consoleApiParams.response();
assertThat(response.getStatus()).isEqualTo(SC_OK);
ImmutableList<String> actual =
ImmutableList.copyOf(response.getStringWriter().toString().split("\r\n"));
@@ -93,11 +72,12 @@ class ConsoleDumDownloadActionTest {
AuthResult authResult = AuthResult.createUser(user);
ConsoleDumDownloadAction action = createAction(authResult);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
private ConsoleDumDownloadAction createAction(AuthResult authResult) {
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
response = (FakeResponse) consoleApiParams.response();
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.GET.toString());
return new ConsoleDumDownloadAction(clock, consoleApiParams, "TheRegistrar", "test_name");
}
@@ -30,22 +30,12 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.gson.Gson;
import google.registry.flows.PasswordOnlyTransportCredentials;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeResponse;
import google.registry.tools.GsonUtils;
import google.registry.ui.server.console.ConsoleEppPasswordAction.EppPasswordData;
import google.registry.util.EmailMessage;
import jakarta.mail.internet.AddressException;
@@ -56,20 +46,12 @@ import java.io.StringReader;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class ConsoleEppPasswordActionTest {
private static final Gson GSON = GsonUtils.provideGson();
class ConsoleEppPasswordActionTest extends ConsoleActionBaseTestCase {
private static String eppPostData =
"{\"registrarId\":\"%s\",\"oldPassword\":\"%s\",\"newPassword\":\"%s\",\"newPasswordRepeat\":\"%s\"}";
private ConsoleApiParams consoleApiParams;
protected PasswordOnlyTransportCredentials credentials = new PasswordOnlyTransportCredentials();
private FakeResponse response;
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@BeforeEach
void beforeEach() {
@@ -86,9 +68,8 @@ class ConsoleEppPasswordActionTest {
void testFailure_emptyParams() throws IOException {
ConsoleEppPasswordAction action = createAction("", "", "", "");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("Missing param(s): registrarId");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("Missing param(s): registrarId");
}
@Test
@@ -96,9 +77,8 @@ class ConsoleEppPasswordActionTest {
ConsoleEppPasswordAction action =
createAction("TheRegistrar", "oldPassword", "newPassword", "newPasswordRepeat");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.contains("New password fields don't match");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).contains("New password fields don't match");
}
@Test
@@ -106,9 +86,8 @@ class ConsoleEppPasswordActionTest {
ConsoleEppPasswordAction action =
createAction("TheRegistrar", "oldPassword", "randomPasword", "randomPasword");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.contains("Registrar password is incorrect");
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getPayload()).contains("Registrar password is incorrect");
}
@Test
@@ -124,12 +103,12 @@ class ConsoleEppPasswordActionTest {
+ " environment")
.setBody(
"The following changes were made in registry unittest environment to the"
+ " registrar TheRegistrar by user email@email.com:\n"
+ " registrar TheRegistrar by admin fte@email.tld:\n"
+ "\n"
+ "password: ******** -> ••••••••\n")
.setRecipients(ImmutableList.of(new InternetAddress("notification@test.example")))
.build());
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
}
@Test
@@ -137,7 +116,7 @@ class ConsoleEppPasswordActionTest {
ConsoleEppPasswordAction action =
createAction("TheRegistrar", "foobar", "randomPassword", "randomPassword");
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertDoesNotThrow(() -> credentials.validate(loadRegistrar("TheRegistrar"), "randomPassword"));
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.EPP_PASSWORD_UPDATE);
@@ -147,16 +126,6 @@ class ConsoleEppPasswordActionTest {
private ConsoleEppPasswordAction createAction(
String registrarId, String oldPassword, String newPassword, String newPasswordRepeat)
throws IOException {
response = new FakeResponse();
User user =
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
DatabaseHelper.putInDb(user);
AuthResult authResult = AuthResult.createUser(user);
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
AuthenticatedRegistrarAccessor authenticatedRegistrarAccessor =
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of("TheRegistrar", OWNER));
@@ -27,19 +27,16 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import google.registry.model.OteStatsTestHelper;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.auth.AuthResult;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeResponse;
import google.registry.tools.GsonUtils;
import google.registry.tools.IamClient;
import google.registry.ui.server.console.ConsoleOteAction.OteCreateData;
import google.registry.util.StringGenerator;
@@ -50,19 +47,11 @@ import java.util.stream.Collectors;
import org.json.simple.JSONArray;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class ConsoleOteActionTest {
class ConsoleOteActionTest extends ConsoleActionBaseTestCase {
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private static final Gson GSON = GsonUtils.provideGson();
private final IamClient iamClient = mock(IamClient.class);
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
private FakeResponse response;
private ConsoleApiParams consoleApiParams;
private StringGenerator passwordGenerator =
new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
@@ -90,16 +79,12 @@ class ConsoleOteActionTest {
Optional.of("someRandomString"),
Optional.of(new OteCreateData("testRegistrarId", "tescontact@registry.example")));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
@Test
void testFailure_invalidParamsNoRegistrarId() {
user =
user.asBuilder()
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
AuthResult authResult = AuthResult.createUser(user);
AuthResult authResult = AuthResult.createUser(fteUser);
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
ConsoleOteAction action =
createAction(
@@ -109,9 +94,8 @@ class ConsoleOteActionTest {
Optional.of("someRandomString"),
Optional.of(new OteCreateData("", "test@email.com")));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("OT&E create body is invalid");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("OT&E create body is invalid");
}
@Test
@@ -130,18 +114,13 @@ class ConsoleOteActionTest {
Optional.of("someRandomString"),
Optional.of(new OteCreateData("testRegistrarId", "")));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("OT&E create body is invalid");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("OT&E create body is invalid");
}
@Test
void testSuccess_oteCreated() {
user =
user.asBuilder()
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
AuthResult authResult = AuthResult.createUser(user);
AuthResult authResult = AuthResult.createUser(fteUser);
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
ConsoleOteAction action =
createAction(
@@ -152,8 +131,7 @@ class ConsoleOteActionTest {
Optional.of(new OteCreateData("theregistrar", "contact@registry.example")));
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
action.run();
String response = ((FakeResponse) consoleApiParams.response()).getPayload();
var obsResponse = GSON.fromJson(response, Map.class);
var obsResponse = GSON.fromJson(response.getPayload(), Map.class);
assertThat(
ImmutableMap.of(
"theregistrar-1", "theregistrar-sunrise",
@@ -162,7 +140,7 @@ class ConsoleOteActionTest {
"theregistrar-5", "theregistrar-eap",
"password", "abcdefghijklmnop"))
.containsExactlyEntriesIn(obsResponse);
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
verifyIapPermission(
"contact@registry.example",
Optional.of("someRandomString@email.test"),
@@ -183,50 +161,40 @@ class ConsoleOteActionTest {
Optional.of(new OteCreateData("theregistrar", "contact@registry.example")));
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("Missing registrarId parameter");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("Missing registrarId parameter");
}
@Test
void testSuccess_finishedOte() throws Exception {
OteStatsTestHelper.setupCompleteOte("theregistrar");
user =
user.asBuilder()
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
AuthResult authResult = AuthResult.createUser(user);
AuthResult authResult = AuthResult.createUser(fteUser);
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
ConsoleOteAction action =
createAction(
Action.Method.GET, authResult, "theregistrar-1", Optional.empty(), Optional.empty());
action.run();
List<Map<String, ?>> response =
GSON.fromJson(((FakeResponse) consoleApiParams.response()).getPayload(), JSONArray.class);
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertTrue(response.stream().allMatch(status -> Boolean.TRUE.equals(status.get("completed"))));
List<Map<String, ?>> responseMaps = GSON.fromJson(response.getPayload(), JSONArray.class);
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertTrue(
responseMaps.stream().allMatch(status -> Boolean.TRUE.equals(status.get("completed"))));
}
@Test
void testSuccess_unfinishedOte() throws Exception {
OteStatsTestHelper.setupIncompleteOte("theregistrar");
user =
user.asBuilder()
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
AuthResult authResult = AuthResult.createUser(user);
AuthResult authResult = AuthResult.createUser(fteUser);
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
ConsoleOteAction action =
createAction(
Action.Method.GET, authResult, "theregistrar-1", Optional.empty(), Optional.empty());
action.run();
List<Map<String, ?>> response =
GSON.fromJson(((FakeResponse) consoleApiParams.response()).getPayload(), JSONArray.class);
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
List<Map<String, ?>> responseMaps = GSON.fromJson(response.getPayload(), JSONArray.class);
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(
response.stream()
responseMaps.stream()
.filter(status -> Boolean.FALSE.equals(status.get("completed")))
.map(status -> status.get("description"))
.collect(Collectors.toList()))
@@ -240,9 +208,9 @@ class ConsoleOteActionTest {
String registrarId,
Optional<String> maybeGroupEmailAddress,
Optional<OteCreateData> oteCreateData) {
response = new FakeResponse();
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
response = (FakeResponse) consoleApiParams.response();
return new ConsoleOteAction(
consoleApiParams,
iamClient,
@@ -42,12 +42,10 @@ import google.registry.model.console.UserRoles;
import google.registry.model.domain.Domain;
import google.registry.model.domain.RegistryLock;
import google.registry.model.eppcommon.StatusValue;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.auth.AuthResult;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.tools.DomainLockUtils;
import google.registry.util.EmailMessage;
@@ -55,13 +53,11 @@ import google.registry.util.StringGenerator;
import jakarta.mail.internet.InternetAddress;
import java.io.IOException;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -71,7 +67,7 @@ import org.mockito.quality.Strictness;
/** Tests for {@link ConsoleRegistryLockAction}. */
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ConsoleRegistryLockActionTest {
public class ConsoleRegistryLockActionTest extends ConsoleActionBaseTestCase {
private static final String EXPECTED_EMAIL_MESSAGE =
"""
@@ -81,16 +77,9 @@ public class ConsoleRegistryLockActionTest {
https://registrarconsole.tld/console/#/registry-lock-verify?lockVerificationCode=\
123456789ABCDEFGHJKLMNPQRSTUVWXY""";
private final FakeClock fakeClock = new FakeClock(DateTime.parse("2024-04-18T12:00:00.000Z"));
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(fakeClock).buildIntegrationTestExtension();
@Mock GmailClient gmailClient;
private ConsoleRegistryLockAction action;
private Domain defaultDomain;
private FakeResponse response;
private User user;
@BeforeEach
@@ -118,15 +107,15 @@ public class ConsoleRegistryLockActionTest {
@Test
void testGet_simpleLock() {
saveRegistryLock(createDefaultLockBuilder().setLockCompletionTime(fakeClock.nowUtc()).build());
saveRegistryLock(createDefaultLockBuilder().setLockCompletionTime(clock.nowUtc()).build());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload())
.isEqualTo(
"""
[{"domainName":"example.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
{"creationTime":"2024-04-18T12:00:00.000Z"},"unlockRequestTime":"null","lockCompletionTime":\
"2024-04-18T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false}]\
{"creationTime":"2024-04-15T00:00:00.000Z"},"unlockRequestTime":"null","lockCompletionTime":\
"2024-04-15T00:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false}]\
""");
}
@@ -148,11 +137,11 @@ public class ConsoleRegistryLockActionTest {
.setRegistrarId("TheRegistrar")
.setVerificationCode("123456789ABCDEFGHJKLMNPQRSTUVWXY")
.setRegistrarPocId("johndoe@theregistrar.com")
.setLockCompletionTime(fakeClock.nowUtc())
.setUnlockRequestTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.setUnlockRequestTime(clock.nowUtc())
.build();
saveRegistryLock(expiredUnlock);
fakeClock.advanceBy(Duration.standardDays(1));
clock.advanceBy(Duration.standardDays(1));
RegistryLock regularLock =
new RegistryLock.Builder()
@@ -161,9 +150,9 @@ public class ConsoleRegistryLockActionTest {
.setRegistrarId("TheRegistrar")
.setVerificationCode("123456789ABCDEFGHJKLMNPQRSTUVWXY")
.setRegistrarPocId("johndoe@theregistrar.com")
.setLockCompletionTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.build();
fakeClock.advanceOneMilli();
clock.advanceOneMilli();
RegistryLock adminLock =
new RegistryLock.Builder()
.setRepoId("repoId")
@@ -171,7 +160,7 @@ public class ConsoleRegistryLockActionTest {
.setRegistrarId("TheRegistrar")
.setVerificationCode("122222222ABCDEFGHJKLMNPQRSTUVWXY")
.isSuperuser(true)
.setLockCompletionTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.build();
RegistryLock incompleteLock =
new RegistryLock.Builder()
@@ -189,8 +178,8 @@ public class ConsoleRegistryLockActionTest {
.setRegistrarId("TheRegistrar")
.setVerificationCode("123456789ABCDEFGHJKLMNPQRSTUVWXY")
.setRegistrarPocId("johndoe@theregistrar.com")
.setLockCompletionTime(fakeClock.nowUtc())
.setUnlockRequestTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.setUnlockRequestTime(clock.nowUtc())
.build();
RegistryLock unlockedLock =
@@ -200,9 +189,9 @@ public class ConsoleRegistryLockActionTest {
.setRegistrarId("TheRegistrar")
.setRegistrarPocId("johndoe@theregistrar.com")
.setVerificationCode("123456789ABCDEFGHJKLMNPQRSTUUUUU")
.setLockCompletionTime(fakeClock.nowUtc())
.setUnlockRequestTime(fakeClock.nowUtc())
.setUnlockCompletionTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.setUnlockRequestTime(clock.nowUtc())
.setUnlockCompletionTime(clock.nowUtc())
.build();
saveRegistryLock(regularLock);
@@ -218,24 +207,24 @@ public class ConsoleRegistryLockActionTest {
assertThat(response.getPayload())
.isEqualTo(
"""
[{"domainName":"adminexample.test","lockRequestTime":{"creationTime":"2024-04-19T12:00:00.001Z"},\
"unlockRequestTime":"null","lockCompletionTime":"2024-04-19T12:00:00.001Z","unlockCompletionTime":\
[{"domainName":"adminexample.test","lockRequestTime":{"creationTime":"2024-04-16T00:00:00.001Z"},\
"unlockRequestTime":"null","lockCompletionTime":"2024-04-16T00:00:00.001Z","unlockCompletionTime":\
"null","isSuperuser":true},\
\
{"domainName":"example.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":\
"2024-04-19T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
{"creationTime":"2024-04-16T00:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":\
"2024-04-16T00:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
\
{"domainName":"expiredunlock.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
{"creationTime":"2024-04-18T12:00:00.000Z"},"unlockRequestTime":"2024-04-18T12:00:00.000Z",\
"lockCompletionTime":"2024-04-18T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
{"creationTime":"2024-04-15T00:00:00.000Z"},"unlockRequestTime":"2024-04-15T00:00:00.000Z",\
"lockCompletionTime":"2024-04-15T00:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
\
{"domainName":"incompleteunlock.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"2024-04-19T12:00:00.001Z",\
"lockCompletionTime":"2024-04-19T12:00:00.001Z","unlockCompletionTime":"null","isSuperuser":false},\
{"creationTime":"2024-04-16T00:00:00.001Z"},"unlockRequestTime":"2024-04-16T00:00:00.001Z",\
"lockCompletionTime":"2024-04-16T00:00:00.001Z","unlockCompletionTime":"null","isSuperuser":false},\
\
{"domainName":"pending.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":"null",\
{"creationTime":"2024-04-16T00:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":"null",\
"unlockCompletionTime":"null","isSuperuser":false}]""");
}
@@ -288,7 +277,7 @@ public class ConsoleRegistryLockActionTest {
@Test
void testPost_unlock() throws Exception {
saveRegistryLock(createDefaultLockBuilder().setLockCompletionTime(fakeClock.nowUtc()).build());
saveRegistryLock(createDefaultLockBuilder().setLockCompletionTime(clock.nowUtc()).build());
persistResource(defaultDomain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
action = createDefaultPostAction(false);
action.run();
@@ -301,7 +290,7 @@ public class ConsoleRegistryLockActionTest {
@Test
void testPost_unlock_relockDuration() throws Exception {
saveRegistryLock(createDefaultLockBuilder().setLockCompletionTime(fakeClock.nowUtc()).build());
saveRegistryLock(createDefaultLockBuilder().setLockCompletionTime(clock.nowUtc()).build());
persistResource(defaultDomain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
action =
createPostAction(
@@ -318,10 +307,7 @@ public class ConsoleRegistryLockActionTest {
@Test
void testPost_adminUnlockingAdmin() throws Exception {
saveRegistryLock(
createDefaultLockBuilder()
.setLockCompletionTime(fakeClock.nowUtc())
.isSuperuser(true)
.build());
createDefaultLockBuilder().setLockCompletionTime(clock.nowUtc()).isSuperuser(true).build());
persistResource(defaultDomain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
user =
user.asBuilder()
@@ -387,10 +373,7 @@ public class ConsoleRegistryLockActionTest {
@Test
void testPost_failure_nonAdminUnlockingAdmin() throws Exception {
saveRegistryLock(
createDefaultLockBuilder()
.setLockCompletionTime(fakeClock.nowUtc())
.isSuperuser(true)
.build());
createDefaultLockBuilder().setLockCompletionTime(clock.nowUtc()).isSuperuser(true).build());
persistResource(defaultDomain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
action = createDefaultPostAction(false);
action.run();
@@ -464,9 +447,9 @@ public class ConsoleRegistryLockActionTest {
void testPost_failure_alreadyUnlocked() throws Exception {
saveRegistryLock(
createDefaultLockBuilder()
.setLockCompletionTime(fakeClock.nowUtc())
.setUnlockRequestTime(fakeClock.nowUtc())
.setUnlockCompletionTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.setUnlockRequestTime(clock.nowUtc())
.setUnlockCompletionTime(clock.nowUtc())
.build());
action = createDefaultPostAction(false);
action.run();
@@ -501,7 +484,7 @@ public class ConsoleRegistryLockActionTest {
new DomainLockUtils(
new DeterministicStringGenerator(StringGenerator.Alphabets.BASE_58),
"adminreg",
new CloudTasksHelper(fakeClock).getTestCloudTasksUtils());
new CloudTasksHelper(clock).getTestCloudTasksUtils());
response = (FakeResponse) params.response();
return new ConsoleRegistryLockAction(
params, domainLockUtils, gmailClient, optionalPostInput, "TheRegistrar");
@@ -30,12 +30,10 @@ import google.registry.model.console.UserRoles;
import google.registry.model.domain.Domain;
import google.registry.model.domain.RegistryLock;
import google.registry.model.eppcommon.StatusValue;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.auth.AuthResult;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.tools.DomainLockUtils;
import google.registry.util.StringGenerator;
@@ -43,19 +41,11 @@ import jakarta.servlet.http.HttpServletResponse;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link ConsoleRegistryLockVerifyAction}. */
public class ConsoleRegistryLockVerifyActionTest {
public class ConsoleRegistryLockVerifyActionTest extends ConsoleActionBaseTestCase {
private static final String DEFAULT_CODE = "123456789ABCDEFGHJKLMNPQRSTUUUUU";
private final FakeClock fakeClock = new FakeClock();
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(fakeClock).buildIntegrationTestExtension();
private FakeResponse response;
private Domain defaultDomain;
private User user;
@@ -96,8 +86,8 @@ public class ConsoleRegistryLockVerifyActionTest {
persistResource(defaultDomain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
saveRegistryLock(
createDefaultLockBuilder()
.setLockCompletionTime(fakeClock.nowUtc())
.setUnlockRequestTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.setUnlockRequestTime(clock.nowUtc())
.build());
action.run();
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
@@ -130,8 +120,8 @@ public class ConsoleRegistryLockVerifyActionTest {
saveRegistryLock(
createDefaultLockBuilder()
.isSuperuser(true)
.setLockCompletionTime(fakeClock.nowUtc())
.setUnlockRequestTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.setUnlockRequestTime(clock.nowUtc())
.build());
user =
user.asBuilder()
@@ -159,7 +149,7 @@ public class ConsoleRegistryLockVerifyActionTest {
@Test
void testFailure_expiredLock() {
saveRegistryLock(createDefaultLockBuilder().build());
fakeClock.advanceBy(Duration.standardDays(1));
clock.advanceBy(Duration.standardDays(1));
action.run();
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("The pending lock has expired; please try again");
@@ -181,8 +171,8 @@ public class ConsoleRegistryLockVerifyActionTest {
saveRegistryLock(
createDefaultLockBuilder()
.isSuperuser(true)
.setLockCompletionTime(fakeClock.nowUtc())
.setUnlockRequestTime(fakeClock.nowUtc())
.setLockCompletionTime(clock.nowUtc())
.setUnlockRequestTime(clock.nowUtc())
.build());
action.run();
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST);
@@ -209,7 +199,7 @@ public class ConsoleRegistryLockVerifyActionTest {
new DomainLockUtils(
new DeterministicStringGenerator(StringGenerator.Alphabets.BASE_58),
"adminreg",
new CloudTasksHelper(fakeClock).getTestCloudTasksUtils());
new CloudTasksHelper(clock).getTestCloudTasksUtils());
response = (FakeResponse) params.response();
return new ConsoleRegistryLockVerifyAction(params, domainLockUtils, verificationCode);
}
@@ -28,21 +28,17 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.FakeResponse;
import google.registry.testing.SystemPropertyExtension;
import google.registry.tools.GsonUtils;
import google.registry.util.EmailMessage;
import google.registry.util.RegistryEnvironment;
import jakarta.mail.internet.AddressException;
@@ -51,17 +47,14 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.ConsoleUpdateRegistrarAction}. */
class ConsoleUpdateRegistrarActionTest {
private static final Gson GSON = GsonUtils.provideGson();
private ConsoleApiParams consoleApiParams;
private FakeResponse response;
class ConsoleUpdateRegistrarActionTest extends ConsoleActionBaseTestCase {
private Registrar registrar;
@@ -92,13 +85,8 @@ class ConsoleUpdateRegistrarActionTest {
.setEmailAddress("user@registrarId.com")
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build());
consoleApiParams = createParams();
}
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@Test
void testSuccess_updatesRegistrar() throws IOException {
var action =
@@ -108,17 +96,44 @@ class ConsoleUpdateRegistrarActionTest {
"TheRegistrar",
"app, dev",
false,
"\"2025-01-01T00:00:00.000Z\""));
"\"2023-12-12T00:00:00.000Z\""));
action.run();
Registrar newRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get();
assertThat(newRegistrar.getAllowedTlds()).containsExactly("app", "dev");
assertThat(newRegistrar.isRegistryLockAllowed()).isFalse();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE);
assertThat(history.getDescription()).hasValue("TheRegistrar");
}
@Test
void testSuccess_updatesNullPocVerificationDate() throws IOException {
var action =
createAction(
String.format(registrarPostData, "TheRegistrar", "app, dev", false, "\"null\""));
action.run();
Registrar newRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get();
assertThat(newRegistrar.getLastPocVerificationDate())
.isEqualTo(DateTime.parse("1970-01-01T00:00:00.000Z"));
}
@Test
void testFailure_pocVerificationInTheFuture() throws IOException {
var action =
createAction(
String.format(
registrarPostData,
"TheRegistrar",
"app, dev",
false,
"\"2025-02-01T00:00:00.000Z\""));
action.run();
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat((String) response.getPayload())
.contains("Invalid value of LastPocVerificationDate - value is in the future");
}
@Test
void testFails_missingWhoisContact() throws IOException {
RegistryEnvironment.PRODUCTION.setup(systemPropertyExtension);
@@ -129,10 +144,10 @@ class ConsoleUpdateRegistrarActionTest {
"TheRegistrar",
"app, dev",
false,
"\"2025-01-01T00:00:00.000Z\""));
"\"2024-12-12T00:00:00.000Z\""));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat((String) ((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat((String) response.getPayload())
.contains("Cannot modify allowed TLDs if there is no WHOIS abuse contact set");
}
@@ -159,12 +174,12 @@ class ConsoleUpdateRegistrarActionTest {
"TheRegistrar",
"app, dev",
false,
"\"2025-01-01T00:00:00.000Z\""));
"\"2023-12-12T00:00:00.000Z\""));
action.run();
Registrar newRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get();
assertThat(newRegistrar.getAllowedTlds()).containsExactly("app", "dev");
assertThat(newRegistrar.isRegistryLockAllowed()).isFalse();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
}
@Test
@@ -176,7 +191,7 @@ class ConsoleUpdateRegistrarActionTest {
"TheRegistrar",
"app, dev",
false,
"\"2025-01-01T00:00:00.000Z\""));
"\"2023-12-12T00:00:00.000Z\""));
action.run();
verify(consoleApiParams.sendEmailUtils().gmailClient, times(1))
.sendEmail(
@@ -186,11 +201,11 @@ class ConsoleUpdateRegistrarActionTest {
+ " environment")
.setBody(
"The following changes were made in registry unittest environment to the"
+ " registrar TheRegistrar by user user@registrarId.com:\n"
+ " registrar TheRegistrar by admin fte@email.tld:\n"
+ "\n"
+ "allowedTlds: null -> [app, dev]\n"
+ "lastPocVerificationDate: 1970-01-01T00:00:00.000Z ->"
+ " 2025-01-01T00:00:00.000Z\n")
+ " 2023-12-12T00:00:00.000Z\n")
.setRecipients(ImmutableList.of(new InternetAddress("notification@test.example")))
.build());
}
@@ -21,13 +21,8 @@ import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import google.registry.model.console.User;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeResponse;
import jakarta.servlet.http.Cookie;
import java.io.IOException;
@@ -35,41 +30,25 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.ConsoleUserDataAction}. */
class ConsoleUserDataActionTest {
private static final Gson GSON = RequestModule.provideGson();
private ConsoleApiParams consoleApiParams;
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
class ConsoleUserDataActionTest extends ConsoleActionBaseTestCase {
@Test
void testSuccess_hasXSRFCookie() throws IOException {
User user = DatabaseHelper.createAdminUser("email@email.com");
AuthResult authResult = AuthResult.createUser(user);
ConsoleUserDataAction action =
createAction(Optional.of(ConsoleApiParamsUtils.createFake(authResult)));
ConsoleUserDataAction action = createAction(Optional.of(consoleApiParams));
action.run();
List<Cookie> cookies = ((FakeResponse) consoleApiParams.response()).getCookies();
List<Cookie> cookies = response.getCookies();
assertThat(cookies.stream().map(cookie -> cookie.getName()).collect(toImmutableList()))
.containsExactly("X-CSRF-Token");
}
@Test
void testSuccess_getContactInfo() throws IOException {
User user = DatabaseHelper.createAdminUser("email@email.com");
AuthResult authResult = AuthResult.createUser(user);
ConsoleUserDataAction action =
createAction(Optional.of(ConsoleApiParamsUtils.createFake(authResult)));
ConsoleUserDataAction action = createAction(Optional.of(consoleApiParams));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
Map jsonObject =
GSON.fromJson(((FakeResponse) consoleApiParams.response()).getPayload(), Map.class);
assertThat(response.getStatus()).isEqualTo(SC_OK);
Map jsonObject = GSON.fromJson(response.getPayload(), Map.class);
assertThat(jsonObject)
.containsExactly(
"userRoles",
@@ -92,7 +71,7 @@ class ConsoleUserDataActionTest {
void testFailure_notAuthenticated() throws IOException {
ConsoleUserDataAction action = createAction(Optional.empty());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_UNAUTHORIZED);
assertThat(response.getStatus()).isEqualTo(SC_UNAUTHORIZED);
}
private ConsoleUserDataAction createAction(Optional<ConsoleApiParams> maybeConsoleApiParams)
@@ -101,6 +80,7 @@ class ConsoleUserDataActionTest {
maybeConsoleApiParams.orElseGet(
() -> ConsoleApiParamsUtils.createFake(AuthResult.NOT_AUTHENTICATED));
when(consoleApiParams.request().getMethod()).thenReturn("GET");
response = (FakeResponse) consoleApiParams.response();
return new ConsoleUserDataAction(
consoleApiParams, "Nomulus", "support@example.com", "+1 (212) 867 5309", "test");
}
@@ -29,14 +29,11 @@ import com.google.api.services.directory.Directory.Users.Delete;
import com.google.api.services.directory.Directory.Users.Insert;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.ConsoleApiParamsUtils;
@@ -53,11 +50,8 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class ConsoleUsersActionTest {
private static final Gson GSON = RequestModule.provideGson();
class ConsoleUsersActionTest extends ConsoleActionBaseTestCase {
private final Directory directory = mock(Directory.class);
private final Users users = mock(Users.class);
@@ -70,12 +64,6 @@ class ConsoleUsersActionTest {
private StringGenerator passwordGenerator =
new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
private ConsoleApiParams consoleApiParams;
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@BeforeEach
void beforeEach() {
User dbUser1 =
@@ -130,7 +118,6 @@ class ConsoleUsersActionTest {
Optional.of("GET"),
Optional.empty());
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getPayload())
.isEqualTo(
"[{\"emailAddress\":\"test1@test.com\",\"role\":\"PRIMARY_CONTACT\"},{\"emailAddress\":\"test2@test.com\",\"role\":\"PRIMARY_CONTACT\"}]");
@@ -155,7 +142,6 @@ class ConsoleUsersActionTest {
Optional.of("GET"),
Optional.empty());
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@@ -172,7 +158,6 @@ class ConsoleUsersActionTest {
when(directory.users()).thenReturn(users);
when(users.insert(any(com.google.api.services.directory.model.User.class))).thenReturn(insert);
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).contains("Email prefix is invalid");
}
@@ -190,7 +175,6 @@ class ConsoleUsersActionTest {
when(directory.users()).thenReturn(users);
when(users.insert(any(com.google.api.services.directory.model.User.class))).thenReturn(insert);
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_CREATED);
assertThat(response.getPayload())
.contains(
@@ -215,7 +199,6 @@ class ConsoleUsersActionTest {
when(directory.users()).thenReturn(users);
when(users.delete(any(String.class))).thenReturn(delete);
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getPayload())
.contains("Can't update user not associated with registrarId TheRegistrar");
@@ -234,7 +217,6 @@ class ConsoleUsersActionTest {
when(directory.users()).thenReturn(users);
when(users.delete(any(String.class))).thenReturn(delete);
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).contains("User email-1@email.com doesn't exist");
}
@@ -258,7 +240,6 @@ class ConsoleUsersActionTest {
when(directory.users()).thenReturn(users);
when(users.delete(any(String.class))).thenReturn(delete);
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(DatabaseHelper.loadByKeyIfPresent(VKey.create(User.class, "test2@test.com")))
.isEmpty();
@@ -299,7 +280,6 @@ class ConsoleUsersActionTest {
when(directory.users()).thenReturn(users);
when(users.delete(any(String.class))).thenReturn(delete);
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_OK);
Optional<User> actualUser =
DatabaseHelper.loadByKeyIfPresent(VKey.create(User.class, "test4@test.com"));
@@ -343,7 +323,6 @@ class ConsoleUsersActionTest {
when(directory.users()).thenReturn(users);
when(users.insert(any(com.google.api.services.directory.model.User.class))).thenReturn(insert);
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).contains("Total users amount per registrar is limited to 4");
}
@@ -372,7 +351,6 @@ class ConsoleUsersActionTest {
new UserData("test2@test.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null)));
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(
DatabaseHelper.loadByKey(VKey.create(User.class, "test2@test.com"))
@@ -398,7 +376,6 @@ class ConsoleUsersActionTest {
Optional.of(
new UserData("test3@test.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null)));
action.run();
var response = ((FakeResponse) consoleApiParams.response());
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getPayload())
.contains("Can't update user not associated with registrarId TheRegistrar");
@@ -413,6 +390,7 @@ class ConsoleUsersActionTest {
maybeConsoleApiParams.orElseGet(
() -> ConsoleApiParamsUtils.createFake(AuthResult.NOT_AUTHENTICATED));
when(consoleApiParams.request().getMethod()).thenReturn(method.orElse("GET"));
response = (FakeResponse) consoleApiParams.response();
return new ConsoleUsersAction(
consoleApiParams,
directory,
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.RegistrarRole;
@@ -36,7 +35,6 @@ import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
@@ -51,13 +49,9 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.RegistrarsAction}. */
class RegistrarsActionTest {
private static final Gson GSON = RequestModule.provideGson();
private ConsoleApiParams consoleApiParams;
class RegistrarsActionTest extends ConsoleActionBaseTestCase {
private StringGenerator passwordGenerator =
new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
@@ -94,10 +88,6 @@ class RegistrarsActionTest {
"{ \"street\": [\"test street\"], \"city\": \"test city\", \"state\": \"test state\","
+ " \"zip\": \"00700\", \"countryCode\": \"US\" }");
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@Test
void testSuccess_onlyRealAndOteRegistrars() {
Registrar registrar = persistNewRegistrar("registrarId");
@@ -115,8 +105,8 @@ class RegistrarsActionTest {
createUser(
new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_LEAD).build())));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
String payload = ((FakeResponse) consoleApiParams.response()).getPayload();
assertThat(response.getStatus()).isEqualTo(SC_OK);
String payload = response.getPayload();
var actualRegistrarIds =
ImmutableList.copyOf(GSON.fromJson(payload, Registrar[].class)).stream()
@@ -135,8 +125,8 @@ class RegistrarsActionTest {
AuthResult.createUser(
createUser(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
String payload = ((FakeResponse) consoleApiParams.response()).getPayload();
assertThat(response.getStatus()).isEqualTo(SC_OK);
String payload = response.getPayload();
assertThat(
ImmutableList.of(
"\"registrarId\":\"NewRegistrar\"",
@@ -162,8 +152,8 @@ class RegistrarsActionTest {
.build())));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
String payload = ((FakeResponse) consoleApiParams.response()).getPayload();
assertThat(response.getStatus()).isEqualTo(SC_OK);
String payload = response.getPayload();
Registrar[] registrars = GSON.fromJson(payload, Registrar[].class);
assertThat(registrars).hasLength(1);
assertThat(registrars[0].getRegistrarId()).isEqualTo("registrarId");
@@ -171,12 +161,9 @@ class RegistrarsActionTest {
@Test
void testSuccess_createRegistrar() {
RegistrarsAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createUser(new UserRoles.Builder().setIsAdmin(true).build())));
RegistrarsAction action = createAction(Action.Method.POST, AuthResult.createUser(fteUser));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
Registrar r = loadRegistrar("regIdTest");
assertThat(r).isNotNull();
assertThat(
@@ -202,14 +189,10 @@ class RegistrarsActionTest {
.filter(entry -> !entry.getKey().equals(key))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
RegistrarsAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(
createUser(new UserRoles.Builder().setIsAdmin(true).build())));
createAction(Action.Method.POST, AuthResult.createUser(fteUser));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus())
.isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo(
String.format(
"Missing value for %s", userFriendlyKeysToRegistrarKeys.get(key)));
@@ -219,13 +202,10 @@ class RegistrarsActionTest {
@Test
void testFailure_createRegistrar_existingRegistrar() {
saveRegistrar("regIdTest");
RegistrarsAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createUser(new UserRoles.Builder().setIsAdmin(true).build())));
RegistrarsAction action = createAction(Action.Method.POST, AuthResult.createUser(fteUser));
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Registrar with registrarId regIdTest already exists");
}
@@ -237,6 +217,7 @@ class RegistrarsActionTest {
private RegistrarsAction createAction(Action.Method method, AuthResult authResult) {
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
response = (FakeResponse) consoleApiParams.response();
if (method.equals(Action.Method.GET)) {
return new RegistrarsAction(
consoleApiParams, Optional.ofNullable(null), passwordGenerator, passcodeGenerator);
@@ -17,7 +17,6 @@ package google.registry.ui.server.console.domains;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.DatabaseHelper.loadSingleton;
import static google.registry.testing.DatabaseHelper.persistActiveContact;
@@ -33,36 +32,28 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import google.registry.flows.DaggerEppTestComponent;
import google.registry.flows.EppController;
import google.registry.flows.EppTestComponent;
import google.registry.model.common.FeatureFlag;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.domain.Domain;
import google.registry.model.eppcommon.StatusValue;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.tools.GsonUtils;
import google.registry.ui.server.console.ConsoleActionBaseTestCase;
import google.registry.ui.server.console.ConsoleApiParams;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link ConsoleBulkDomainAction}. */
public class ConsoleBulkDomainActionTest {
private static final Gson GSON = GsonUtils.provideGson();
public class ConsoleBulkDomainActionTest extends ConsoleActionBaseTestCase {
private static ImmutableSet<StatusValue> serverSuspensionStatuses =
ImmutableSet.of(
@@ -72,14 +63,7 @@ public class ConsoleBulkDomainActionTest {
StatusValue.SERVER_DELETE_PROHIBITED,
StatusValue.SERVER_HOLD);
private final FakeClock clock = new FakeClock(DateTime.parse("2024-05-13T00:00:00.000Z"));
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
private EppController eppController;
private FakeResponse fakeResponse;
private Domain domain;
@BeforeEach
@@ -96,7 +80,6 @@ public class ConsoleBulkDomainActionTest {
.build()
.startRequest()
.eppController();
createTld("tld");
domain =
persistDomainWithDependentResources(
"example",
@@ -115,8 +98,8 @@ public class ConsoleBulkDomainActionTest {
GSON.toJsonTree(
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")));
action.run();
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
assertThat(fakeResponse.getPayload())
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload())
.isEqualTo(
"""
{"example.tld":{"message":"Command completed successfully; action pending",\
@@ -129,22 +112,14 @@ public class ConsoleBulkDomainActionTest {
@Test
void testSuccess_suspend() throws Exception {
User adminUser =
persistResource(
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(
new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).setIsAdmin(true).build())
.build());
ConsoleBulkDomainAction action =
createAction(
"SUSPEND",
GSON.toJsonTree(
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")),
adminUser);
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")));
action.run();
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
assertThat(fakeResponse.getPayload())
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload())
.isEqualTo(
"""
{"example.tld":{"message":"Command completed successfully","responseCode":1000}}""");
@@ -157,25 +132,17 @@ public class ConsoleBulkDomainActionTest {
@Test
void testSuccess_unsuspend() throws Exception {
User adminUser =
persistResource(
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(
new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).setIsAdmin(true).build())
.build());
persistResource(domain.asBuilder().addStatusValues(serverSuspensionStatuses).build());
ConsoleBulkDomainAction action =
createAction(
"UNSUSPEND",
GSON.toJsonTree(
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")),
adminUser);
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")));
assertThat(loadByEntity(domain).getStatusValues())
.containsAtLeastElementsIn(serverSuspensionStatuses);
action.run();
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
assertThat(fakeResponse.getPayload())
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload())
.isEqualTo(
"""
{"example.tld":{"message":"Command completed successfully","responseCode":1000}}""");
@@ -197,8 +164,8 @@ public class ConsoleBulkDomainActionTest {
"reason",
"test")));
action.run();
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
assertThat(fakeResponse.getPayload())
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload())
.isEqualTo(
"""
{"example.tld":{"message":"Command completed successfully; action pending","responseCode":1001},\
@@ -214,8 +181,8 @@ public class ConsoleBulkDomainActionTest {
void testFailure_badActionString() {
ConsoleBulkDomainAction action = createAction("bad", GSON.toJsonTree(ImmutableMap.of()));
action.run();
assertThat(fakeResponse.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(fakeResponse.getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo(
"No enum constant"
+ " google.registry.ui.server.console.domains.ConsoleDomainActionType.BulkAction.bad");
@@ -225,8 +192,8 @@ public class ConsoleBulkDomainActionTest {
void testFailure_emptyBody() {
ConsoleBulkDomainAction action = createAction("DELETE", null);
action.run();
assertThat(fakeResponse.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(fakeResponse.getPayload()).isEqualTo("Bulk action payload must be present");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("Bulk action payload must be present");
}
@Test
@@ -247,7 +214,7 @@ public class ConsoleBulkDomainActionTest {
.build())
.build());
action.run();
assertThat(fakeResponse.getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
// @ptkach - reenable with suspend change
@@ -271,21 +238,14 @@ public class ConsoleBulkDomainActionTest {
// }
private ConsoleBulkDomainAction createAction(String action, JsonElement payload) {
User user =
persistResource(
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(
new UserRoles.Builder().setIsAdmin(true).setGlobalRole(GlobalRole.FTE).build())
.build());
return createAction(action, payload, user);
return createAction(action, payload, fteUser);
}
private ConsoleBulkDomainAction createAction(String action, JsonElement payload, User user) {
AuthResult authResult = AuthResult.createUser(user);
ConsoleApiParams params = ConsoleApiParamsUtils.createFake(authResult);
when(params.request().getMethod()).thenReturn("POST");
fakeResponse = (FakeResponse) params.response();
response = (FakeResponse) params.response();
return new ConsoleBulkDomainAction(
params, eppController, "TheRegistrar", action, Optional.ofNullable(payload));
}
@@ -20,9 +20,10 @@ import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.MARKETING;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
import static google.registry.testing.DatabaseHelper.createAdminUser;
import static google.registry.testing.DatabaseHelper.deleteResource;
import static google.registry.testing.DatabaseHelper.insertInDb;
import static google.registry.testing.DatabaseHelper.loadAllOf;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
@@ -36,19 +37,16 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.FakeResponse;
import google.registry.ui.server.console.ConsoleApiParams;
import google.registry.ui.server.console.ConsoleActionBaseTestCase;
import google.registry.util.EmailMessage;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
@@ -57,12 +55,11 @@ import java.util.HashMap;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.settings.ContactAction}. */
class ContactActionTest {
class ContactActionTest extends ConsoleActionBaseTestCase {
private static String jsonRegistrar1 =
"{\"name\":\"Test Registrar 1\","
"{\"id\":%s,\"name\":\"Test Registrar 1\","
+ "\"emailAddress\":\"test.registrar1@example.com\","
+ "\"registrarId\":\"registrarId\","
+ "\"phoneNumber\":\"+1.9999999999\",\"faxNumber\":\"+1.9999999991\","
@@ -70,32 +67,26 @@ class ContactActionTest {
+ "\"visibleInWhoisAsTech\":false,\"visibleInDomainWhoisAsAbuse\":false}";
private Registrar testRegistrar;
private ConsoleApiParams consoleApiParams;
private RegistrarPoc adminPoc;
private RegistrarPoc techPoc;
private RegistrarPoc marketingPoc;
private static final Gson GSON = RequestModule.provideGson();
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@BeforeEach
void beforeEach() {
testRegistrar = saveRegistrar("registrarId");
adminPoc =
new RegistrarPoc.Builder()
.setRegistrar(testRegistrar)
.setName("Test Registrar 1")
.setEmailAddress("test.registrar1@example.com")
.setPhoneNumber("+1.9999999999")
.setFaxNumber("+1.9999999991")
.setTypes(ImmutableSet.of(ADMIN))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build();
persistResource(
new RegistrarPoc.Builder()
.setRegistrar(testRegistrar)
.setName("Test Registrar 1")
.setEmailAddress("test.registrar1@example.com")
.setPhoneNumber("+1.9999999999")
.setFaxNumber("+1.9999999991")
.setTypes(ImmutableSet.of(ADMIN))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build());
techPoc =
adminPoc
.asBuilder()
@@ -121,58 +112,28 @@ class ContactActionTest {
@Test
void testSuccess_getContactInfo() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.GET,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId());
createAction(Action.Method.GET, fteUser, testRegistrar.getRegistrarId(), null);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("[" + jsonRegistrar1 + "]");
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(response.getPayload()).contains(String.format(jsonRegistrar1, adminPoc.getId()));
}
@Test
void testSuccess_noOp() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
adminPoc);
createAction(Action.Method.PUT, fteUser, testRegistrar.getRegistrarId(), adminPoc);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
verify(consoleApiParams.sendEmailUtils().gmailClient, never()).sendEmail(any());
}
@Test
void testSuccess_onlyContactsWithNonEmptyType() throws IOException {
adminPoc = adminPoc.asBuilder().setTypes(ImmutableSet.of()).build();
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.GET,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload()).isEqualTo("[]");
}
@Test
void testSuccess_postCreateContactInfo() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
adminPoc,
techPoc);
createAction(Action.Method.POST, fteUser, testRegistrar.getRegistrarId(), techPoc);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
@@ -183,16 +144,16 @@ class ContactActionTest {
@Test
void testSuccess_postUpdateContactInfo() throws IOException {
insertInDb(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
RegistrarPoc techPocIncorrect =
persistResource(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc,
techPoc);
techPocIncorrect.asBuilder().setEmailAddress(techPoc.getEmailAddress()).build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
HashMap<String, String> testResult = new HashMap<>();
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
@@ -207,38 +168,37 @@ class ContactActionTest {
@Test
void testFailure_postUpdateContactInfo_duplicateEmails() throws IOException {
insertInDb(techPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
fteUser,
testRegistrar.getRegistrarId(),
adminPoc,
techPoc.asBuilder().setEmailAddress("test.registrar1@example.com").build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo(
"One email address (test.registrar1@example.com) cannot be used for multiple contacts");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.map(r -> r.getName())
.collect(toImmutableList()))
.isEmpty();
.containsExactly("Test Registrar 1", "Test Registrar 2");
}
@Test
void testFailure_postUpdateContactInfo_requiredContactRemoved() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setTypes(ImmutableSet.of(ABUSE)).build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("Must have at least one primary contact");
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("Must have at least one primary contact");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
@@ -248,12 +208,11 @@ class ContactActionTest {
@Test
void testFailure_postUpdateContactInfo_phoneNumberRemoved() throws IOException {
adminPoc = adminPoc.asBuilder().setTypes(ImmutableSet.of(ADMIN, TECH)).build();
insertInDb(adminPoc);
adminPoc = persistResource(adminPoc.asBuilder().setTypes(ImmutableSet.of(ADMIN, TECH)).build());
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc
.asBuilder()
@@ -261,8 +220,8 @@ class ContactActionTest {
.setTypes(ImmutableSet.of(ADMIN, TECH))
.build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Please provide a phone number for at least one technical contact");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
@@ -276,33 +235,27 @@ class ContactActionTest {
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setPhoneNumber(null).setVisibleInDomainWhoisAsAbuse(true).build());
techPoc.asBuilder().setPhoneNumber(null).setVisibleInDomainWhoisAsAbuse(true).build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("The abuse contact visible in domain WHOIS query must have a phone number");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.isEmpty();
}
@Test
void testFailure_postUpdateContactInfo_whoisContactPhoneNumberRemoved() throws IOException {
adminPoc = adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(true).build();
insertInDb(adminPoc);
adminPoc = persistResource(adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(true).build());
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(false).build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
assertThat(response.getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("An abuse contact visible in domain WHOIS query must be designated");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
@@ -311,94 +264,19 @@ class ContactActionTest {
.containsExactly(adminPoc);
}
@Test
void testFailure_postUpdateContactInfo_newContactCannotSetRegistryLockPassword()
throws IOException {
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
adminPoc
.asBuilder()
.setAllowedToSetRegistryLockPassword(true)
.setRegistryLockEmailAddress("lock@example.com")
.build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("Cannot set registry lock password directly on new contact");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.isEmpty();
}
@Test
void testFailure_postUpdateContactInfo_cannotModifyRegistryLockEmail() throws IOException {
adminPoc =
adminPoc
.asBuilder()
.setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(true)
.build();
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setRegistryLockEmailAddress("unlock@example.com").build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("Cannot modify registryLockEmailAddress through the UI");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.containsExactly(adminPoc);
}
@Test
void testFailure_postUpdateContactInfo_cannotSetIsAllowedToSetRegistryLockPassword()
throws IOException {
adminPoc =
adminPoc
.asBuilder()
.setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(false)
.build();
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setAllowedToSetRegistryLockPassword(true).build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
.isEqualTo("Cannot modify isAllowedToSetRegistryLockPassword through the UI");
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.containsExactly(adminPoc);
}
@Test
void testSuccess_sendsEmail() throws IOException, AddressException {
insertInDb(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
deleteResource(adminPoc);
techPoc = persistResource(techPoc);
Long id = techPoc.getId();
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
techPoc);
techPoc.asBuilder().setEmailAddress("incorrect@example.com").build());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
verify(consoleApiParams.sendEmailUtils().gmailClient, times(1))
.sendEmail(
EmailMessage.newBuilder()
@@ -407,27 +285,33 @@ class ContactActionTest {
+ " environment")
.setBody(
"The following changes were made in registry unittest environment to the"
+ " registrar registrarId by admin email@email.com:\n"
+ " registrar registrarId by admin fte@email.tld:\n"
+ "\n"
+ "contacts:\n"
+ " ADDED:\n"
+ " {name=Test Registrar 2,"
+ " emailAddress=test.registrar2@example.com, registrarId=registrarId,"
+ " {id="
+ id
+ ", name=Test Registrar 2,"
+ " emailAddress=incorrect@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.1234567890,"
+ " faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=true,"
+ " visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n"
+ " REMOVED:\n"
+ " {name=Test Registrar 2, emailAddress=incorrect@email.com,"
+ " {id="
+ id
+ ", name=Test Registrar 2, emailAddress=test.registrar2@example.com,"
+ " registrarId=registrarId, registryLockEmailAddress=null,"
+ " phoneNumber=+1.1234567890, faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=false,"
+ " visibleInWhoisAsTech=true, visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n"
+ " FINAL CONTENTS:\n"
+ " {name=Test Registrar 2,"
+ " emailAddress=test.registrar2@example.com, registrarId=registrarId,"
+ " {id="
+ id
+ ", name=Test Registrar 2,"
+ " emailAddress=incorrect@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.1234567890,"
+ " faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=true,"
@@ -439,16 +323,11 @@ class ContactActionTest {
@Test
void testSuccess_postDeleteContactInfo() throws IOException {
insertInDb(adminPoc, techPoc, marketingPoc);
insertInDb(techPoc, marketingPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
adminPoc,
techPoc);
createAction(Action.Method.DELETE, fteUser, testRegistrar.getRegistrarId(), marketingPoc);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
assertThat(
loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
@@ -459,52 +338,48 @@ class ContactActionTest {
@Test
void testFailure_postDeleteContactInfo_missingPermission() throws IOException {
insertInDb(adminPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(
new UserRoles.Builder()
.setRegistrarRoles(
ImmutableMap.of(
testRegistrar.getRegistrarId(), RegistrarRole.ACCOUNT_MANAGER))
.build())
.build()),
Action.Method.DELETE,
new User.Builder()
.setEmailAddress("email@email.com")
.setUserRoles(
new UserRoles.Builder()
.setRegistrarRoles(
ImmutableMap.of(
testRegistrar.getRegistrarId(), RegistrarRole.ACCOUNT_MANAGER))
.build())
.build(),
testRegistrar.getRegistrarId(),
techPoc);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
@Test
void testFailure_changesAdminEmail() throws Exception {
insertInDb(adminPoc.asBuilder().setEmailAddress("oldemail@example.com").build());
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc);
adminPoc.asBuilder().setEmailAddress("testemail@example.com").build());
action.run();
FakeResponse fakeResponse = (FakeResponse) consoleApiParams.response();
FakeResponse fakeResponse = response;
assertThat(fakeResponse.getStatus()).isEqualTo(400);
assertThat(fakeResponse.getPayload())
.isEqualTo("Cannot remove or change the email address of primary contacts");
}
private ContactAction createAction(
Action.Method method, AuthResult authResult, String registrarId, RegistrarPoc... contacts)
Action.Method method, User user, String registrarId, RegistrarPoc contact)
throws IOException {
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
consoleApiParams = ConsoleApiParamsUtils.createFake(AuthResult.createUser(user));
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
response = (FakeResponse) consoleApiParams.response();
if (method.equals(Action.Method.GET)) {
return new ContactAction(consoleApiParams, registrarId, Optional.empty());
} else {
return new ContactAction(
consoleApiParams, registrarId, Optional.of(ImmutableSet.copyOf(contacts)));
}
return new ContactAction(consoleApiParams, registrarId, Optional.of(contact));
}
}
@@ -26,13 +26,11 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
@@ -40,24 +38,18 @@ import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.ui.server.console.ConsoleApiParams;
import google.registry.ui.server.console.ConsoleActionBaseTestCase;
import google.registry.ui.server.console.ConsoleModule;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link RdapRegistrarFieldsAction}. */
public class RdapRegistrarFieldsActionTest {
public class RdapRegistrarFieldsActionTest extends ConsoleActionBaseTestCase {
private ConsoleApiParams consoleApiParams;
private static final Gson GSON = RequestModule.provideGson();
private final FakeClock clock = new FakeClock(DateTime.parse("2023-08-01T00:00:00.000Z"));
private final AuthenticatedRegistrarAccessor registrarAccessor =
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of("TheRegistrar", Role.OWNER, "NewRegistrar", Role.OWNER));
@@ -81,10 +73,6 @@ public class RdapRegistrarFieldsActionTest {
"{\"street\": [\"123 Example Boulevard\"], \"city\": \"Williamsburg\", \"state\":"
+ " \"NY\", \"zip\": \"11201\", \"countryCode\": \"US\"}"));
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@Test
void testSuccess_setsAllFields() throws Exception {
Registrar oldRegistrar = Registrar.loadRequiredRegistrarCached("TheRegistrar");
@@ -113,7 +101,7 @@ public class RdapRegistrarFieldsActionTest {
+ " \"NL\", \"zip\": \"10011\", \"countryCode\": \"CA\"}"));
RdapRegistrarFieldsAction action = createAction();
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat(response.getStatus()).isEqualTo(SC_OK);
Registrar newRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get(); // skip cache
assertThat(newRegistrar.getLocalizedAddress().toJsonMap()).isEqualTo(addressMap);
assertThat(newRegistrar.getPhoneNumber()).isEqualTo("+1.4155552671");
@@ -130,34 +118,30 @@ public class RdapRegistrarFieldsActionTest {
@Test
void testFailure_noAccessToRegistrar() throws Exception {
Registrar newRegistrar = Registrar.loadByRegistrarIdCached("NewRegistrar").get();
AuthResult onlyTheRegistrar =
AuthResult.createUser(
new User.Builder()
.setEmailAddress("email@email.example")
.setUserRoles(
new UserRoles.Builder()
.setRegistrarRoles(
ImmutableMap.of("TheRegistrar", RegistrarRole.PRIMARY_CONTACT))
.build())
.build());
User onlyTheRegistrar =
new User.Builder()
.setEmailAddress("email@email.example")
.setUserRoles(
new UserRoles.Builder()
.setRegistrarRoles(
ImmutableMap.of("TheRegistrar", RegistrarRole.PRIMARY_CONTACT))
.build())
.build();
uiRegistrarMap.put("registrarId", "NewRegistrar");
RdapRegistrarFieldsAction action = createAction(onlyTheRegistrar);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
// should be no change
assertThat(DatabaseHelper.loadByEntity(newRegistrar)).isEqualTo(newRegistrar);
}
private AuthResult defaultUserAuth() {
return AuthResult.createUser(DatabaseHelper.createAdminUser("email@email.example"));
}
private RdapRegistrarFieldsAction createAction() throws IOException {
return createAction(defaultUserAuth());
return createAction(fteUser);
}
private RdapRegistrarFieldsAction createAction(AuthResult authResult) throws IOException {
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
private RdapRegistrarFieldsAction createAction(User user) throws IOException {
consoleApiParams = ConsoleApiParamsUtils.createFake(AuthResult.createUser(user));
response = (FakeResponse) consoleApiParams.response();
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.POST.toString());
doReturn(new BufferedReader(new StringReader(uiRegistrarMap.toString())))
.when(consoleApiParams.request())
@@ -27,20 +27,14 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.gson.Gson;
import google.registry.flows.certs.CertificateChecker;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.testing.ConsoleApiParamsUtils;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.ui.server.console.ConsoleApiParams;
import google.registry.ui.server.console.ConsoleActionBaseTestCase;
import google.registry.ui.server.console.ConsoleModule;
import java.io.BufferedReader;
import java.io.IOException;
@@ -49,19 +43,15 @@ import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.settings.SecurityAction}. */
class SecurityActionTest {
class SecurityActionTest extends ConsoleActionBaseTestCase {
private static String jsonRegistrar1 =
String.format(
"{\"registrarId\": \"registrarId\", \"clientCertificate\": \"%s\","
+ " \"ipAddressAllowList\": [\"192.168.1.1/32\"]}",
SAMPLE_CERT2);
private static final Gson GSON = RequestModule.provideGson();
private ConsoleApiParams consoleApiParams;
private final FakeClock clock = new FakeClock();
private Registrar testRegistrar;
private AuthenticatedRegistrarAccessor registrarAccessor =
@@ -77,10 +67,6 @@ class SecurityActionTest {
ImmutableSet.of("secp256r1", "secp384r1"),
clock);
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@BeforeEach
void beforeEach() {
testRegistrar = saveRegistrar("registrarId");
@@ -91,7 +77,6 @@ class SecurityActionTest {
clock.setTo(DateTime.parse("2020-11-01T00:00:00Z"));
SecurityAction action =
createAction(
AuthResult.createUser(DatabaseHelper.createAdminUser("email@email.com")),
testRegistrar.getRegistrarId());
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
@@ -105,9 +90,7 @@ class SecurityActionTest {
assertThat(history.getDescription()).hasValue("registrarId");
}
private SecurityAction createAction(AuthResult authResult, String registrarId)
throws IOException {
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
private SecurityAction createAction(String registrarId) throws IOException {
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.POST.toString());
doReturn(new BufferedReader(new StringReader(jsonRegistrar1)))
.when(consoleApiParams.request())
@@ -16,12 +16,16 @@ package google.registry.webdriver;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.server.Fixture.BASIC;
import static google.registry.testing.DatabaseHelper.persistResource;
import com.google.common.collect.ImmutableMap;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.RegistrarRole;
import google.registry.model.registrar.Registrar;
import google.registry.server.RegistryTestServer;
import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
@@ -74,6 +78,10 @@ public class ConsoleScreenshotTest {
@BeforeEach
void beforeEach() throws Exception {
server.setRegistrarRoles(ImmutableMap.of("TheRegistrar", RegistrarRole.ACCOUNT_MANAGER));
Registrar registrar = Registrar.loadByRegistrarId("TheRegistrar").get();
registrar =
registrar.asBuilder().setLastPocVerificationDate(DateTime.now(DateTimeZone.UTC)).build();
persistResource(registrar);
loadHomePage();
}
@@ -0,0 +1,11 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<check>
<domain:check
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>%DOMAIN%</domain:name>
</domain:check>
</check>
<clTRID>ABC-12345</clTRID>
</command>
</epp>
@@ -11,7 +11,7 @@ CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST
CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST,DELETE,PUT n USER PUBLIC
CONSOLE /console-api/settings/rdap-fields RdapRegistrarFieldsAction POST n USER PUBLIC
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
@@ -79,7 +79,7 @@ CONSOLE /console-api/registrar ConsoleUpdateRegistr
CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
CONSOLE /console-api/settings/contacts ContactAction GET,POST,DELETE,PUT n USER PUBLIC
CONSOLE /console-api/settings/rdap-fields RdapRegistrarFieldsAction POST n USER PUBLIC
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
@@ -5,13 +5,14 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "entity",
"handle": "%NAME%",
"handle": "%CONTACT_HANDLE_1%",
"status": ["active", "associated"],
"links": [
{
"rel": "self",
"href": "https://example.tld/rdap/entity/%NAME%",
"type": "application/rdap+json"
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -25,13 +26,13 @@
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "%FULLNAME%"],
["fn", {}, "text", "%CONTACT_FULLNAME_1%"],
["org", {}, "text", "GOOGLE INCORPORATED <script>"],
["adr", {}, "text",
[
"",
"",
[ %ADDRESS% ],
[ %CONTACT_ADDRESS_1% ],
"KOKOMO",
"BM",
"31337",
@@ -27,7 +27,8 @@
{
"type":"text\/html",
"href": "https:\/\/github.com\/google\/nomulus\/blob\/master\/docs\/rdap.md#authentication",
"rel": "alternate"
"rel": "alternate",
"value": "%REQUEST_URL%"
}
],
"description": [
@@ -5,14 +5,15 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName" : "entity",
"handle" : "%NAME%",
"status" : ["%STATUS%"],
"handle" : "%CONTACT_HANDLE_1%",
"status" : ["%STATUS_1%"],
"links" :
[
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/%NAME%",
"type" : "application/rdap+json"
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -26,13 +27,13 @@
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "%FULLNAME%"],
["fn", {}, "text", "%CONTACT_FULLNAME_1%"],
["org", {}, "text", "GOOGLE INCORPORATED <script>"],
["adr", {}, "text",
[
"",
"",
[ %ADDRESS% ],
[ %CONTACT_ADDRESS_1% ],
"KOKOMO",
"BM",
"31337",
@@ -5,14 +5,15 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName" : "entity",
"handle" : "%NAME%",
"handle" : "%CONTACT_HANDLE_1%",
"status" : ["inactive"],
"links" :
[
{
"rel" : "self",
"href": "https://example.tld/rdap/entity/%NAME%",
"type" : "application/rdap+json"
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"events":
@@ -38,5 +39,4 @@
]
}
]
}
@@ -32,7 +32,8 @@
{
"rel" : "alternate",
"href" : "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/entities"
}
]
},
@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -79,7 +83,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -115,7 +120,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray" : [
@@ -160,7 +166,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -197,7 +204,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -236,7 +244,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/addgraceperiod.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/addgraceperiod.lol"
}
],
"remarks": [
@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -128,7 +130,8 @@
{
"href": "https://example.tld/rdap/domain/autorenew.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"nameservers": [
@@ -140,7 +143,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/autorenew.lol"
}
],
"remarks": [
@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -98,7 +103,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"vcardArray" : [
@@ -149,7 +155,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -186,7 +193,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -223,7 +231,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -18,17 +18,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -64,7 +67,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -83,7 +87,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -110,7 +115,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray" : [
@@ -155,7 +161,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -192,7 +199,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -229,7 +237,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/renew.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/renew.lol"
}
],
"remarks": [
@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -105,7 +110,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"publicIds" : [
@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"remarks": [
@@ -105,7 +110,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/domain/cat.lol"
}
],
"publicIds" : [
@@ -164,7 +170,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domain/cat.lol"
}
]
},
@@ -200,7 +207,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domain/cat.lol"
}
]
},
@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/redemption.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/redemption.lol"
}
],
"remarks": [
@@ -17,17 +17,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -58,7 +61,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -77,7 +81,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -105,7 +110,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" : [
@@ -164,7 +170,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "%REQUEST_URL%"
}
]
},
@@ -200,7 +207,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "%REQUEST_URL%"
}
]
},
@@ -237,7 +245,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "%REQUEST_URL%"
}
]
},
@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"publicIds": [
@@ -65,7 +66,8 @@
{
"href": "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel": "alternate",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"title": "REDACTED FOR PRIVACY",
@@ -124,7 +126,8 @@
{
"href": "https://example.tld/rdap/domain/transfer.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"nameservers": [
@@ -136,7 +139,8 @@
{
"href": "https://example.tld/rdap/nameserver/ns1.cat.lol",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domain/transfer.lol"
}
],
"remarks": [
@@ -18,17 +18,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "%REQUEST_URL%"
}
],
"events": [
@@ -60,7 +63,8 @@
"href":
"https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -80,7 +84,8 @@
"href":
"https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"remarks": [
@@ -108,7 +113,8 @@
{
"href": "https://example.tld/rdap/entity/1",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray" : [
@@ -159,7 +165,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -196,7 +203,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -233,7 +241,8 @@
{
"href": "https://example.tld/rdap/entity/%CONTACT_HANDLE_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"vcardArray": [
@@ -18,17 +18,20 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://rdap.example.com/withoutSlash/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "related"
"rel": "related",
"value": "https://example.tld/rdap/domains"
}
],
"events": [
@@ -60,7 +63,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -80,7 +84,8 @@
{
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -108,7 +113,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "https://example.tld/rdap/domains"
}
],
"publicIds" : [
@@ -167,7 +173,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -203,7 +210,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -239,7 +247,8 @@
{
"href":"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
"rel":"alternate",
"type":"text/html"
"type":"text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -8,7 +8,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -27,7 +28,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -46,7 +48,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -65,7 +68,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_4%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -100,7 +104,8 @@
{
"type" : "application/rdap+json",
"rel" : "next",
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%"
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -124,12 +129,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -148,9 +155,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "glossary",
"href" : "https://icann.org/epp",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -160,9 +168,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "help",
"href" : "https://icann.org/wicf",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}
@@ -8,7 +8,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -27,7 +28,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -46,7 +48,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -66,7 +69,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_4%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -105,12 +109,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -129,9 +135,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "glossary",
"href" : "https://icann.org/epp",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -141,9 +148,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "help",
"href" : "https://icann.org/wicf",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}
@@ -8,7 +8,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -27,7 +28,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -46,7 +48,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_3%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -66,7 +69,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_4%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -101,7 +105,8 @@
{
"type" : "application/rdap+json",
"rel" : "next",
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%"
"href" : "https://example.tld/rdap/domains?%NEXT_QUERY%",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -125,12 +130,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -149,9 +156,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "glossary",
"href" : "https://icann.org/epp",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -161,9 +169,10 @@
"links" :
[
{
"rel" : "alternate",
"rel" : "help",
"href" : "https://icann.org/wicf",
"type" : "text/html"
"type" : "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}
@@ -13,7 +13,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -34,7 +35,8 @@
{
"href": "https://example.tld/rdap/domain/%DOMAIN_PUNYCODE_NAME_2%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "https://example.tld/rdap/domains"
}
],
"remarks": [
@@ -69,12 +71,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/domains"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -87,9 +91,10 @@
"links":
[
{
"rel": "alternate",
"rel": "glossary",
"href": "https://icann.org/epp",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
},
@@ -99,9 +104,10 @@
"links":
[
{
"rel": "alternate",
"rel": "help",
"href": "https://icann.org/wicf",
"type": "text/html"
"type": "text/html",
"value": "https://example.tld/rdap/domains"
}
]
}
@@ -28,12 +28,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "%REQUEST_URL%"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "%REQUEST_URL%"
}
],
"title": "RDAP Terms of Service"
@@ -27,12 +27,14 @@
{
"rel" : "alternate",
"type" : "text/html",
"href" : "https://github.com/google/nomulus/blob/master/docs/rdap.md"
"href" : "https://github.com/google/nomulus/blob/master/docs/rdap.md",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
},
{
"rel": "self",
"type": "application/rdap+json",
"href": "https://example.tld/rdap/help"
"href": "https://example.tld/rdap/help",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
}
]
},
@@ -56,12 +58,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/help%POSSIBLE_SLASH%"
}
]
}
@@ -26,12 +26,14 @@
{
"href": "https://example.tld/rdap/help/tos",
"rel": "self",
"type": "application/rdap+json"
"type": "application/rdap+json",
"value": "https://example.tld/rdap/help/tos"
},
{
"href": "https://www.registry.tld/about/rdap/tos.html",
"rel": "alternate",
"type": "text/html"
"href": "https://www.example.tld/about/rdap/tos.html",
"rel": "terms-of-service",
"type": "text/html",
"value": "https://example.tld/rdap/help/tos"
}
]
}
@@ -5,14 +5,15 @@
"icann_rdap_technical_implementation_guide_0"
],
"objectClassName": "nameserver",
"handle": "%HANDLE%",
"ldhName": "%NAME%",
"handle": "%NAMESERVER_HANDLE_1%",
"ldhName": "%NAMESERVER_NAME_1%",
"status": ["%STATUS%"],
"links": [
{
"href": "https://example.tld/rdap/nameserver/%NAME%",
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"ipAddresses": {
@@ -36,7 +37,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" :
@@ -7,15 +7,16 @@
"status": [
"active"
],
"handle": "%HANDLE%",
"handle": "%NAMESERVER_HANDLE_1%",
"links": [
{
"href": "https://example.tld/rdap/nameserver/%NAME%",
"href": "https://example.tld/rdap/nameserver/%NAMESERVER_NAME_1%",
"type": "application/rdap+json",
"rel": "self"
"rel": "self",
"value": "%REQUEST_URL%"
}
],
"ldhName": "%NAME%",
"ldhName": "%NAMESERVER_NAME_1%",
"events": [
{
"eventAction": "last update of RDAP database",
@@ -33,7 +34,8 @@
{
"rel" : "self",
"href" : "https://example.tld/rdap/entity/1",
"type" : "application/rdap+json"
"type" : "application/rdap+json",
"value": "%REQUEST_URL%"
}
],
"publicIds" :

Some files were not shown because too many files have changed in this diff Show More