1
0
mirror of https://github.com/google/nomulus synced 2026-05-21 15:21:48 +00:00

Compare commits

...

18 Commits

Author SHA1 Message Date
gbrodman
d4bcff0c31 Add password reset Java object (#2765)
A future PR will add the actions that save and use this object. That
future PR will also require loading RegistrarPoc objects given the
registrar ID, hence the change in that class.
2025-06-17 19:00:50 +00:00
Ben McIlwain
62065f88fb Remove spurious parenthesis in URS command output (#2767)
It was making the undo nomulus command look like this:

)nomulus ...
2025-06-16 20:23:48 +00:00
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
Pavlo Tkach
b4d239c329 Add console POC reminder backend support (#2747) 2025-04-30 14:15:43 +00:00
gbrodman
daa7ab3bfa Disable primary-contact editing in console (#2745)
This is necessary because we'll use primary-contact emails as a way of
resetting passwords.

In the UI, don't allow editing of email address for primary contacts,
and don't allow addition/removal of the primary contact field
post-creation.

In the backend, make sure that all emails previously added still exist.
2025-04-29 17:32:29 +00:00
143 changed files with 5404 additions and 4288 deletions

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();
}));
});
});

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) => {

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,

View File

@@ -57,7 +57,7 @@ export class NavigationComponent {
}
ngOnDestroy() {
this.subscription.unsubscribe();
this.subscription && this.subscription.unsubscribe();
}
getElementId(node: RouteWithIcon) {

View File

@@ -71,6 +71,7 @@ export interface Registrar
registrarName: string;
registryLockAllowed?: boolean;
type?: string;
lastPocVerificationDate?: string;
}
@Injectable({

View File

@@ -16,11 +16,7 @@ import { Component, effect, ViewEncapsulation } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { take } from 'rxjs';
import { RegistrarService } from 'src/app/registrar/registrar.service';
import {
ContactService,
contactTypeToViewReadyContact,
ViewReadyContact,
} from './contact.service';
import { ContactService, ViewReadyContact } from './contact.service';
@Component({
selector: 'app-contact',

View File

@@ -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 || [],
};
}
@@ -83,7 +86,7 @@ export class ContactService {
: contactTypeToViewReadyContact({
emailAddress: '',
name: '',
types: ['ADMIN'],
types: ['TECH'],
faxNumber: '',
phoneNumber: '',
registrarId: '',
@@ -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()));
}
}

View File

@@ -56,6 +56,7 @@
[required]="true"
[(ngModel)]="contactService.contactInEdit.emailAddress"
[ngModelOptions]="{ standalone: true }"
[disabled]="emailAddressIsDisabled()"
/>
</mat-form-field>
@@ -85,14 +86,18 @@
<mat-icon color="accent">error</mat-icon>Required to select at least one
</p>
<div class="">
<mat-checkbox
<ng-container
*ngFor="let contactType of contactTypeToTextMap | keyvalue"
[checked]="checkboxIsChecked(contactType.key)"
(change)="checkboxOnChange($event, contactType.key)"
[disabled]="checkboxIsDisabled(contactType.key)"
>
{{ contactType.value }}
</mat-checkbox>
<mat-checkbox
*ngIf="shouldDisplayCheckbox(contactType.key)"
[checked]="checkboxIsChecked(contactType.key)"
(change)="checkboxOnChange($event, contactType.key)"
[disabled]="checkboxIsDisabled(contactType.key)"
>
{{ contactType.value }}
</mat-checkbox>
</ng-container>
</div>
</section>

View File

@@ -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();
@@ -82,6 +86,10 @@ export class ContactDetailsComponent {
});
}
shouldDisplayCheckbox(type: string) {
return type !== 'ADMIN' || this.checkboxIsChecked(type);
}
checkboxIsChecked(type: string) {
return this.contactService.contactInEdit.types.includes(
type as contactType
@@ -89,6 +97,9 @@ export class ContactDetailsComponent {
}
checkboxIsDisabled(type: string) {
if (type === 'ADMIN') {
return true;
}
return (
this.contactService.contactInEdit.types.length === 1 &&
this.contactService.contactInEdit.types[0] === (type as contactType)
@@ -105,4 +116,8 @@ export class ContactDetailsComponent {
);
}
}
emailAddressIsDisabled() {
return this.contactService.contactInEdit.types.includes('ADMIN');
}
}

View File

@@ -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>

View File

@@ -0,0 +1,5 @@
.console-app__pocReminder {
a {
color: white !important;
}
}

View File

@@ -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();
},
});
}
}
}

View File

@@ -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),
}
);
}

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 {

View File

@@ -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(),

View File

@@ -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)) {

View File

@@ -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 {}

View File

@@ -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;

View File

@@ -0,0 +1,150 @@
// 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.model.console;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.Buildable;
import google.registry.model.CreateAutoTimestamp;
import google.registry.model.ImmutableObject;
import google.registry.persistence.WithVKey;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.AttributeOverrides;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import java.util.Optional;
import java.util.UUID;
import org.joda.time.DateTime;
/**
* Represents a password reset request of some type.
*
* <p>Password reset requests must be performed within an hour of the time that they were requested,
* as well as requiring that the requester and the fulfiller have the proper respective permissions.
*/
@Entity
@WithVKey(String.class)
public class PasswordResetRequest extends ImmutableObject implements Buildable {
public enum Type {
EPP,
REGISTRY_LOCK
}
@Id private String verificationCode;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
Type type;
@AttributeOverrides({
@AttributeOverride(
name = "creationTime",
column = @Column(name = "requestTime", nullable = false))
})
CreateAutoTimestamp requestTime = CreateAutoTimestamp.create(null);
@Column(nullable = false)
String requester;
@Column DateTime fulfillmentTime;
@Column(nullable = false)
String destinationEmail;
@Column(nullable = false)
String registrarId;
public String getVerificationCode() {
return verificationCode;
}
public Type getType() {
return type;
}
public DateTime getRequestTime() {
return requestTime.getTimestamp();
}
public String getRequester() {
return requester;
}
public Optional<DateTime> getFulfillmentTime() {
return Optional.ofNullable(fulfillmentTime);
}
public String getDestinationEmail() {
return destinationEmail;
}
public String getRegistrarId() {
return registrarId;
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** Builder for constructing immutable {@link PasswordResetRequest} objects. */
public static class Builder extends Buildable.Builder<PasswordResetRequest> {
public Builder() {}
private Builder(PasswordResetRequest instance) {
super(instance);
}
@Override
public PasswordResetRequest build() {
checkArgumentNotNull(getInstance().type, "Type must be specified");
checkArgumentNotNull(getInstance().requester, "Requester must be specified");
checkArgumentNotNull(getInstance().destinationEmail, "Destination email must be specified");
checkArgumentNotNull(getInstance().registrarId, "Registrar ID must be specified");
getInstance().verificationCode = UUID.randomUUID().toString();
return super.build();
}
public Builder setType(Type type) {
getInstance().type = type;
return this;
}
public Builder setRequester(String requester) {
getInstance().requester = requester;
return this;
}
public Builder setDestinationEmail(String destinationEmail) {
getInstance().destinationEmail = destinationEmail;
return this;
}
public Builder setRegistrarId(String registrarId) {
getInstance().registrarId = registrarId;
return this;
}
public Builder setFulfillmentTime(DateTime fulfillmentTime) {
getInstance().fulfillmentTime = fulfillmentTime;
return this;
}
}
}

View File

@@ -403,6 +403,9 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
*/
DateTime lastExpiringFailoverCertNotificationSentDate = START_OF_TIME;
/** The time that the POCs have been reviewed last. */
@Expose DateTime lastPocVerificationDate = START_OF_TIME;
/** Telephone support passcode (5-digit numeric) */
String phonePasscode;
@@ -461,6 +464,10 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
return registrarName;
}
public DateTime getLastPocVerificationDate() {
return lastPocVerificationDate;
}
public Type getType() {
return type;
}
@@ -593,13 +600,8 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
return getContacts().stream().filter(RegistrarPoc::getVisibleInDomainWhoisAsAbuse).findFirst();
}
private ImmutableSet<RegistrarPoc> getContactPocs() {
return tm().transact(
() ->
tm().query("FROM RegistrarPoc WHERE registrarId = :registrarId", RegistrarPoc.class)
.setParameter("registrarId", registrarId)
.getResultStream()
.collect(toImmutableSet()));
private ImmutableList<RegistrarPoc> getContactPocs() {
return tm().transact(() -> RegistrarPoc.loadForRegistrar(registrarId));
}
@Override
@@ -614,6 +616,7 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
.putString(
"lastExpiringFailoverCertNotificationSentDate",
lastExpiringFailoverCertNotificationSentDate)
.putString("lastPocVerificationDate", lastPocVerificationDate)
.put("registrarName", registrarName)
.put("type", type)
.put("state", state)
@@ -802,6 +805,12 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J
return thisCastToDerived();
}
public B setLastPocVerificationDate(DateTime now) {
checkArgumentNotNull(now, "Registrar lastPocVerificationDate cannot be null");
getInstance().lastPocVerificationDate = now;
return thisCastToDerived();
}
private static String calculateHash(String clientCertificate) {
if (clientCertificate == null) {
return null;

View File

@@ -27,6 +27,7 @@ import static google.registry.util.PasswordUtils.hashPassword;
import static java.util.stream.Collectors.joining;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.gson.annotations.Expose;
@@ -36,6 +37,7 @@ import google.registry.model.JsonMapBuilder;
import google.registry.model.Jsonifiable;
import google.registry.model.UnsafeSerializable;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.QueryComposer;
import google.registry.util.PasswordUtils;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -93,6 +95,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 +185,10 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
tm().putAll(contacts);
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
@@ -295,6 +305,7 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
.put("visibleInDomainWhoisAsAbuse", visibleInDomainWhoisAsAbuse)
.put("allowedToSetRegistryLockPassword", allowedToSetRegistryLockPassword)
.put("registryLockAllowed", isRegistryLockAllowed())
.put("id", getId())
.build();
}
@@ -423,6 +434,12 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
}
}
public static ImmutableList<RegistrarPoc> loadForRegistrar(String registrarId) {
return tm().createQueryComposer(RegistrarPoc.class)
.where("registrarId", QueryComposer.Comparator.EQ, registrarId)
.list();
}
/** Class to represent the composite primary key for {@link RegistrarPoc} entity. */
@VisibleForTesting
public static class RegistrarPocId extends ImmutableObject implements Serializable {

View File

@@ -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,
})

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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())

View File

@@ -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());

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -251,11 +251,12 @@ final class UniformRapidSuspensionCommand extends MutatingEppToolCommand {
if (undo) {
return "";
}
StringBuilder undoBuilder = new StringBuilder("UNDO COMMAND:\n\n)")
.append("nomulus -e ")
.append(RegistryToolEnvironment.get())
.append(" uniform_rapid_suspension --undo --domain_name ")
.append(domainName);
StringBuilder undoBuilder =
new StringBuilder("UNDO COMMAND:\n\n")
.append("nomulus -e ")
.append(RegistryToolEnvironment.get())
.append(" uniform_rapid_suspension --undo --domain_name ")
.append(domainName);
if (!existingNameservers.isEmpty()) {
undoBuilder.append(" --hosts ").append(Joiner.on(',').join(existingNameservers));
}

View File

@@ -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

View File

@@ -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,17 +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())
.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()

View File

@@ -15,12 +15,13 @@
package google.registry.ui.server.console.settings;
import static com.google.common.base.Preconditions.checkArgument;
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;
@@ -33,66 +34,122 @@ import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPoc.Type;
import google.registry.persistence.transaction.QueryComposer.Comparator;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
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 =
tm().transact(
() ->
tm()
.createQueryComposer(RegistrarPoc.class)
.where("registrarId", Comparator.EQ, registrarId)
.stream()
.filter(r -> !r.getTypes().isEmpty())
.collect(toImmutableList()));
ImmutableList<RegistrarPoc> contacts =
tm().transact(() -> RegistrarPoc.loadForRegistrar(registrarId));
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 +158,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 +170,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 +215,8 @@ public class ContactAction extends ConsoleApiAction {
throw new ContactRequirementException(t);
}
}
enforcePrimaryContactRestrictions(oldContactsByType, newContactsByType);
ensurePhoneNumberNotRemovedForContactTypes(oldContactsByType, newContactsByType, Type.TECH);
Optional<RegistrarPoc> domainWhoisAbuseContact =
getDomainWhoisVisibleAbuseContact(updatedContacts);
@@ -187,6 +235,23 @@ public class ContactAction extends ConsoleApiAction {
checkContactRegistryLockRequirements(existingContacts, updatedContacts);
}
private static void enforcePrimaryContactRestrictions(
Multimap<Type, RegistrarPoc> oldContactsByType,
Multimap<Type, RegistrarPoc> newContactsByType) {
ImmutableSet<String> oldAdminEmails =
oldContactsByType.get(Type.ADMIN).stream()
.map(RegistrarPoc::getEmailAddress)
.collect(toImmutableSet());
ImmutableSet<String> newAdminEmails =
newContactsByType.get(Type.ADMIN).stream()
.map(RegistrarPoc::getEmailAddress)
.collect(toImmutableSet());
if (!newAdminEmails.containsAll(oldAdminEmails)) {
throw new ContactRequirementException(
"Cannot remove or change the email address of primary contacts");
}
}
private static void checkContactRegistryLockRequirements(
ImmutableSet<RegistrarPoc> existingContacts, ImmutableSet<RegistrarPoc> updatedContacts) {
// Any contact(s) with new passwords must be allowed to set them

View File

@@ -47,13 +47,14 @@
<class>google.registry.model.billing.BillingRecurrence</class>
<class>google.registry.model.common.Cursor</class>
<class>google.registry.model.common.DnsRefreshRequest</class>
<class>google.registry.model.common.FeatureFlag</class>
<class>google.registry.model.console.ConsoleUpdateHistory</class>
<class>google.registry.model.console.PasswordResetRequest</class>
<class>google.registry.model.console.User</class>
<class>google.registry.model.contact.ContactHistory</class>
<class>google.registry.model.contact.Contact</class>
<class>google.registry.model.domain.Domain</class>
<class>google.registry.model.domain.DomainHistory</class>
<class>google.registry.model.common.FeatureFlag</class>
<class>google.registry.model.domain.GracePeriod</class>
<class>google.registry.model.domain.GracePeriod$GracePeriodHistory</class>
<class>google.registry.model.domain.secdns.DomainDsData</class>

View File

@@ -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>

View File

@@ -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

View File

@@ -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) {

View File

@@ -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");
}
}

View File

@@ -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 =

View File

@@ -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) {

View File

@@ -0,0 +1,65 @@
// 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.model.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.testing.DatabaseHelper.persistResource;
import static org.junit.Assert.assertThrows;
import google.registry.model.EntityTestCase;
import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import org.junit.jupiter.api.Test;
/** Tests for {@link PasswordResetRequest}. */
public class PasswordResetRequestTest extends EntityTestCase {
PasswordResetRequestTest() {
super(JpaEntityCoverageCheck.ENABLED);
}
@Test
void testSuccess_persistence() {
PasswordResetRequest request =
new PasswordResetRequest.Builder()
.setRequester("requestor@email.tld")
.setDestinationEmail("destination@email.tld")
.setType(PasswordResetRequest.Type.EPP)
.setRegistrarId("TheRegistrar")
.build();
String verificationCode = request.getVerificationCode();
assertThat(verificationCode).isNotEmpty();
persistResource(request);
PasswordResetRequest fromDatabase =
DatabaseHelper.loadByKey(VKey.create(PasswordResetRequest.class, verificationCode));
assertAboutImmutableObjects().that(fromDatabase).isEqualExceptFields(request, "requestTime");
assertThat(fromDatabase.getRequestTime()).isEqualTo(fakeClock.nowUtc());
}
@Test
void testFailure_nullFields() {
PasswordResetRequest.Builder builder = new PasswordResetRequest.Builder();
assertThrows(IllegalArgumentException.class, builder::build);
builder.setType(PasswordResetRequest.Type.EPP);
assertThrows(IllegalArgumentException.class, builder::build);
builder.setRequester("foobar@email.tld");
assertThrows(IllegalArgumentException.class, builder::build);
builder.setDestinationEmail("email@email.tld");
assertThrows(IllegalArgumentException.class, builder::build);
builder.setRegistrarId("TheRegistrar");
builder.build();
}
}

View File

@@ -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();
@@ -496,6 +498,28 @@ class RegistrarTest extends EntityTestCase {
.isEqualTo(fakeClock.nowUtc());
}
@Test
void testSuccess_setLastPocVerificationDate() {
assertThat(
registrar
.asBuilder()
.setLastPocVerificationDate(fakeClock.nowUtc())
.build()
.getLastPocVerificationDate())
.isEqualTo(fakeClock.nowUtc());
}
@Test
void testFailure_setLastPocVerificationDate_nullDate() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> new Registrar.Builder().setLastPocVerificationDate(null).build());
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Registrar lastPocVerificationDate cannot be null");
}
@Test
void testFailure_setLastExpiringFailoverCertNotificationSentDate_nullDate() {
IllegalArgumentException thrown =

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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[]");
}

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -25,6 +25,7 @@ import google.registry.model.common.CursorTest;
import google.registry.model.common.DnsRefreshRequestTest;
import google.registry.model.common.FeatureFlagTest;
import google.registry.model.console.ConsoleUpdateHistoryTest;
import google.registry.model.console.PasswordResetRequestTest;
import google.registry.model.console.UserTest;
import google.registry.model.contact.ContactTest;
import google.registry.model.domain.DomainSqlTest;
@@ -104,6 +105,7 @@ import org.junit.runner.RunWith;
FeatureFlagTest.class,
HostHistoryTest.class,
LockTest.class,
PasswordResetRequestTest.class,
PollMessageTest.class,
PremiumListDaoTest.class,
RdeRevisionTest.class,

View File

@@ -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

View File

@@ -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

View File

@@ -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 =

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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");
}

View File

@@ -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));

View File

@@ -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,

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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,24 +47,22 @@ 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;
private User user;
private static String registrarPostData =
"{\"registrarId\":\"%s\",\"allowedTlds\":[%s],\"registryLockAllowed\":%s}";
"{\"registrarId\":\"%s\",\"allowedTlds\":[%s],\"registryLockAllowed\":%s,"
+ " \"lastPocVerificationDate\":%s }";
@RegisterExtension
@Order(Integer.MAX_VALUE)
@@ -91,33 +85,69 @@ 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 = createAction(String.format(registrarPostData, "TheRegistrar", "app, dev", false));
var action =
createAction(
String.format(
registrarPostData,
"TheRegistrar",
"app, dev",
false,
"\"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);
var action = createAction(String.format(registrarPostData, "TheRegistrar", "app, dev", false));
var action =
createAction(
String.format(
registrarPostData,
"TheRegistrar",
"app, dev",
false,
"\"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");
}
@@ -137,17 +167,31 @@ class ConsoleUpdateRegistrarActionTest {
.setVisibleInDomainWhoisAsAbuse(true)
.build();
persistResource(contact);
var action = createAction(String.format(registrarPostData, "TheRegistrar", "app, dev", false));
var action =
createAction(
String.format(
registrarPostData,
"TheRegistrar",
"app, dev",
false,
"\"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
void testSuccess_sendsEmail() throws AddressException, IOException {
var action = createAction(String.format(registrarPostData, "TheRegistrar", "app, dev", false));
var action =
createAction(
String.format(
registrarPostData,
"TheRegistrar",
"app, dev",
false,
"\"2023-12-12T00:00:00.000Z\""));
action.run();
verify(consoleApiParams.sendEmailUtils().gmailClient, times(1))
.sendEmail(
@@ -157,9 +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")
+ "allowedTlds: null -> [app, dev]\n"
+ "lastPocVerificationDate: 1970-01-01T00:00:00.000Z ->"
+ " 2023-12-12T00:00:00.000Z\n")
.setRecipients(ImmutableList.of(new InternetAddress("notification@test.example")))
.build());
}

View File

@@ -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");
}

View File

@@ -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,

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -18,10 +18,12 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
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;
@@ -35,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;
@@ -56,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\","
@@ -69,95 +67,73 @@ class ContactActionTest {
+ "\"visibleInWhoisAsTech\":false,\"visibleInDomainWhoisAsAbuse\":false}";
private Registrar testRegistrar;
private ConsoleApiParams consoleApiParams;
private RegistrarPoc testRegistrarPoc1;
private RegistrarPoc testRegistrarPoc2;
private static final Gson GSON = RequestModule.provideGson();
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private RegistrarPoc adminPoc;
private RegistrarPoc techPoc;
private RegistrarPoc marketingPoc;
@BeforeEach
void beforeEach() {
testRegistrar = saveRegistrar("registrarId");
testRegistrarPoc1 =
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();
testRegistrarPoc2 =
testRegistrarPoc1
adminPoc =
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()
.setName("Test Registrar 2")
.setTypes(ImmutableSet.of(TECH))
.setVisibleInWhoisAsTech(true)
.setVisibleInWhoisAsAdmin(false)
.setEmailAddress("test.registrar2@example.com")
.setPhoneNumber("+1.1234567890")
.setFaxNumber("+1.1234567891")
.build();
marketingPoc =
adminPoc
.asBuilder()
.setName("Test Registrar 3")
.setTypes(ImmutableSet.of(MARKETING))
.setVisibleInWhoisAsAdmin(false)
.setEmailAddress("test.registrar3@example.com")
.setPhoneNumber("+1.1238675309")
.setFaxNumber("+1.1238675309")
.build();
}
@Test
void testSuccess_getContactInfo() throws IOException {
insertInDb(testRegistrarPoc1);
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(testRegistrarPoc1);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
testRegistrarPoc1);
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 {
testRegistrarPoc1 = testRegistrarPoc1.asBuilder().setTypes(ImmutableSet.of()).build();
insertInDb(testRegistrarPoc1);
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(testRegistrarPoc1);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
testRegistrarPoc1,
testRegistrarPoc2);
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()))
@@ -168,16 +144,16 @@ class ContactActionTest {
@Test
void testSuccess_postUpdateContactInfo() throws IOException {
insertInDb(testRegistrarPoc1.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(),
testRegistrarPoc1,
testRegistrarPoc2);
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()))
@@ -192,69 +168,66 @@ 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(),
testRegistrarPoc1,
testRegistrarPoc2.asBuilder().setEmailAddress("test.registrar1@example.com").build());
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(testRegistrarPoc1);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
testRegistrarPoc1.asBuilder().setTypes(ImmutableSet.of(ABUSE)).build());
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()))
.collect(toImmutableList()))
.containsExactly(testRegistrarPoc1);
.containsExactly(adminPoc);
}
@Test
void testFailure_postUpdateContactInfo_phoneNumberRemoved() throws IOException {
testRegistrarPoc1 =
testRegistrarPoc1.asBuilder().setTypes(ImmutableSet.of(ADMIN, TECH)).build();
insertInDb(testRegistrarPoc1);
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(),
testRegistrarPoc1
adminPoc
.asBuilder()
.setPhoneNumber(null)
.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()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.containsExactly(testRegistrarPoc1);
.containsExactly(adminPoc);
}
@Test
@@ -262,136 +235,48 @@ class ContactActionTest {
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
fteUser,
testRegistrar.getRegistrarId(),
testRegistrarPoc1
.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 {
testRegistrarPoc1 = testRegistrarPoc1.asBuilder().setVisibleInDomainWhoisAsAbuse(true).build();
insertInDb(testRegistrarPoc1);
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(),
testRegistrarPoc1.asBuilder().setVisibleInDomainWhoisAsAbuse(false).build());
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()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList()))
.containsExactly(testRegistrarPoc1);
}
@Test
void testFailure_postUpdateContactInfo_newContactCannotSetRegistryLockPassword()
throws IOException {
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
testRegistrarPoc1
.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 {
testRegistrarPoc1 =
testRegistrarPoc1
.asBuilder()
.setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(true)
.build();
insertInDb(testRegistrarPoc1);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
testRegistrarPoc1
.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(testRegistrarPoc1);
}
@Test
void testFailure_postUpdateContactInfo_cannotSetIsAllowedToSetRegistryLockPassword()
throws IOException {
testRegistrarPoc1 =
testRegistrarPoc1
.asBuilder()
.setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(false)
.build();
insertInDb(testRegistrarPoc1);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
testRegistrarPoc1.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(testRegistrarPoc1);
.containsExactly(adminPoc);
}
@Test
void testSuccess_sendsEmail() throws IOException, AddressException {
insertInDb(testRegistrarPoc1.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(),
testRegistrarPoc1);
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()
@@ -400,90 +285,101 @@ 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 1,"
+ " emailAddress=test.registrar1@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.9999999999,"
+ " faxNumber=+1.9999999991, types=[ADMIN],"
+ " visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false,"
+ " {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 1, emailAddress=incorrect@email.com,"
+ " {id="
+ id
+ ", name=Test Registrar 2, emailAddress=test.registrar2@example.com,"
+ " registrarId=registrarId, registryLockEmailAddress=null,"
+ " phoneNumber=+1.9999999999, faxNumber=+1.9999999991, types=[ADMIN],"
+ " visibleInWhoisAsAdmin=true,"
+ " visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false,"
+ " phoneNumber=+1.1234567890, faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=false,"
+ " visibleInWhoisAsTech=true, visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n"
+ " FINAL CONTENTS:\n"
+ " {name=Test Registrar 1,"
+ " emailAddress=test.registrar1@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.9999999999,"
+ " faxNumber=+1.9999999991, types=[ADMIN],"
+ " visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false,"
+ " {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")
.setRecipients(
ImmutableList.of(
new InternetAddress("notification@test.example"),
new InternetAddress("incorrect@email.com")))
.setRecipients(ImmutableList.of(new InternetAddress("notification@test.example")))
.build());
}
@Test
void testSuccess_postDeleteContactInfo() throws IOException {
insertInDb(testRegistrarPoc1);
insertInDb(techPoc, marketingPoc);
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
testRegistrarPoc2);
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()))
.map(r -> r.getName())
.collect(toImmutableList()))
.containsExactly("Test Registrar 2");
.containsExactly("Test Registrar 1", "Test Registrar 2");
}
@Test
void testFailure_postDeleteContactInfo_missingPermission() throws IOException {
insertInDb(testRegistrarPoc1);
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(),
testRegistrarPoc2);
techPoc);
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
@Test
void testFailure_changesAdminEmail() throws Exception {
ContactAction action =
createAction(
Action.Method.PUT,
fteUser,
testRegistrar.getRegistrarId(),
adminPoc.asBuilder().setEmailAddress("testemail@example.com").build());
action.run();
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));
}
}

View File

@@ -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())

View File

@@ -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())

View File

@@ -16,13 +16,18 @@ 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;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junitpioneer.jupiter.RetryingTest;
@@ -50,7 +55,15 @@ import org.openqa.selenium.WebElement;
*/
// The Selenium image only supports amd64 architecture.
@EnabledIfSystemProperty(named = "os.arch", matches = "amd64")
public class ConsoleScreenshotTest extends WebDriverTestCase {
@Timeout(120)
public class ConsoleScreenshotTest {
@RegisterExtension
static final DockerWebDriverExtension webDriverProvider = new DockerWebDriverExtension();
@RegisterExtension
final WebDriverPlusScreenDifferExtension driver =
new WebDriverPlusScreenDifferExtension(webDriverProvider::getWebDriver);
@RegisterExtension
final TestServerExtension server =
@@ -65,6 +78,10 @@ public class ConsoleScreenshotTest extends WebDriverTestCase {
@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();
}

View File

@@ -1,30 +0,0 @@
// Copyright 2019 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.webdriver;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Base class for tests that needs a {@link WebDriverPlusScreenDifferExtension}. */
@Timeout(120)
class WebDriverTestCase {
@RegisterExtension
static final DockerWebDriverExtension webDriverProvider = new DockerWebDriverExtension();
@RegisterExtension
final WebDriverPlusScreenDifferExtension driver =
new WebDriverPlusScreenDifferExtension(webDriverProvider::getWebDriver);
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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",

View File

@@ -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": [

View File

@@ -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",

View File

@@ -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 @@
]
}
]
}

View File

@@ -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"
}
]
},

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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" : [

View File

@@ -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"
}
]
},

View File

@@ -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": [

View File

@@ -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%"
}
]
},

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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"
}
]
},

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