1
0
mirror of https://github.com/google/nomulus synced 2026-05-22 07:41:50 +00:00

Compare commits

...

11 Commits

Author SHA1 Message Date
Shicong Huang
19bc1c9c9c Add annotation processor to generate converter for VKey (#566) 2020-04-29 17:29:05 -04:00
gbrodman
c361c9e601 Remove email-editing footgun (#503)
* Remove email-editing footgun

Email address is used as the primary key so we should be very careful
about changing it. This will have even more importance when this is the
location to which we will be sending registry lock confirmation emails.

Note: we allow addition or removal of contacts through the UI (and don't
want to disable that) and because all edits are performed by saving the
entire list of contacts, we can't explicitly prevent all possible edits
of email address in the backend. So this doesn't technically prevent
anything security-wise, but it makes it much more difficult to
accidentally edit an email when you shouldn't.

* Enforce non-deletion of registry-lock-enabled contacts

* Fix tests

* Specify contact
2020-04-29 11:44:51 -04:00
Weimin Yu
aa0dcea537 Fix flaky tests due to Entity name conflicts (#569)
* Fix flaky tests due to Entity name conflicts

Objectify siliently replaces current registration of a given kind
when another class is registered for this kind. There are
several TestObject classes in the current code base, which by
default are all mapped to the same kind.

Tests have only been flaky because impacted tests need to run
in specific orders for failures to happen. Using multiple executors
in Gradle also reduced the likely hood of errors. To reproduce the
problem run the following tests in order (e.g., by putting them in
a test suite):
1. ExportCommitLogDiffActionTest
2. CreateAutoTimestampTest
3. RestoreCommitLogsActionTest

In this PR, we
- Made sure all entities have unique kinds.
- Made all test entities register with AppEngineRule instead of directly
  with ObjectifyService.
- Added code in AppEngineRule to check for re-registrations.
- Added presumit check for forbidden direct registration.
2020-04-28 15:32:42 -04:00
sarahcaseybot
e920e4d201 Remove Lock Dual Read and Dual Write (#568) 2020-04-27 17:30:51 -04:00
Ben McIlwain
cd13f6c5d3 Allow the nomulus renew_domain command to specify the client ID (#567)
* Allow the `nomulus renew_domain` command to specify the client ID

This means that a superuser can renew a domain and have the associated history
entry, one time billing event, and renewal grace period be recorded against a
specified registrar rather than the owning registrar of the domain.  This is
useful to e.g. renew a domain for free by "charging" the renewal to the
registry's fake registrar.  Since the grace period is written to the specified
cliend id as well, if the actual registrar deletes the domain, they don't get
back the money that they didn't pay in the first place.
2020-04-24 18:06:27 -04:00
Ben McIlwain
210de9340e Don't NPE when nomulus tool is run without a subcommand (#564)
* Don't NPE when nomulus tool is run without a subcommand

This occurred when an environment was specified but without a subcommand. Now,
the list of valid subcommands is outputted instead of seeing a generic NPE.

This also makes some formatting changes in other files that were causing the
incremental format check to fail.

* Try AppEngineRule
2020-04-24 17:32:58 -04:00
Michael Muller
5d58be6f0a Remove separate deployment of persistence.xml (#563)
* Remove separate deployment of persistence.xml

We added a step to explicitly copy persistence.xml because for some reason it
wasn't originally getting deployed to app-engine, resulting in failures on
startup.  However, this file is now included in core.jar and we are now
getting a warning about multiple persistence units with the same name as it
reads the files from both the filesystem and core.jar.
2020-04-23 13:35:37 -04:00
Shicong Huang
d8066ca752 Remove minimumIdle config in HikariCP (#557)
* Remove minimumIdle config for HikariCP

* Add comment

* Resolve comment
2020-04-22 19:35:02 -04:00
gbrodman
ca3ae9b0e4 Add SqlEntity and DatastoreEntity interfaces (#562)
* Add SqlEntity and DatastoreEntity interfaces

These will be used when replaying transactions from either the Datastore
commit logs or the SQL Transaction objects.

When Datastore is the primary database, we will read in the
Datastore commit logs, convert each saved entity to however many SQL
entities, then save those SQL entities in SQL.

When SQL is the primary database, we will read in the SQL objects from a
yet-to-be-created SQL table, convert them to however many Datastore
entities, then save those Datastore entities in Datastore.

This PR includes a couple simple examples of how this will work for entities that are
saveable in both SQL and Datastore (the simple case).

* Add 1-1 mapping between entity annotations and interfaces
2020-04-21 17:28:49 -04:00
Shicong Huang
295251ee78 Add JPA annotations to ContactResource and generate schema (#547)
* Add JPA annotations to ContactResource and generate schema

* Resolve comments

* Resolve comments

* Manually add foreign key constraints

* Run with junit5

* Rebase on HEAD

* Fix DomainBaseSqlTest
2020-04-21 15:40:16 -04:00
Michael Muller
7ca0e9387c Persist DomainBase.nsHosts VKeys to SQL (#541)
Persist nsHosts in Cloud SQL

Persist the VKey based nameserver hosts field of DomainBase in Cloud SQL with
foreign key constraints.
2020-04-20 13:03:12 -04:00
106 changed files with 2193 additions and 444 deletions

View File

@@ -31,10 +31,6 @@ def coreResourcesDir = "${rootDir}/core/build/resources/main"
war {
webInf {
from "../../core/src/main/java/google/registry/env/common/${project.name}/WEB-INF"
from("${coreResourcesDir}/META-INF/persistence.xml") {
into "classes/META-INF"
}
}
}

View File

@@ -99,6 +99,15 @@ PRESUBMITS = {
"System.(out|err).println is only allowed in tools/ packages. Please "
"use a logger instead.",
# ObjectifyService.register is restricted to main/ or AppEngineRule.
PresubmitCheck(
r".*\bObjectifyService\.register", "java", {
"/build/", "/generated/", "node_modules/", "src/main/",
"AppEngineRule.java"
}):
"ObjectifyService.register is not allowed in tests. Please use "
"AppengineRule.register instead.",
# PostgreSQLContainer instantiation must specify docker tag
PresubmitCheck(
r"[\s\S]*new\s+PostgreSQLContainer(<[\s\S]*>)?\(\s*\)[\s\S]*",

View File

@@ -295,6 +295,8 @@ dependencies {
testAnnotationProcessor deps['com.google.auto.value:auto-value']
annotationProcessor deps['com.google.dagger:dagger-compiler']
testAnnotationProcessor deps['com.google.dagger:dagger-compiler']
annotationProcessor project(':processor')
testAnnotationProcessor project(':processor')
testCompile deps['com.google.appengine:appengine-testing']
testCompile deps['com.google.guava:guava-testlib']

View File

@@ -12,24 +12,24 @@ com.google.dagger:dagger-producers:2.21
com.google.dagger:dagger-spi:2.21
com.google.dagger:dagger:2.21
com.google.errorprone:error_prone_annotation:2.3.3
com.google.errorprone:error_prone_annotations:2.3.3
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_check_api:2.3.3
com.google.errorprone:error_prone_core:2.3.3
com.google.errorprone:error_prone_type_annotations:2.3.3
com.google.errorprone:javac-shaded:9-dev-r4023-3
com.google.googlejavaformat:google-java-format:1.5
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.j2objc:j2objc-annotations:1.3
com.google.protobuf:protobuf-java:3.4.0
com.googlecode.java-diff-utils:diffutils:1.3.0
com.squareup:javapoet:1.11.1
com.squareup:javapoet:1.12.1
javax.annotation:jsr250-api:1.0
javax.inject:javax.inject:1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-compat-qual:2.5.3
org.checkerframework:checker-qual:2.5.3
org.checkerframework:checker-qual:2.10.0
org.checkerframework:dataflow:2.5.3
org.checkerframework:javacutil:2.5.3
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.pcollections:pcollections:2.1.2

View File

@@ -12,24 +12,24 @@ com.google.dagger:dagger-producers:2.21
com.google.dagger:dagger-spi:2.21
com.google.dagger:dagger:2.21
com.google.errorprone:error_prone_annotation:2.3.3
com.google.errorprone:error_prone_annotations:2.3.3
com.google.errorprone:error_prone_annotations:2.3.4
com.google.errorprone:error_prone_check_api:2.3.3
com.google.errorprone:error_prone_core:2.3.3
com.google.errorprone:error_prone_type_annotations:2.3.3
com.google.errorprone:javac-shaded:9-dev-r4023-3
com.google.googlejavaformat:google-java-format:1.5
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.j2objc:j2objc-annotations:1.3
com.google.protobuf:protobuf-java:3.4.0
com.googlecode.java-diff-utils:diffutils:1.3.0
com.squareup:javapoet:1.11.1
com.squareup:javapoet:1.12.1
javax.annotation:jsr250-api:1.0
javax.inject:javax.inject:1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-compat-qual:2.5.3
org.checkerframework:checker-qual:2.5.3
org.checkerframework:checker-qual:2.10.0
org.checkerframework:dataflow:2.5.3
org.checkerframework:javacutil:2.5.3
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.pcollections:pcollections:2.1.2

View File

@@ -1512,21 +1512,11 @@ public final class RegistryConfig {
return CONFIG_SETTINGS.get().hibernate.hikariConnectionTimeout;
}
/** Returns the minimum idle connections for HikariCP. */
public static String getHibernateHikariMinimumIdle() {
return CONFIG_SETTINGS.get().hibernate.hikariMinimumIdle;
}
/** Returns the maximum pool size for HikariCP. */
public static String getHibernateHikariMaximumPoolSize() {
return CONFIG_SETTINGS.get().hibernate.hikariMaximumPoolSize;
}
/** Returns the idle timeout for HikariCP. */
public static String getHibernateHikariIdleTimeout() {
return CONFIG_SETTINGS.get().hibernate.hikariIdleTimeout;
}
/** Returns the roid suffix to be used for the roids of all contacts and hosts. */
public static String getContactAndHostRoidSuffix() {
return CONFIG_SETTINGS.get().registryPolicy.contactAndHostRoidSuffix;

View File

@@ -112,9 +112,7 @@ public class RegistryConfigSettings {
public String connectionIsolation;
public String logSqlQueries;
public String hikariConnectionTimeout;
public String hikariMinimumIdle;
public String hikariMaximumPoolSize;
public String hikariIdleTimeout;
}
/** Configuration for Cloud SQL. */

View File

@@ -207,9 +207,17 @@ hibernate:
# Connection pool configurations.
hikariConnectionTimeout: 20000
hikariMinimumIdle: 0
# We occasionally received "Connection is not available, request timed out"
# exception when setting minimumIdle to 0 and it turned out it is a bug (See
# https://github.com/brettwooldridge/HikariCP/issues/1212) in HikariCP and
# the workaround is to use a fixed size connection pool.
#
# HikariCP also recommends not setting minimumIdle for maximum performance
# and responsiveness to spike demands (See
# https://github.com/brettwooldridge/HikariCP).
# TODO(b/154720215): Experiment with a smaller pool size.
hikariMaximumPoolSize: 20
hikariIdleTimeout: 300000
cloudSql:
# jdbc url for the Cloud SQL database.

View File

@@ -70,9 +70,11 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
/** The ID of the registrar that is currently sponsoring this resource. */
@Index
@Column(nullable = false)
String currentSponsorClientId;
/** The ID of the registrar that created this resource. */
@Column(nullable = false)
String creationClientId;
/**
@@ -88,7 +90,9 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
// Map the method to XML, not the field, because if we map the field (with an adaptor class) it
// will never be omitted from the xml even if the timestamp inside creationTime is null and we
// return null from the adaptor. (Instead it gets written as an empty tag.)
@Index CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
@Column(nullable = false)
@Index
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
/**
* The time when this resource was or will be deleted.
@@ -131,7 +135,7 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
@Transient
ImmutableSortedMap<DateTime, Key<CommitLogManifest>> revisions = ImmutableSortedMap.of();
public final String getRepoId() {
public String getRepoId() {
return repoId;
}

View File

@@ -16,13 +16,14 @@ package google.registry.model.contact;
import com.googlecode.objectify.annotation.Embed;
import google.registry.model.eppcommon.Address;
import javax.persistence.Embeddable;
/**
* EPP Contact Address
*
* <p>This class is embedded inside the {@link PostalInfo} of an EPP contact to hold its
* address. The fields are all defined in parent class {@link Address}, but the subclass is still
* necessary to pick up the contact namespace.
* <p>This class is embedded inside the {@link PostalInfo} of an EPP contact to hold its address.
* The fields are all defined in parent class {@link Address}, but the subclass is still necessary
* to pick up the contact namespace.
*
* <p>This does not implement {@code Overlayable} because it is intended to be bulk replaced on
* update.
@@ -30,6 +31,7 @@ import google.registry.model.eppcommon.Address;
* @see PostalInfo
*/
@Embed
@Embeddable
public class ContactAddress extends Address {
/** Builder for {@link ContactAddress}. */

View File

@@ -20,6 +20,7 @@ import javax.xml.bind.annotation.XmlType;
/** A version of authInfo specifically for contacts. */
@Embed
@javax.persistence.Embeddable
@XmlType(namespace = "urn:ietf:params:xml:ns:contact-1.0")
public class ContactAuthInfo extends AuthInfo {
public static ContactAuthInfo create(PasswordAuth pw) {

View File

@@ -16,17 +16,19 @@ package google.registry.model.contact;
import com.googlecode.objectify.annotation.Embed;
import google.registry.model.eppcommon.PhoneNumber;
import javax.persistence.Embeddable;
/**
* EPP Contact Phone Number
*
* <p>This class is embedded inside a {@link ContactResource} hold the phone number of an EPP
* contact. The fields are all defined in the parent class {@link PhoneNumber}, but the subclass is
* contact. The fields are all defined in the parent class {@link PhoneNumber}, but the subclass is
* still necessary to pick up the contact namespace.
*
* @see ContactResource
*/
@Embed
@Embeddable
public class ContactPhoneNumber extends PhoneNumber {
/** Builder for {@link ContactPhoneNumber}. */

View File

@@ -33,6 +33,11 @@ import google.registry.model.transfer.TransferData;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlElement;
import org.joda.time.DateTime;
@@ -43,9 +48,19 @@ import org.joda.time.DateTime;
*/
@ReportedOn
@Entity
@javax.persistence.Entity(name = "Contact")
@javax.persistence.Table(
name = "Contact",
indexes = {
@javax.persistence.Index(columnList = "creationTime"),
@javax.persistence.Index(columnList = "currentSponsorClientId"),
@javax.persistence.Index(columnList = "deletionTime"),
@javax.persistence.Index(columnList = "contactId", unique = true),
@javax.persistence.Index(columnList = "searchName")
})
@ExternalMessagingName("contact")
public class ContactResource extends EppResource implements
ForeignKeyedEppResource, ResourceWithTransferData {
public class ContactResource extends EppResource
implements ForeignKeyedEppResource, ResourceWithTransferData {
/**
* Unique identifier for this contact.
@@ -61,13 +76,55 @@ public class ContactResource extends EppResource implements
* US-ASCII character set. Personal info; cleared by {@link Builder#wipeOut}.
*/
@IgnoreSave(IfNull.class)
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "addr_local_name")),
@AttributeOverride(name = "org", column = @Column(name = "addr_local_org")),
@AttributeOverride(name = "type", column = @Column(name = "addr_local_type")),
@AttributeOverride(
name = "address.streetLine1",
column = @Column(name = "addr_local_street_line1")),
@AttributeOverride(
name = "address.streetLine2",
column = @Column(name = "addr_local_street_line2")),
@AttributeOverride(
name = "address.streetLine3",
column = @Column(name = "addr_local_street_line3")),
@AttributeOverride(name = "address.city", column = @Column(name = "addr_local_city")),
@AttributeOverride(name = "address.state", column = @Column(name = "addr_local_state")),
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_local_zip")),
@AttributeOverride(
name = "address.countryCode",
column = @Column(name = "addr_local_country_code"))
})
PostalInfo localizedPostalInfo;
/**
* Internationalized postal info for the contact. Personal info; cleared by
* {@link Builder#wipeOut}.
* Internationalized postal info for the contact. Personal info; cleared by {@link
* Builder#wipeOut}.
*/
@IgnoreSave(IfNull.class)
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "addr_i18n_name")),
@AttributeOverride(name = "org", column = @Column(name = "addr_i18n_org")),
@AttributeOverride(name = "type", column = @Column(name = "addr_i18n_type")),
@AttributeOverride(
name = "address.streetLine1",
column = @Column(name = "addr_i18n_street_line1")),
@AttributeOverride(
name = "address.streetLine2",
column = @Column(name = "addr_i18n_street_line2")),
@AttributeOverride(
name = "address.streetLine3",
column = @Column(name = "addr_i18n_street_line3")),
@AttributeOverride(name = "address.city", column = @Column(name = "addr_i18n_city")),
@AttributeOverride(name = "address.state", column = @Column(name = "addr_i18n_state")),
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_i18n_zip")),
@AttributeOverride(
name = "address.countryCode",
column = @Column(name = "addr_i18n_country_code"))
})
PostalInfo internationalizedPostalInfo;
/**
@@ -80,10 +137,20 @@ public class ContactResource extends EppResource implements
/** Contacts voice number. Personal info; cleared by {@link Builder#wipeOut}. */
@IgnoreSave(IfNull.class)
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "phoneNumber", column = @Column(name = "voice_phone_number")),
@AttributeOverride(name = "extension", column = @Column(name = "voice_phone_extension")),
})
ContactPhoneNumber voice;
/** Contacts fax number. Personal info; cleared by {@link Builder#wipeOut}. */
@IgnoreSave(IfNull.class)
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "phoneNumber", column = @Column(name = "fax_phone_number")),
@AttributeOverride(name = "extension", column = @Column(name = "fax_phone_extension")),
})
ContactPhoneNumber fax;
/** Contacts email address. Personal info; cleared by {@link Builder#wipeOut}. */
@@ -91,10 +158,16 @@ public class ContactResource extends EppResource implements
String email;
/** Authorization info (aka transfer secret) of the contact. */
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
})
ContactAuthInfo authInfo;
/** Data about any pending or past transfers on this contact. */
TransferData transferData;
// TODO(b/153363295): Figure out how to persist transfer data
@Transient TransferData transferData;
/**
* The time that this resource was last transferred.
@@ -107,6 +180,16 @@ public class ContactResource extends EppResource implements
// the wipeOut() function, so that data is not kept around for deleted contacts.
/** Disclosure policy. */
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "disclose_types_name")),
@AttributeOverride(name = "org", column = @Column(name = "disclose_types_org")),
@AttributeOverride(name = "addr", column = @Column(name = "disclose_types_addr")),
@AttributeOverride(name = "flag", column = @Column(name = "disclose_mode_flag")),
@AttributeOverride(name = "voice.marked", column = @Column(name = "disclose_show_voice")),
@AttributeOverride(name = "fax.marked", column = @Column(name = "disclose_show_fax")),
@AttributeOverride(name = "email.marked", column = @Column(name = "disclose_show_email"))
})
Disclose disclose;
public String getContactId() {

View File

@@ -22,11 +22,14 @@ import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
import google.registry.model.eppcommon.PresenceMarker;
import java.util.List;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
/** The "discloseType" from {@link "http://tools.ietf.org/html/rfc5733"}. */
@Embed
@Embeddable
@XmlType(propOrder = {"name", "org", "addr", "voice", "fax", "email"})
public class Disclose extends ImmutableObject {
@@ -36,11 +39,11 @@ public class Disclose extends ImmutableObject {
List<PostalInfoChoice> addr;
PresenceMarker voice;
@Embedded PresenceMarker voice;
PresenceMarker fax;
@Embedded PresenceMarker fax;
PresenceMarker email;
@Embedded PresenceMarker email;
@XmlAttribute
Boolean flag;

View File

@@ -21,6 +21,9 @@ import google.registry.model.Buildable;
import google.registry.model.Buildable.Overlayable;
import google.registry.model.ImmutableObject;
import java.util.Optional;
import javax.persistence.Embeddable;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlEnumValue;
@@ -29,10 +32,11 @@ import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/**
* Implementation of both "postalInfoType" and "chgPostalInfoType" from
* {@link "http://tools.ietf.org/html/rfc5733"}.
* Implementation of both "postalInfoType" and "chgPostalInfoType" from {@link
* "http://tools.ietf.org/html/rfc5733"}.
*/
@Embed
@Embeddable
@XmlType(propOrder = {"name", "org", "address", "type"})
public class PostalInfo extends ImmutableObject implements Overlayable<PostalInfo> {
@@ -53,6 +57,7 @@ public class PostalInfo extends ImmutableObject implements Overlayable<PostalInf
@XmlElement(name = "addr")
ContactAddress address;
@Enumerated(EnumType.STRING)
@XmlAttribute
Type type;

View File

@@ -66,6 +66,7 @@ import google.registry.model.registry.Registry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.schema.replay.DatastoreAndSqlEntity;
import google.registry.util.CollectionUtils;
import java.util.HashSet;
import java.util.Objects;
@@ -78,6 +79,7 @@ import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.JoinTable;
import javax.persistence.Transient;
import org.joda.time.DateTime;
import org.joda.time.Interval;
@@ -105,7 +107,7 @@ import org.joda.time.Interval;
})
@ExternalMessagingName("domain")
public class DomainBase extends EppResource
implements ForeignKeyedEppResource, ResourceWithTransferData {
implements ForeignKeyedEppResource, ResourceWithTransferData, DatastoreAndSqlEntity {
/** The max number of years that a domain can be registered for, as set by ICANN policy. */
public static final int MAX_REGISTRATION_YEARS = 10;
@@ -141,7 +143,10 @@ public class DomainBase extends EppResource
*/
@Index @ElementCollection @Transient Set<Key<HostResource>> nsHosts;
@Ignore @Transient Set<VKey<HostResource>> nsHostVKeys;
@Ignore
@ElementCollection
@JoinTable(name = "DomainHost")
Set<VKey<HostResource>> nsHostVKeys;
/**
* The union of the contacts visible via {@link #getContacts} and {@link #getRegistrant}.

View File

@@ -18,6 +18,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
import javax.persistence.Embeddable;
import javax.persistence.MappedSuperclass;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;
@@ -31,17 +33,21 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
* "e164Type" type from {@link "http://tools.ietf.org/html/draft-lozano-tmch-smd"}.
*
* <blockquote>
*
* <p>"Contact telephone number structure is derived from structures defined in [ITU.E164.2005].
* Telephone numbers described in this mapping are character strings that MUST begin with a plus
* sign ("+", ASCII value 0x002B), followed by a country code defined in [ITU.E164.2005], followed
* by a dot (".", ASCII value 0x002E), followed by a sequence of digits representing the telephone
* number. An optional "x" attribute is provided to note telephone extension information."
*
* </blockquote>
*
* @see google.registry.model.contact.ContactPhoneNumber
* @see google.registry.model.mark.MarkPhoneNumber
*/
@XmlTransient
@Embeddable
@MappedSuperclass
public class PhoneNumber extends ImmutableObject {
@XmlValue

View File

@@ -17,6 +17,7 @@ package google.registry.model.eppcommon;
import com.googlecode.objectify.annotation.Embed;
import google.registry.model.ImmutableObject;
import java.io.Serializable;
import javax.persistence.Embeddable;
import javax.xml.bind.annotation.XmlTransient;
/**
@@ -26,6 +27,7 @@ import javax.xml.bind.annotation.XmlTransient;
* {@code <foo></foo>}, and will unmarshal always to {@code <foo/>}.
*/
@Embed
@Embeddable
public class PresenceMarker extends ImmutableObject implements Serializable {
@XmlTransient
boolean marked = true;

View File

@@ -34,23 +34,27 @@ import google.registry.model.annotations.ReportedOn;
import google.registry.model.domain.DomainBase;
import google.registry.model.transfer.TransferData;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import java.net.InetAddress;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import javax.persistence.ElementCollection;
import org.joda.time.DateTime;
/**
* A persistable Host resource including mutable and non-mutable fields.
*
* <p>A host's {@link TransferData} is stored on the superordinate domain. Non-subordinate hosts
* <p>A host's {@link TransferData} is stored on the superordinate domain. Non-subordinate hosts
* don't carry a full set of TransferData; all they have is lastTransferTime.
*
* @see <a href="https://tools.ietf.org/html/rfc5732">RFC 5732</a>
*/
@ReportedOn
@Entity
@javax.persistence.Entity
@ExternalMessagingName("host")
@WithStringVKey
public class HostResource extends EppResource implements ForeignKeyedEppResource {
/**
@@ -64,8 +68,7 @@ public class HostResource extends EppResource implements ForeignKeyedEppResource
String fullyQualifiedHostName;
/** IP Addresses for this host. Can be null if this is an external host. */
@Index
Set<InetAddress> inetAddresses;
@Index @ElementCollection Set<InetAddress> inetAddresses;
/** The superordinate domain of this host, or null if this is an external host. */
@Index

View File

@@ -151,11 +151,14 @@ public class ObjectifyService {
String kind = Key.getKind(clazz);
boolean registered = factory().getMetadata(kind) != null;
if (clazz.isAnnotationPresent(Entity.class)) {
// Objectify silently ignores re-registrations for a given kind string, even if the classes
// being registered are distinct. Throw an exception if that would happen here.
checkState(!registered,
// Objectify silently replaces current registration for a given kind string when a different
// class is registered again for this kind. For simplicity's sake, throw an exception on any
// re-registration.
checkState(
!registered,
"Kind '%s' already registered, cannot register new @Entity %s",
kind, clazz.getCanonicalName());
kind,
clazz.getCanonicalName());
} else if (clazz.isAnnotationPresent(EntitySubclass.class)) {
// Ensure that any @EntitySubclass classes have also had their parent @Entity registered,
// which Objectify nominally requires but doesn't enforce in 4.x (though it may in 5.x).

View File

@@ -73,6 +73,7 @@ import google.registry.model.annotations.ReportedOn;
import google.registry.model.common.EntityGroupRoot;
import google.registry.model.registrar.Registrar.BillingAccountEntry.CurrencyMapper;
import google.registry.model.registry.Registry;
import google.registry.schema.replay.DatastoreAndSqlEntity;
import google.registry.util.CidrAddressBlock;
import java.security.cert.CertificateParsingException;
import java.util.Comparator;
@@ -107,11 +108,12 @@ import org.joda.time.DateTime;
columnList = "ianaIdentifier",
name = "registrar_iana_identifier_idx"),
})
public class Registrar extends ImmutableObject implements Buildable, Jsonifiable {
public class Registrar extends ImmutableObject
implements Buildable, Jsonifiable, DatastoreAndSqlEntity {
/** Represents the type of a registrar entity. */
public enum Type {
/** A real-world, third-party registrar. Should have non-null IANA and billing IDs. */
/** A real-world, third-party registrar. Should have non-null IANA and billing IDs. */
REAL(Objects::nonNull),
/**

View File

@@ -16,7 +16,6 @@ package google.registry.model.server;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
@@ -29,7 +28,6 @@ import com.googlecode.objectify.annotation.Id;
import google.registry.model.ImmutableObject;
import google.registry.model.annotations.NotBackedUp;
import google.registry.model.annotations.NotBackedUp.Reason;
import google.registry.schema.server.LockDao;
import google.registry.util.RequestStatusChecker;
import google.registry.util.RequestStatusCheckerImpl;
import java.io.Serializable;
@@ -197,22 +195,6 @@ public class Lock extends ImmutableObject implements Serializable {
// Checking if an unexpired lock still exists - if so, the lock can't be acquired.
Lock lock = ofy().load().type(Lock.class).id(lockId).now();
try {
jpaTm()
.transact(
() -> {
Optional<google.registry.schema.server.Lock> cloudSqlLockOptional;
if (tld == null) {
cloudSqlLockOptional = LockDao.load(resourceName);
} else {
cloudSqlLockOptional = LockDao.load(resourceName, tld);
}
LockDao.compare(Optional.ofNullable(lock), cloudSqlLockOptional);
});
} catch (Exception e) {
logger.atSevere().withCause(e).log(
"Issue loading and comparing lock from Cloud SQL");
}
if (lock != null) {
logger.atInfo().log(
"Loaded existing lock: %s for request: %s", lock.lockId, lock.requestLogId);
@@ -237,35 +219,6 @@ public class Lock extends ImmutableObject implements Serializable {
// don't need to be backed up.
ofy().saveWithoutBackup().entity(newLock);
// create and save the lock to Cloud SQL
try {
jpaTm()
.transact(
() -> {
google.registry.schema.server.Lock cloudSqlLock;
if (tld == null) {
cloudSqlLock =
google.registry.schema.server.Lock.createGlobal(
resourceName,
requestStatusChecker.getLogId(),
now,
leaseLength);
} else {
cloudSqlLock =
google.registry.schema.server.Lock.create(
resourceName,
tld,
requestStatusChecker.getLogId(),
now,
leaseLength);
}
LockDao.save(cloudSqlLock);
});
} catch (Exception e) {
logger.atSevere().withCause(e).log(
"Error saving lock to Cloud SQL: %s", newLock);
}
return AcquireResult.create(now, lock, newLock, lockState);
});
@@ -284,44 +237,12 @@ public class Lock extends ImmutableObject implements Serializable {
// this can happen if release() is called around the expiration time and the lock
// expires underneath us.
Lock loadedLock = ofy().load().type(Lock.class).id(lockId).now();
try {
jpaTm()
.transact(
() -> {
Optional<google.registry.schema.server.Lock> cloudSqlLockOptional;
if (tld == null) {
cloudSqlLockOptional = LockDao.load(resourceName);
} else {
cloudSqlLockOptional = LockDao.load(resourceName, tld);
}
LockDao.compare(Optional.ofNullable(loadedLock), cloudSqlLockOptional);
});
} catch (Exception e) {
logger.atSevere().withCause(e).log(
"Issue loading and comparing lock from Cloud SQL");
}
if (Lock.this.equals(loadedLock)) {
// Use noBackupOfy() so that we don't create a commit log entry for deleting the
// lock.
logger.atInfo().log("Deleting lock: %s", lockId);
ofy().deleteWithoutBackup().entity(Lock.this);
// Remove the lock from Cloud SQL
try {
jpaTm()
.transact(
() -> {
if (tld == null) {
LockDao.delete(resourceName);
} else {
LockDao.delete(resourceName, tld);
}
});
} catch (Exception e) {
logger.atSevere().withCause(e).log(
"Error deleting lock from Cloud SQL: %s", loadedLock);
}
lockMetrics.recordRelease(
resourceName, tld, new Duration(acquiredTime, tm().getTransactionTime()));
} else {

View File

@@ -18,6 +18,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;
@@ -31,6 +32,7 @@ import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import javax.persistence.Transient;
/**
* A listener class to invoke entity callbacks in cases where Hibernate doesn't invoke the callback
@@ -167,10 +169,12 @@ public class EntityCallbacksListener {
private Stream<Object> findEmbeddedProperties(Object object, Class<?> clazz) {
return Arrays.stream(clazz.getDeclaredFields())
.filter(field -> !field.isAnnotationPresent(Transient.class))
.filter(
field ->
field.isAnnotationPresent(Embedded.class)
|| field.getType().isAnnotationPresent(Embeddable.class))
.filter(field -> !Modifier.isStatic(field.getModifiers()))
.map(field -> getFieldObject(field, object))
.filter(Objects::nonNull);
}

View File

@@ -17,9 +17,7 @@ package google.registry.persistence;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.config.RegistryConfig.getHibernateConnectionIsolation;
import static google.registry.config.RegistryConfig.getHibernateHikariConnectionTimeout;
import static google.registry.config.RegistryConfig.getHibernateHikariIdleTimeout;
import static google.registry.config.RegistryConfig.getHibernateHikariMaximumPoolSize;
import static google.registry.config.RegistryConfig.getHibernateHikariMinimumIdle;
import static google.registry.config.RegistryConfig.getHibernateLogSqlQueries;
import com.google.api.client.auth.oauth2.Credential;
@@ -50,10 +48,7 @@ public class PersistenceModule {
// This name must be the same as the one defined in persistence.xml.
public static final String PERSISTENCE_UNIT_NAME = "nomulus";
public static final String HIKARI_CONNECTION_TIMEOUT = "hibernate.hikari.connectionTimeout";
public static final String HIKARI_MINIMUM_IDLE = "hibernate.hikari.minimumIdle";
public static final String HIKARI_MAXIMUM_POOL_SIZE = "hibernate.hikari.maximumPoolSize";
public static final String HIKARI_IDLE_TIMEOUT = "hibernate.hikari.idleTimeout";
public static final String HIKARI_DS_SOCKET_FACTORY = "hibernate.hikari.dataSource.socketFactory";
public static final String HIKARI_DS_CLOUD_SQL_INSTANCE =
"hibernate.hikari.dataSource.cloudSqlInstance";
@@ -79,9 +74,7 @@ public class PersistenceModule {
properties.put(Environment.ISOLATION, getHibernateConnectionIsolation());
properties.put(Environment.SHOW_SQL, getHibernateLogSqlQueries());
properties.put(HIKARI_CONNECTION_TIMEOUT, getHibernateHikariConnectionTimeout());
properties.put(HIKARI_MINIMUM_IDLE, getHibernateHikariMinimumIdle());
properties.put(HIKARI_MAXIMUM_POOL_SIZE, getHibernateHikariMaximumPoolSize());
properties.put(HIKARI_IDLE_TIMEOUT, getHibernateHikariIdleTimeout());
properties.put(Environment.DIALECT, NomulusPostgreSQLDialect.class.getName());
return properties.build();
}

View File

@@ -15,6 +15,7 @@
package google.registry.persistence;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.ImmutableObject;
import java.util.Optional;
@@ -41,20 +42,31 @@ public class VKey<T> extends ImmutableObject {
this.primaryKey = primaryKey;
}
public static <T> VKey<T> createSql(Class<? extends T> kind, Object primaryKey) {
return new VKey(kind, null, primaryKey);
/** Creates a {@link VKey} which only contains the sql primary key. */
public static <T> VKey<T> createSql(Class<? extends T> kind, Object sqlKey) {
checkArgumentNotNull(kind, "kind must not be null");
checkArgumentNotNull(sqlKey, "sqlKey must not be null");
return new VKey(kind, null, sqlKey);
}
/** Creates a {@link VKey} which only contains the ofy primary key. */
public static <T> VKey<T> createOfy(
Class<? extends T> kind, com.googlecode.objectify.Key<T> ofyKey) {
Class<? extends T> kind, com.googlecode.objectify.Key<? extends T> ofyKey) {
checkArgumentNotNull(kind, "kind must not be null");
checkArgumentNotNull(ofyKey, "ofyKey must not be null");
return new VKey(kind, ofyKey, null);
}
/** Creates a {@link VKey} which only contains both sql and ofy primary key. */
public static <T> VKey<T> create(
Class<? extends T> kind, Object primaryKey, com.googlecode.objectify.Key ofyKey) {
return new VKey(kind, ofyKey, primaryKey);
Class<? extends T> kind, Object sqlKey, com.googlecode.objectify.Key ofyKey) {
checkArgumentNotNull(kind, "kind must not be null");
checkArgumentNotNull(sqlKey, "sqlKey must not be null");
checkArgumentNotNull(ofyKey, "ofyKey must not be null");
return new VKey(kind, ofyKey, sqlKey);
}
/** Returns the type of the entity. */
public Class<? extends T> getKind() {
return this.kind;
}

View File

@@ -0,0 +1,34 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.persistence;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import javax.persistence.AttributeConverter;
import javax.persistence.Entity;
/**
* Annotation for {@link Entity} which id is long type and needs an {@link AttributeConverter} for
* its VKey.
*/
@Target({ElementType.TYPE})
public @interface WithLongVKey {
/**
* Sets the suffix of the class name for the {@link AttributeConverter} generated by
* LongVKeyProcessor. If not set, the suffix will be the type name of the VKey. Note that the
* class name will be "VKeyConverter_" concatenated with the suffix.
*/
String classNameSuffix() default "";
}

View File

@@ -0,0 +1,34 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.persistence;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import javax.persistence.AttributeConverter;
import javax.persistence.Entity;
/**
* Annotation for {@link Entity} which id is string type and needs an {@link AttributeConverter} for
* its VKey.
*/
@Target({ElementType.TYPE})
public @interface WithStringVKey {
/**
* Sets the suffix of the class name for the {@link AttributeConverter} generated by
* StringVKeyProcessor. If not set, the suffix will be the type name of the VKey. Note that the
* class name will be "VKeyConverter_" concatenated with the suffix.
*/
String classNameSuffix() default "";
}

View File

@@ -0,0 +1,36 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.persistence.converter;
import google.registry.model.contact.Disclose.PostalInfoChoice;
import google.registry.model.contact.PostalInfo;
import java.util.List;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** JPA {@link AttributeConverter} for storing/retrieving {@link List < PostalInfoChoice >}. */
@Converter(autoApply = true)
public class PostalInfoChoiceListConverter extends StringListConverterBase<PostalInfoChoice> {
@Override
String toString(PostalInfoChoice element) {
return element.getType().name();
}
@Override
PostalInfoChoice fromString(String value) {
return PostalInfoChoice.create(PostalInfo.Type.valueOf(value));
}
}

View File

@@ -18,24 +18,20 @@ import google.registry.persistence.VKey;
import javax.annotation.Nullable;
import javax.persistence.AttributeConverter;
/**
* Converts VKey to a string column.
*/
public abstract class VKeyConverter<T> implements AttributeConverter<VKey<T>, String> {
/** Converts VKey to a string column. */
public abstract class VKeyConverter<T, C> implements AttributeConverter<VKey<? extends T>, C> {
@Override
@Nullable
public String convertToDatabaseColumn(@Nullable VKey<T> attribute) {
return attribute == null ? null : (String) attribute.getSqlKey();
public C convertToDatabaseColumn(@Nullable VKey<? extends T> attribute) {
return attribute == null ? null : (C) attribute.getSqlKey();
}
@Override
@Nullable
public VKey<T> convertToEntityAttribute(@Nullable String dbData) {
public VKey<? extends T> convertToEntityAttribute(@Nullable C dbData) {
return dbData == null ? null : VKey.createSql(getAttributeClass(), dbData);
}
/**
* Returns the class of the attribute.
*/
/** Returns the class of the attribute. */
protected abstract Class<T> getAttributeClass();
}

View File

@@ -0,0 +1,31 @@
// Copyright 2020 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.schema.replay;
import com.google.common.collect.ImmutableList;
/** An entity that has the same Java object representation in SQL and Datastore. */
public interface DatastoreAndSqlEntity extends DatastoreEntity, SqlEntity {
@Override
default ImmutableList<DatastoreEntity> toDatastoreEntities() {
return ImmutableList.of(this);
}
@Override
default ImmutableList<SqlEntity> toSqlEntities() {
return ImmutableList.of(this);
}
}

View File

@@ -0,0 +1,30 @@
// Copyright 2020 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.schema.replay;
import com.google.common.collect.ImmutableList;
/**
* An object that can be stored in Datastore and serialized using Objectify's {@link
* com.googlecode.objectify.cmd.Saver#toEntity(Object)} code.
*
* <p>This is used when replaying {@link google.registry.model.ofy.CommitLogManifest}s to import
* transactions and data into the secondary SQL store during the first, Datastore-primary, phase of
* the migration.
*/
public interface DatastoreEntity {
ImmutableList<SqlEntity> toSqlEntities();
}

View File

@@ -0,0 +1,29 @@
// Copyright 2020 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.schema.replay;
import com.google.common.collect.ImmutableList;
/**
* An object that can be stored in Cloud SQL using {@link
* javax.persistence.EntityManager#persist(Object)}
*
* <p>This will be used when replaying SQL transactions into Datastore, during the second,
* SQL-primary, phase of the migration from Datastore to SQL.
*/
public interface SqlEntity {
ImmutableList<DatastoreEntity> toDatastoreEntities();
}

View File

@@ -153,8 +153,8 @@ public final class DomainLockUtils {
/**
* Creates and applies a lock in one step.
*
* <p>This should only be used for admin actions, e.g. Nomulus tool commands or relocks.
* Note: in the case of relocks, isAdmin is determined by the previous lock.
* <p>This should only be used for admin actions, e.g. Nomulus tool commands or relocks. Note: in
* the case of relocks, isAdmin is determined by the previous lock.
*/
public RegistryLock administrativelyApplyLock(
String domainName, String registrarId, @Nullable String registrarPocId, boolean isAdmin) {
@@ -175,7 +175,7 @@ public final class DomainLockUtils {
/**
* Creates and applies an unlock in one step.
*
*
* <p>This should only be used for admin actions, e.g. Nomulus tool commands.
*/
public RegistryLock administrativelyApplyUnlock(

View File

@@ -132,10 +132,8 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
jcommander.parse(args);
} catch (ParameterException e) {
// If we failed to fully parse the command but at least found a valid command name, show only
// the usage for that command. Otherwise, show full usage. Either way, rethrow the error.
if (jcommander.getParsedCommand() == null) {
jcommander.usage();
} else {
// the usage for that command.
if (jcommander.getParsedCommand() != null) {
jcommander.usage(jcommander.getParsedCommand());
}
// Don't rethrow if we said: nomulus command --help
@@ -144,8 +142,13 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
}
throw e;
}
if (showAllCommands) {
String parsedCommand = jcommander.getParsedCommand();
// Show the list of all commands either if requested or if no subcommand name was specified
// (which does not throw a ParameterException parse error above).
if (showAllCommands || parsedCommand == null) {
if (parsedCommand == null) {
System.out.println("The list of available subcommands is:");
}
commands.keySet().forEach(System.out::println);
return;
}
@@ -161,8 +164,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
// retrieving the first (and, by virtue of our usage, only) object from it.
Command command =
(Command)
Iterables.getOnlyElement(
jcommander.getCommands().get(jcommander.getParsedCommand()).getObjects());
Iterables.getOnlyElement(jcommander.getCommands().get(parsedCommand).getObjects());
loggingParams.configureLogging(); // Must be called after parameters are parsed.
try {

View File

@@ -15,6 +15,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.model.EppResourceUtils.loadByForeignKey;
import static google.registry.util.CollectionUtils.findDuplicates;
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
@@ -37,6 +38,13 @@ import org.joda.time.format.DateTimeFormatter;
@Parameters(separators = " =", commandDescription = "Renew domain(s) via EPP.")
final class RenewDomainCommand extends MutatingEppToolCommand {
@Parameter(
names = {"-c", "--client"},
description =
"The registrar to execute as and bill the renewal to; otherwise each domain's sponsoring"
+ " registrar. Renewals by non-sponsoring registrars require --superuser as well.")
String clientId;
@Parameter(
names = {"-p", "--period"},
description = "Number of years to renew the registration for (defaults to 1).")
@@ -63,7 +71,7 @@ final class RenewDomainCommand extends MutatingEppToolCommand {
setSoyTemplate(RenewDomainSoyInfo.getInstance(), RenewDomainSoyInfo.RENEWDOMAIN);
DomainBase domain = domainOptional.get();
addSoyRecord(
domain.getCurrentSponsorClientId(),
isNullOrEmpty(clientId) ? domain.getCurrentSponsorClientId() : clientId,
new SoyMapData(
"domainName", domain.getFullyQualifiedDomainName(),
"expirationDate", domain.getRegistrationExpirationTime().toString(DATE_FORMATTER),

View File

@@ -186,9 +186,7 @@ public final class RegistrarFormFields {
.build();
public static final FormField<String, String> REGISTRY_LOCK_EMAIL_ADDRESS_FIELD =
FormFields.EMAIL
.asBuilderNamed("registryLockEmailAddress")
.build();
FormFields.EMAIL.asBuilderNamed("registryLockEmailAddress").build();
public static final FormField<Boolean, Boolean> CONTACT_VISIBLE_IN_WHOIS_AS_ADMIN_FIELD =
FormField.named("visibleInWhoisAsAdmin", Boolean.class)

View File

@@ -391,7 +391,8 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
* @throws FormException if the checks fail.
*/
void checkContactRequirements(
Set<RegistrarContact> existingContacts, Set<RegistrarContact> updatedContacts) {
ImmutableSet<RegistrarContact> existingContacts,
ImmutableSet<RegistrarContact> updatedContacts) {
// Check that no two contacts use the same email address.
Set<String> emails = new HashSet<>();
for (RegistrarContact contact : updatedContacts) {
@@ -435,7 +436,12 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
throw new ContactRequirementException(
"An abuse contact visible in domain WHOIS query must be designated");
}
checkContactRegistryLockRequirements(existingContacts, updatedContacts);
}
private static void checkContactRegistryLockRequirements(
ImmutableSet<RegistrarContact> existingContacts,
ImmutableSet<RegistrarContact> updatedContacts) {
// Any contact(s) with new passwords must be allowed to set them
for (RegistrarContact updatedContact : updatedContacts) {
if (updatedContact.isRegistryLockAllowed()
@@ -463,6 +469,31 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
}
}
}
// Any previously-existing contacts with registry lock enabled cannot be deleted
existingContacts.stream()
.filter(RegistrarContact::isRegistryLockAllowed)
.forEach(
contact -> {
Optional<RegistrarContact> updatedContactOptional =
updatedContacts.stream()
.filter(
updatedContact ->
updatedContact.getEmailAddress().equals(contact.getEmailAddress()))
.findFirst();
if (!updatedContactOptional.isPresent()) {
throw new FormException(
String.format(
"Cannot delete the contact %s that has registry lock enabled",
contact.getEmailAddress()));
}
if (!updatedContactOptional.get().isRegistryLockAllowed()) {
throw new FormException(
String.format(
"Cannot remove the ability to use registry lock on the contact %s",
contact.getEmailAddress()));
}
});
}
/**

View File

@@ -19,7 +19,9 @@
* Move tests to another (sub)project. This is not a big problem, but feels unnatural.
* Use Hibernate's ServiceRegistry for bootstrapping (not JPA-compliant)
-->
<class>google.registry.model.contact.ContactResource</class>
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.model.host.HostResource</class>
<class>google.registry.model.registrar.Registrar</class>
<class>google.registry.model.registrar.RegistrarContact</class>
<class>google.registry.schema.domain.RegistryLock</class>
@@ -40,6 +42,7 @@
<class>google.registry.persistence.converter.CurrencyUnitConverter</class>
<class>google.registry.persistence.converter.DateTimeConverter</class>
<class>google.registry.persistence.converter.DurationConverter</class>
<class>google.registry.persistence.converter.PostalInfoChoiceListConverter</class>
<class>google.registry.persistence.converter.RegistrarPocSetConverter</class>
<class>google.registry.persistence.converter.StatusValueSetConverter</class>
<class>google.registry.persistence.converter.StringListConverter</class>
@@ -47,6 +50,9 @@
<class>google.registry.persistence.converter.UpdateAutoTimestampConverter</class>
<class>google.registry.persistence.converter.ZonedDateTimeConverter</class>
<!-- Generated converters for VKey -->
<class>google.registry.model.host.VKeyConverter_HostResource</class>
<!-- TODO(weiminyu): check out application-layer validation. -->
<validation-mode>NONE</validation-mode>
</persistence-unit>

View File

@@ -145,6 +145,7 @@
{param label: 'Email' /}
{param namePrefix: $namePrefix /}
{param name: 'emailAddress' /}
{param disabled: not $readonly and $item['emailAddress'] != null /}
{/call}
{call registry.soy.forms.inputFieldRow data="all"}
{param label: 'Phone' /}

View File

@@ -64,8 +64,8 @@ public class DumpGoldenSchemaCommand extends PostgresqlCommand {
if (result.getExitCode() != 0) {
throw new RuntimeException(result.toString());
}
result = postgresContainer.execInContainer(
"cp", CONTAINER_MOUNT_POINT_TMP, CONTAINER_MOUNT_POINT);
result =
postgresContainer.execInContainer("cp", CONTAINER_MOUNT_POINT_TMP, CONTAINER_MOUNT_POINT);
if (result.getExitCode() != 0) {
throw new RuntimeException(result.toString());
}

View File

@@ -50,7 +50,11 @@ import org.junit.runners.JUnit4;
public class ExportCommitLogDiffActionTest {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
public final AppEngineRule appEngine =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(TestObject.class)
.build();
/** Local GCS service available for testing. */
private final GcsService gcsService = GcsServiceFactory.createGcsService();

View File

@@ -71,7 +71,11 @@ public class RestoreCommitLogsActionTest {
final GcsService gcsService = createGcsService();
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
public final AppEngineRule appEngine =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(TestObject.class)
.build();
@Before
public void init() {

View File

@@ -153,6 +153,8 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
doSuccessfulTest(
responseFilename,
renewalYears,
"TheRegistrar",
UserPrivileges.NORMAL,
substitutions,
Money.of(USD, 11).multipliedBy(renewalYears));
}
@@ -160,13 +162,16 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
private void doSuccessfulTest(
String responseFilename,
int renewalYears,
String renewalClientId,
UserPrivileges userPrivileges,
Map<String, String> substitutions,
Money totalRenewCost)
throws Exception {
assertTransactionalFlow(true);
DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime();
DateTime newExpiration = currentExpiration.plusYears(renewalYears);
runFlowAssertResponse(loadFile(responseFilename, substitutions));
runFlowAssertResponse(
CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions));
DomainBase domain = reloadResourceByForeignKey();
HistoryEntry historyEntryDomainRenew =
getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_RENEW);
@@ -183,13 +188,13 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
.and()
.hasLastEppUpdateTime(clock.nowUtc())
.and()
.hasLastEppUpdateClientId("TheRegistrar");
.hasLastEppUpdateClientId(renewalClientId);
assertAboutHistoryEntries().that(historyEntryDomainRenew).hasPeriodYears(renewalYears);
BillingEvent.OneTime renewBillingEvent =
new BillingEvent.OneTime.Builder()
.setReason(Reason.RENEW)
.setTargetId(getUniqueIdFromCommand())
.setClientId("TheRegistrar")
.setClientId(renewalClientId)
.setCost(totalRenewCost)
.setPeriodYears(renewalYears)
.setEventTime(clock.nowUtc())
@@ -233,7 +238,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
GracePeriod.create(
GracePeriodStatus.RENEW,
clock.nowUtc().plus(Registry.get("tld").getRenewGracePeriodLength()),
"TheRegistrar",
renewalClientId,
null),
renewBillingEvent));
}
@@ -256,6 +261,19 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2005-04-03T22:00:00.0Z"));
}
@Test
public void testSuccess_recurringClientIdIsSame_whenSuperuserOverridesRenewal() throws Exception {
persistDomain();
setClientIdForFlow("NewRegistrar");
doSuccessfulTest(
"domain_renew_response.xml",
5,
"NewRegistrar",
UserPrivileges.SUPERUSER,
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2005-04-03T22:00:00.0Z"),
Money.of(USD, 55));
}
@Test
public void testSuccess_customLogicFee() throws Exception {
// The "costly-renew" domain has an additional RENEW fee of 100 from custom logic on top of the
@@ -269,7 +287,13 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
"FEE", "111.00");
setEppInput("domain_renew_fee.xml", customFeeMap);
persistDomain();
doSuccessfulTest("domain_renew_response_fee.xml", 1, customFeeMap, Money.of(USD, 111));
doSuccessfulTest(
"domain_renew_response_fee.xml",
1,
"TheRegistrar",
UserPrivileges.NORMAL,
customFeeMap,
Money.of(USD, 111));
}
@Test
@@ -687,7 +711,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
@Test
public void testFailure_unauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
setClientIdForFlow("NewRegistrar");
persistActiveDomain(getUniqueIdFromCommand());
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
@@ -695,7 +719,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
@Test
public void testSuccess_superuserUnauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
setClientIdForFlow("NewRegistrar");
persistDomain();
runFlowAssertResponse(
CommitMode.LIVE,

View File

@@ -19,12 +19,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static org.joda.time.DateTimeZone.UTC;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.annotation.Entity;
import google.registry.model.common.CrossTldSingleton;
import google.registry.testing.AppEngineRule;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,19 +33,18 @@ import org.junit.runners.JUnit4;
public class CreateAutoTimestampTest {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
public final AppEngineRule appEngine =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(TestObject.class)
.build();
/** Timestamped class. */
@Entity
@Entity(name = "CatTestEntity")
public static class TestObject extends CrossTldSingleton {
CreateAutoTimestamp createTime = CreateAutoTimestamp.create(null);
}
@Before
public void before() {
ObjectifyService.register(TestObject.class);
}
private TestObject reload() {
return ofy().load().entity(new TestObject()).now();
}

View File

@@ -27,7 +27,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import google.registry.testing.AppEngineRule;
@@ -39,7 +38,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,12 +48,11 @@ import org.junit.runners.JUnit4;
public class ImmutableObjectTest {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
@Before
public void register() {
ObjectifyService.register(ValueObject.class);
}
public final AppEngineRule appEngine =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(ValueObject.class)
.build();
/** Simple subclass of ImmutableObject. */
public static class SimpleObject extends ImmutableObject {

View File

@@ -19,12 +19,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static org.joda.time.DateTimeZone.UTC;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.annotation.Entity;
import google.registry.model.common.CrossTldSingleton;
import google.registry.testing.AppEngineRule;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,19 +33,18 @@ import org.junit.runners.JUnit4;
public class UpdateAutoTimestampTest {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
public final AppEngineRule appEngine =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(TestObject.class)
.build();
/** Timestamped class. */
@Entity
@Entity(name = "UatTestEntity")
public static class TestObject extends CrossTldSingleton {
UpdateAutoTimestamp updateTime = UpdateAutoTimestamp.create(null);
}
@Before
public void before() {
ObjectifyService.register(TestObject.class);
}
private TestObject reload() {
return ofy().load().entity(new TestObject()).now();
}

View File

@@ -17,10 +17,13 @@ package google.registry.model.contact;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.ContactResourceSubject.assertAboutContacts;
import static google.registry.testing.DatastoreHelper.cloneAndSetAutoTimestamps;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static org.junit.Assert.assertThrows;
@@ -37,87 +40,119 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import org.junit.Before;
import org.junit.Test;
import google.registry.persistence.VKey;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link ContactResource}. */
public class ContactResourceTest extends EntityTestCase {
ContactResource originalContact;
ContactResource contactResource;
@Before
public ContactResourceTest() {
super(true);
}
@BeforeEach
public void setUp() {
createTld("foobar");
originalContact =
new ContactResource.Builder()
.setContactId("contact_id")
.setRepoId("1-FOOBAR")
.setCreationClientId("registrar1")
.setLastEppUpdateTime(fakeClock.nowUtc())
.setLastEppUpdateClientId("registrar2")
.setLastTransferTime(fakeClock.nowUtc())
.setPersistedCurrentSponsorClientId("registrar3")
.setLocalizedPostalInfo(
new PostalInfo.Builder()
.setType(Type.LOCALIZED)
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
.setCity("New York")
.setState("NY")
.setZip("10011")
.setCountryCode("US")
.build())
.build())
.setInternationalizedPostalInfo(
new PostalInfo.Builder()
.setType(Type.INTERNATIONALIZED)
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
.setCity("New York")
.setState("NY")
.setZip("10011")
.setCountryCode("US")
.build())
.build())
.setVoiceNumber(new ContactPhoneNumber.Builder().setPhoneNumber("867-5309").build())
.setFaxNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("867-5309")
.setExtension("1000")
.build())
.setEmailAddress("jenny@example.com")
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("passw0rd")))
.setDisclose(
new Disclose.Builder()
.setVoice(new PresenceMarker())
.setEmail(new PresenceMarker())
.setFax(new PresenceMarker())
.setFlag(true)
.setAddrs(ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
.setNames(ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
.setOrgs(ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
.build())
.setStatusValues(ImmutableSet.of(StatusValue.OK))
.setTransferData(
new TransferData.Builder()
.setGainingClientId("gaining")
.setLosingClientId("losing")
.setPendingTransferExpirationTime(fakeClock.nowUtc())
.setServerApproveEntities(
ImmutableSet.of(Key.create(BillingEvent.OneTime.class, 1)))
.setTransferRequestTime(fakeClock.nowUtc())
.setTransferStatus(TransferStatus.SERVER_APPROVED)
.setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
.build())
.build();
// Set up a new persisted ContactResource entity.
contactResource =
persistResource(
cloneAndSetAutoTimestamps(
new ContactResource.Builder()
.setContactId("contact_id")
.setRepoId("1-FOOBAR")
.setCreationClientId("a registrar")
.setLastEppUpdateTime(fakeClock.nowUtc())
.setLastEppUpdateClientId("another registrar")
.setLastTransferTime(fakeClock.nowUtc())
.setPersistedCurrentSponsorClientId("a third registrar")
.setLocalizedPostalInfo(
new PostalInfo.Builder()
.setType(Type.LOCALIZED)
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
.setCity("New York")
.setState("NY")
.setZip("10011")
.setCountryCode("US")
.build())
.build())
.setInternationalizedPostalInfo(
new PostalInfo.Builder()
.setType(Type.INTERNATIONALIZED)
.setAddress(
new ContactAddress.Builder()
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
.setCity("New York")
.setState("NY")
.setZip("10011")
.setCountryCode("US")
.build())
.build())
.setVoiceNumber(
new ContactPhoneNumber.Builder().setPhoneNumber("867-5309").build())
.setFaxNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("867-5309")
.setExtension("1000")
.build())
.setEmailAddress("jenny@example.com")
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("passw0rd")))
.setDisclose(
new Disclose.Builder()
.setVoice(new PresenceMarker())
.setEmail(new PresenceMarker())
.setFax(new PresenceMarker())
.setFlag(true)
.setAddrs(
ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
.setNames(
ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
.setOrgs(
ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
.build())
.setStatusValues(ImmutableSet.of(StatusValue.OK))
.setTransferData(
new TransferData.Builder()
.setGainingClientId("gaining")
.setLosingClientId("losing")
.setPendingTransferExpirationTime(fakeClock.nowUtc())
.setServerApproveEntities(
ImmutableSet.of(Key.create(BillingEvent.OneTime.class, 1)))
.setTransferRequestTime(fakeClock.nowUtc())
.setTransferStatus(TransferStatus.SERVER_APPROVED)
.setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
.build())
.build()));
contactResource = persistResource(cloneAndSetAutoTimestamps(originalContact));
}
@Test
public void testCloudSqlPersistence_failWhenViolateForeignKeyConstraint() {
assertThrowForeignKeyViolation(() -> jpaTm().transact(() -> jpaTm().saveNew(originalContact)));
}
@Test
public void testCloudSqlPersistence_succeed() {
saveRegistrar("registrar1");
saveRegistrar("registrar2");
saveRegistrar("registrar3");
jpaTm().transact(() -> jpaTm().saveNew(originalContact));
ContactResource persisted =
jpaTm()
.transact(
() ->
jpaTm()
.load(VKey.createSql(ContactResource.class, originalContact.getRepoId())))
.get();
// TODO(b/153378849): Remove the hard code for postal info after resolving the issue that
// @PostLoad doesn't work in Address
ContactResource fixed =
originalContact
.asBuilder()
.setCreationTime(persisted.getCreationTime())
.setInternationalizedPostalInfo(persisted.getInternationalizedPostalInfo())
.setLocalizedPostalInfo(persisted.getLocalizedPostalInfo())
.setTransferData(null)
.build();
assertThat(persisted).isEqualTo(fixed);
}
@Test

View File

@@ -16,6 +16,8 @@ package google.registry.model.domain;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.time.DateTimeZone.UTC;
@@ -27,6 +29,8 @@ import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension;
import google.registry.testing.DatastoreEntityExtension;
@@ -54,20 +58,25 @@ public class DomainBaseSqlTest {
DomainBase domain;
Key<ContactResource> contactKey;
Key<ContactResource> contact2Key;
VKey<HostResource> host1VKey;
HostResource host;
@BeforeEach
public void setUp() {
contactKey = Key.create(ContactResource.class, "contact_id1");
contact2Key = Key.create(ContactResource.class, "contact_id2");
host1VKey = VKey.createSql(HostResource.class, "host1");
domain =
new DomainBase.Builder()
.setFullyQualifiedDomainName("example.com")
.setRepoId("4-COM")
.setCreationClientId("a registrar")
.setCreationClientId("registrar1")
.setLastEppUpdateTime(fakeClock.nowUtc())
.setLastEppUpdateClientId("AnotherRegistrar")
.setLastEppUpdateClientId("registrar2")
.setLastTransferTime(fakeClock.nowUtc())
.setNameservers(host1VKey)
.setStatusValues(
ImmutableSet.of(
StatusValue.CLIENT_DELETE_PROHIBITED,
@@ -79,7 +88,7 @@ public class DomainBaseSqlTest {
.setRegistrant(contactKey)
.setContacts(ImmutableSet.of(DesignatedContact.create(Type.ADMIN, contact2Key)))
.setSubordinateHosts(ImmutableSet.of("ns1.example.com"))
.setPersistedCurrentSponsorClientId("losing")
.setPersistedCurrentSponsorClientId("registrar3")
.setRegistrationExpirationTime(fakeClock.nowUtc().plusYears(1))
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("password")))
.setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2})))
@@ -87,16 +96,31 @@ public class DomainBaseSqlTest {
LaunchNotice.create("tcnid", "validatorId", START_OF_TIME, START_OF_TIME))
.setSmdId("smdid")
.build();
host =
new HostResource.Builder()
.setRepoId("host1")
.setFullyQualifiedHostName("ns1.example.com")
.setCreationClientId("registrar1")
.setPersistedCurrentSponsorClientId("registrar2")
.build();
}
@Test
public void testDomainBasePersistence() {
saveRegistrar("registrar1");
saveRegistrar("registrar2");
saveRegistrar("registrar3");
jpaTm()
.transact(
() -> {
// Persist the domain.
EntityManager em = jpaTm().getEntityManager();
em.persist(domain);
// Persist the host.
em.persist(host);
});
jpaTm()
@@ -125,4 +149,18 @@ public class DomainBaseSqlTest {
assertThat(result).isEqualTo(org);
});
}
@Test
public void testForeignKeyConstraints() {
assertThrowForeignKeyViolation(
() -> {
jpaTm()
.transact(
() -> {
// Persist the domain without the associated host object.
EntityManager em = jpaTm().getEntityManager();
em.persist(domain);
});
});
}
}

View File

@@ -16,7 +16,6 @@ package google.registry.model.ofy;
import static com.google.appengine.api.datastore.EntityTranslator.convertToPb;
import static com.google.common.truth.Truth.assertThat;
import static com.googlecode.objectify.ObjectifyService.register;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.model.ofy.CommitLogBucket.getBucketKey;
import static google.registry.model.ofy.ObjectifyService.ofy;
@@ -47,7 +46,11 @@ import org.junit.runners.JUnit4;
public class OfyCommitLogTest {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
public final AppEngineRule appEngine =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(TestVirtualObject.class, Root.class, Child.class)
.build();
@Rule
public final InjectRule inject = new InjectRule();
@@ -56,8 +59,6 @@ public class OfyCommitLogTest {
@Before
public void before() {
register(Root.class);
register(Child.class);
inject.setStaticField(Ofy.class, "clock", clock);
}

View File

@@ -28,7 +28,6 @@ import static org.mockito.Mockito.when;
import google.registry.model.ofy.Ofy;
import google.registry.model.server.Lock.LockState;
import google.registry.schema.server.LockDao;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectRule;
@@ -65,19 +64,16 @@ public class LockTest {
Optional<Lock> lock = Lock.acquire(RESOURCE_NAME, tld, leaseLength, requestStatusChecker, true);
verify(Lock.lockMetrics).recordAcquire(RESOURCE_NAME, tld, expectedLockState);
verifyNoMoreInteractions(Lock.lockMetrics);
assertThat(LockDao.load(RESOURCE_NAME, tld)).isPresent();
Lock.lockMetrics = null;
return lock;
}
private void release(Lock lock, String expectedTld, long expectedMillis) {
assertThat(LockDao.load(RESOURCE_NAME, expectedTld)).isPresent();
Lock.lockMetrics = mock(LockMetrics.class);
lock.release();
verify(Lock.lockMetrics)
.recordRelease(RESOURCE_NAME, expectedTld, Duration.millis(expectedMillis));
verifyNoMoreInteractions(Lock.lockMetrics);
assertThat(LockDao.load(RESOURCE_NAME, expectedTld)).isEmpty();
Lock.lockMetrics = null;
}

View File

@@ -23,7 +23,6 @@ import static org.joda.time.Duration.standardHours;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedMap;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.annotation.Entity;
import google.registry.model.common.CrossTldSingleton;
import google.registry.model.ofy.CommitLogManifest;
@@ -45,13 +44,17 @@ public class CommitLogRevisionsTranslatorFactoryTest {
private static final DateTime START_TIME = DateTime.parse("2000-01-01TZ");
@Entity
@Entity(name = "ClrtfTestEntity")
public static class TestObject extends CrossTldSingleton {
ImmutableSortedMap<DateTime, Key<CommitLogManifest>> revisions = ImmutableSortedMap.of();
}
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
public final AppEngineRule appEngine =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(TestObject.class)
.build();
@Rule
public final InjectRule inject = new InjectRule();
@@ -60,7 +63,6 @@ public class CommitLogRevisionsTranslatorFactoryTest {
@Before
public void before() {
ObjectifyService.register(TestObject.class);
inject.setStaticField(Ofy.class, "clock", clock);
}

View File

@@ -28,15 +28,19 @@ public class VKeyTest {
@Rule
public final AppEngineRule appEngineRule =
AppEngineRule.builder().withDatastoreAndCloudSql().build();
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(TestObject.class)
.build();
public VKeyTest() {}
@Test
public void testOptionalAccessors() {
VKey<TestObject> key = VKey.create(TestObject.class, null, null);
assertThat(key.maybeGetSqlKey().isPresent()).isFalse();
assertThat(key.maybeGetOfyKey().isPresent()).isFalse();
VKey<TestObject> key =
VKey.create(TestObject.class, "foo", Key.create(TestObject.create("foo")));
assertThat(key.maybeGetSqlKey().isPresent()).isTrue();
assertThat(key.maybeGetOfyKey().isPresent()).isTrue();
Key<TestObject> ofyKey = Key.create(TestObject.create("foo"));
assertThat(VKey.createOfy(TestObject.class, ofyKey).maybeGetOfyKey().get()).isEqualTo(ofyKey);

View File

@@ -0,0 +1,65 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.persistence.converter;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import google.registry.persistence.VKey;
import google.registry.persistence.WithLongVKey;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test SQL persistence of VKey. */
@RunWith(JUnit4.class)
public class LongVKeyConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder()
.withEntityClass(TestEntity.class, VKeyConverter_LongType.class)
.buildUnitTestRule();
@Test
public void testRoundTrip() {
TestEntity original = new TestEntity(VKey.createSql(TestEntity.class, 10L));
jpaTm().transact(() -> jpaTm().getEntityManager().persist(original));
TestEntity retrieved =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
assertThat(retrieved.number.getSqlKey()).isEqualTo(10L);
}
@Entity(name = "TestEntity")
@WithLongVKey(classNameSuffix = "LongType")
static class TestEntity {
@Id String id = "id";
VKey<TestEntity> number;
TestEntity(VKey<TestEntity> number) {
this.number = number;
}
/** Default constructor, needed for hibernate. */
public TestEntity() {}
}
}

View File

@@ -18,9 +18,9 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.Rule;
@@ -30,13 +30,15 @@ import org.junit.runners.JUnit4;
/** Test SQL persistence of VKey. */
@RunWith(JUnit4.class)
public class VKeyConverterTest {
public class StringVKeyConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
new JpaTestRules.Builder()
.withEntityClass(TestEntity.class, VKeyConverter_StringType.class)
.buildUnitTestRule();
public VKeyConverterTest() {}
public StringVKeyConverterTest() {}
@Test
public void testRoundTrip() {
@@ -45,27 +47,16 @@ public class VKeyConverterTest {
jpaTm().transact(() -> jpaTm().getEntityManager().persist(original));
TestEntity retrieved =
jpaTm().transact(
() -> jpaTm().getEntityManager().find(TestEntity.class, "TheRealSpartacus"));
jpaTm()
.transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "TheRealSpartacus"));
assertThat(retrieved.other.getSqlKey()).isEqualTo("ImSpartacus!");
}
static class TestEntityVKeyConverter extends VKeyConverter<TestEntity> {
@Override
protected Class<TestEntity> getAttributeClass() {
return TestEntity.class;
}
}
@Entity(name = "TestEntity")
@WithStringVKey(classNameSuffix = "StringType")
static class TestEntity {
@Id
String id;
@Id String id;
// Specifying "@Converter(autoApply = true) on TestEntityVKeyConverter this doesn't seem to
// work.
@Convert(converter = TestEntityVKeyConverter.class)
VKey<TestEntity> other;
TestEntity(String id, VKey<TestEntity> other) {

View File

@@ -41,6 +41,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
@@ -76,7 +77,7 @@ abstract class JpaTransactionManagerRule extends ExternalResource {
private final Clock clock;
private final Optional<String> initScriptPath;
private final ImmutableList<Class> extraEntityClasses;
private final ImmutableMap userProperties;
private final ImmutableMap<String, String> userProperties;
private static final JdbcDatabaseContainer database = create();
private static final HibernateSchemaExporter exporter =
@@ -143,15 +144,18 @@ abstract class JpaTransactionManagerRule extends ExternalResource {
new String(Files.readAllBytes(tempSqlFile.toPath()), StandardCharsets.UTF_8));
}
ImmutableMap properties = PersistenceModule.providesDefaultDatabaseConfigs();
Map<String, String> properties =
Maps.newHashMap(PersistenceModule.providesDefaultDatabaseConfigs());
// Set the minimumIdle to 0 so assertReasonableNumDbConnections() can check if there is
// connection leak after each test.
properties.put("hibernate.hikari.minimumIdle", "0");
properties.put("hibernate.hikari.idleTimeout", "300000");
if (!userProperties.isEmpty()) {
// If there are user properties, create a new properties object with these added.
ImmutableMap.Builder builder = properties.builder();
builder.putAll(userProperties);
properties.putAll(userProperties);
// Forbid Hibernate push to stay consistent with flyway-based schema management.
builder.put(Environment.HBM2DDL_AUTO, "none");
builder.put(Environment.SHOW_SQL, "true");
properties = builder.build();
properties.put(Environment.HBM2DDL_AUTO, "none");
properties.put(Environment.SHOW_SQL, "true");
}
assertReasonableNumDbConnections();
emf =
@@ -159,7 +163,7 @@ abstract class JpaTransactionManagerRule extends ExternalResource {
getJdbcUrl(),
database.getUsername(),
database.getPassword(),
properties,
ImmutableMap.copyOf(properties),
extraEntityClasses);
emfEntityHash = entityHash;
}

View File

@@ -16,6 +16,7 @@ package google.registry.schema.integration;
import static com.google.common.truth.Truth.assert_;
import google.registry.model.contact.ContactResourceTest;
import google.registry.model.domain.DomainBaseSqlTest;
import google.registry.model.registry.RegistryLockDaoTest;
import google.registry.persistence.transaction.JpaEntityCoverage;
@@ -68,6 +69,7 @@ import org.junit.runner.RunWith;
// BeforeSuiteTest must be the first entry. See class javadoc for details.
BeforeSuiteTest.class,
ClaimsListDaoTest.class,
ContactResourceTest.class,
CursorDaoTest.class,
DomainBaseSqlTest.class,
LockDaoTest.class,

View File

@@ -0,0 +1,65 @@
// Copyright 2020 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.schema.replay;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableSet;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ClassInfoList;
import io.github.classgraph.ScanResult;
import org.junit.Ignore;
import org.junit.Test;
/**
* Test to verify classes implement {@link SqlEntity} and {@link DatastoreEntity} when they should.
*/
public class EntityTest {
@Test
@Ignore("This won't be done until b/152410794 is done, since it requires many entity changes")
public void testSqlEntityPersistence() {
try (ScanResult scanResult =
new ClassGraph().enableAnnotationInfo().whitelistPackages("google.registry").scan()) {
// All javax.persistence entities must implement SqlEntity and vice versa
ImmutableSet<String> javaxPersistenceClasses =
getClassNames(
scanResult.getClassesWithAnnotation(javax.persistence.Entity.class.getName()));
ImmutableSet<String> sqlEntityClasses =
getClassNames(scanResult.getClassesImplementing(SqlEntity.class.getName()));
assertThat(javaxPersistenceClasses).isEqualTo(sqlEntityClasses);
// All com.googlecode.objectify.annotation.Entity classes must implement DatastoreEntity and
// vice versa
ImmutableSet<String> objectifyClasses =
getClassNames(
scanResult.getClassesWithAnnotation(
com.googlecode.objectify.annotation.Entity.class.getName()));
ImmutableSet<String> datastoreEntityClasses =
getClassNames(scanResult.getClassesImplementing(DatastoreEntity.class.getName()));
assertThat(objectifyClasses).isEqualTo(datastoreEntityClasses);
}
}
private ImmutableSet<String> getClassNames(ClassInfoList classInfoList) {
return classInfoList.stream()
.filter(ClassInfo::isStandardClass)
.map(ClassInfo::loadClass)
.map(Class::getName)
.collect(toImmutableSet());
}
}

View File

@@ -34,6 +34,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyFilter;
import google.registry.model.ofy.ObjectifyService;
import google.registry.model.registrar.Registrar;
@@ -50,6 +51,7 @@ import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.logging.LogManager;
import javax.annotation.Nullable;
@@ -127,10 +129,14 @@ public final class AppEngineRule extends ExternalResource
private String taskQueueXml;
private UserInfo userInfo;
// Test Objectify entity classes to be used with this AppEngineRule instance.
private ImmutableList<Class<?>> ofyTestEntities;
/** Builder for {@link AppEngineRule}. */
public static class Builder {
private AppEngineRule rule = new AppEngineRule();
private ImmutableList.Builder<Class<?>> ofyTestEntities = new ImmutableList.Builder();
/** Turn on the Datastore service and the Cloud SQL service. */
public Builder withDatastoreAndCloudSql() {
@@ -181,10 +187,29 @@ public final class AppEngineRule extends ExternalResource
return this;
}
/**
* Declares test-only entities to be registered with {@code ObjectifyService}.
*
* <p>Note that {@code ObjectifyService} silently replaces the current registration for a given
* kind when a different class is registered for this kind. Since {@code ObjectifyService} does
* not support de-registration, each test entity class must be of a unique kind across the
* entire code base. Although this requirement can be worked around by using different {@code
* ObjectifyService} instances for each test (class), the setup overhead would rise
* significantly.
*
* @see AppEngineRule#register(Class)
*/
@SafeVarargs
public final Builder withOfyTestEntities(Class<?>... entities) {
ofyTestEntities.add(entities);
return this;
}
public AppEngineRule build() {
checkState(
!rule.enableJpaEntityCoverageCheck || rule.withDatastoreAndCloudSql,
"withJpaEntityCoverageCheck enabled without Cloud SQL");
rule.ofyTestEntities = this.ofyTestEntities.build();
return rule;
}
}
@@ -411,6 +436,7 @@ public final class AppEngineRule extends ExternalResource
// Reset id allocation in ObjectifyService so that ids are deterministic in tests.
ObjectifyService.resetNextTestId();
loadInitialData();
this.ofyTestEntities.forEach(AppEngineRule::register);
}
}
@@ -443,6 +469,24 @@ public final class AppEngineRule extends ExternalResource
}
}
/**
* Registers test-only Objectify entities and checks for re-registrations for the same kind by
* different classes.
*/
private static void register(Class<?> entityClass) {
String kind = Key.getKind(entityClass);
Optional.ofNullable(com.googlecode.objectify.ObjectifyService.factory().getMetadata(kind))
.ifPresent(
meta ->
checkState(
meta.getEntityClass() == entityClass,
"Cannot register %s. The Kind %s is already registered with %s.",
entityClass.getName(),
kind,
meta.getEntityClass().getName()));
com.googlecode.objectify.ObjectifyService.register(entityClass);
}
/** Install {@code testing/logging.properties} so logging is less noisy. */
private static void setupLogging() throws IOException {
LogManager.getLogManager()

View File

@@ -18,6 +18,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
import com.google.common.base.Joiner;
import com.googlecode.objectify.annotation.Entity;
import java.io.File;
import java.io.IOException;
import org.junit.Before;
@@ -88,9 +89,29 @@ public class AppEngineRuleTest {
assertThrows(AssertionError.class, () -> appEngineRule.after());
}
@Test
public void testRegisterOfyEntities_failure() {
AppEngineRule appEngineRule =
AppEngineRule.builder()
.withDatastoreAndCloudSql()
.withOfyTestEntities(google.registry.testing.TestObject.class, TestObject.class)
.build();
String expectedErrorMessage =
String.format(
"Cannot register %s. The Kind %s is already registered with %s",
TestObject.class.getName(),
"TestObject",
google.registry.testing.TestObject.class.getName());
assertThrows(expectedErrorMessage, IllegalStateException.class, appEngineRule::before);
appEngineRule.after();
}
private void writeAutoIndexFile(String content) throws IOException {
com.google.common.io.Files.asCharSink(
new File(temporaryFolder.getRoot(), "datastore-indexes-auto.xml"), UTF_8)
.write(content);
}
@Entity
private static final class TestObject {}
}

View File

@@ -14,12 +14,19 @@
package google.registry.testing;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.AppEngineRule.makeRegistrar1;
import static org.junit.Assert.assertThrows;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import google.registry.model.registry.RegistryLockDao;
import google.registry.schema.domain.RegistryLock;
import java.sql.SQLException;
import java.util.Optional;
import javax.persistence.RollbackException;
import org.junit.function.ThrowingRunnable;
/** Static utils for setting up and retrieving test resources from the SQL database. */
public class SqlHelper {
@@ -52,5 +59,19 @@ public class SqlHelper {
return jpaTm().transact(() -> RegistryLockDao.getByRevisionId(revisionId));
}
public static void saveRegistrar(String clientId) {
jpaTm()
.transact(
() -> jpaTm().saveNew(makeRegistrar1().asBuilder().setClientId(clientId).build()));
}
public static void assertThrowForeignKeyViolation(ThrowingRunnable runnable) {
RollbackException thrown = assertThrows(RollbackException.class, runnable);
assertThat(Throwables.getRootCause(thrown)).isInstanceOf(SQLException.class);
assertThat(Throwables.getRootCause(thrown))
.hasMessageThat()
.contains("violates foreign key constraint");
}
private SqlHelper() {}
}

View File

@@ -17,7 +17,6 @@ package google.registry.testing;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Parent;
@@ -30,9 +29,6 @@ import google.registry.model.common.EntityGroupRoot;
*/
@Entity
public class TestObject extends ImmutableObject {
static {
ObjectifyService.register(TestObject.class); // Register this kind on first reference.
}
@Parent
Key<EntityGroupRoot> parent;
@@ -70,9 +66,6 @@ public class TestObject extends ImmutableObject {
@Entity
@VirtualEntity
public static class TestVirtualObject extends ImmutableObject {
static {
ObjectifyService.register(TestVirtualObject.class); // Register this kind on first reference.
}
@Id
String id;

View File

@@ -98,19 +98,20 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
"--visible_in_domain_whois_as_abuse=false",
"NewRegistrar");
RegistrarContact registrarContact = loadRegistrar("NewRegistrar").getContacts().asList().get(1);
assertThat(registrarContact).isEqualTo(
new RegistrarContact.Builder()
.setParent(registrar)
.setName("Judith Registrar")
.setEmailAddress("judith.doe@example.com")
.setRegistryLockEmailAddress("judith.doe@external.com")
.setPhoneNumber("+1.2125650000")
.setFaxNumber("+1.2125650001")
.setTypes(ImmutableSet.of(WHOIS))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build());
assertThat(registrarContact)
.isEqualTo(
new RegistrarContact.Builder()
.setParent(registrar)
.setName("Judith Registrar")
.setEmailAddress("judith.doe@example.com")
.setRegistryLockEmailAddress("judith.doe@external.com")
.setPhoneNumber("+1.2125650000")
.setFaxNumber("+1.2125650001")
.setTypes(ImmutableSet.of(WHOIS))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false)
.build());
}
@Test
@@ -305,17 +306,18 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
"--visible_in_domain_whois_as_abuse=true",
"NewRegistrar");
RegistrarContact registrarContact = loadRegistrar("NewRegistrar").getContacts().asList().get(1);
assertThat(registrarContact).isEqualTo(
new RegistrarContact.Builder()
.setParent(registrar)
.setName("Jim Doe")
.setEmailAddress("jim.doe@example.com")
.setRegistryLockEmailAddress("jim.doe@external.com")
.setTypes(ImmutableSet.of(ADMIN, ABUSE))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(true)
.build());
assertThat(registrarContact)
.isEqualTo(
new RegistrarContact.Builder()
.setParent(registrar)
.setName("Jim Doe")
.setEmailAddress("jim.doe@example.com")
.setRegistryLockEmailAddress("jim.doe@external.com")
.setTypes(ImmutableSet.of(ADMIN, ABUSE))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(true)
.build());
assertThat(registrarContact.getGaeUserId()).isNull();
}

View File

@@ -0,0 +1,88 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
import google.registry.testing.AppEngineRule;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.concurrent.locks.ReentrantLock;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link google.registry.tools.RegistryTool}. */
public class RegistryToolTest {
@RegisterExtension
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
// Lock for stdout/stderr. Note that this is static: since we're dealing with globals, we need
// to lock for the entire JVM.
private static final ReentrantLock stdoutLock = new ReentrantLock();
private PrintStream oldStdout;
private final ByteArrayOutputStream stdout = new ByteArrayOutputStream();
@BeforeEach
void beforeEach() {
// Capture standard output/error. This is problematic because gradle tests run in parallel in
// the same JVM. So first lock out any other tests in this JVM that are trying to do this
// trick.
// TODO(mcilwain): Turn this into a JUnit 5 extension.
stdoutLock.lock();
oldStdout = System.out;
System.setOut(new PrintStream(stdout));
}
@AfterEach
final void afterEach() {
System.setOut(oldStdout);
stdoutLock.unlock();
}
@Test
void test_displayAvailableCommands() throws Exception {
RegistryTool.main(new String[] {"-e", "unittest", "--commands"});
// Check for the existence of a few common commands.
assertThat(getStdout()).contains("login");
assertThat(getStdout()).contains("check_domain");
assertThat(getStdout()).contains("get_tld");
}
@Test
void test_noSubcommandSpecified_displaysAvailableCommands() throws Exception {
RegistryTool.main(new String[] {"-e", "unittest"});
assertThat(getStdout()).contains("The list of available subcommands is:");
assertThat(getStdout()).contains("login");
assertThat(getStdout()).contains("check_domain");
assertThat(getStdout()).contains("get_tld");
}
@Test
void test_noEnvironmentSpecified_throwsCorrectError() {
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> RegistryTool.main(new String[] {}));
assertThat(thrown).hasMessageThat().contains("Please specify the environment flag");
}
private String getStdout() {
return new String(stdout.toByteArray(), UTF_8);
}
}

View File

@@ -15,21 +15,27 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatastoreHelper.newDomainBase;
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
import static google.registry.testing.DatastoreHelper.persistNewRegistrar;
import static google.registry.testing.DatastoreHelper.persistResource;
import static org.junit.Assert.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableMap;
import google.registry.model.domain.DomainBase;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectRule;
import google.registry.util.Clock;
import java.util.List;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
/** Unit tests for {@link RenewDomainCommand}. */
public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCommand> {
@@ -63,23 +69,57 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCo
.verifyNoMoreSent();
}
private static List<DomainBase> persistThreeDomains() {
ImmutableList.Builder<DomainBase> domains = new ImmutableList.Builder<>();
domains.add(
persistActiveDomain(
"domain1.tld",
DateTime.parse("2014-09-05T05:05:05Z"),
DateTime.parse("2015-09-05T05:05:05Z")));
domains.add(
persistActiveDomain(
"domain2.tld",
DateTime.parse("2014-11-05T05:05:05Z"),
DateTime.parse("2015-11-05T05:05:05Z")));
// The third domain is owned by a different registrar.
domains.add(
persistResource(
newDomainBase("domain3.tld")
.asBuilder()
.setCreationTimeForTest(DateTime.parse("2015-01-05T05:05:05Z"))
.setRegistrationExpirationTime(DateTime.parse("2016-01-05T05:05:05Z"))
.setPersistedCurrentSponsorClientId("NewRegistrar")
.build()));
return domains.build();
}
@Test
public void testSuccess_multipleDomains() throws Exception {
persistActiveDomain(
"domain1.tld",
DateTime.parse("2014-09-05T05:05:05Z"),
DateTime.parse("2015-09-05T05:05:05Z"));
persistActiveDomain(
"domain2.tld",
DateTime.parse("2014-11-05T05:05:05Z"),
DateTime.parse("2015-11-05T05:05:05Z"));
persistActiveDomain(
"domain3.tld",
DateTime.parse("2015-01-05T05:05:05Z"),
DateTime.parse("2016-01-05T05:05:05Z"));
public void testSuccess_multipleDomains_renewsAndUsesEachDomainsRegistrar() throws Exception {
persistThreeDomains();
runCommandForced("--period 3", "domain1.tld", "domain2.tld", "domain3.tld");
eppVerifier
.expectClientId("TheRegistrar")
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain1.tld", "EXPDATE", "2015-09-05", "YEARS", "3"))
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain2.tld", "EXPDATE", "2015-11-05", "YEARS", "3"))
.expectClientId("NewRegistrar")
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain3.tld", "EXPDATE", "2016-01-05", "YEARS", "3"))
.verifyNoMoreSent();
}
@Test
public void testSuccess_multipleDomains_renewsAndUsesSpecifiedRegistrar() throws Exception {
persistThreeDomains();
persistNewRegistrar("reg3", "Registrar 3", Registrar.Type.REAL, 9783L);
runCommandForced("--period 3", "domain1.tld", "domain2.tld", "domain3.tld", "-u", "-c reg3");
eppVerifier
.expectClientId("reg3")
.expectSuperuser()
.verifySent(
"domain_renew.xml",
ImmutableMap.of("DOMAIN", "domain1.tld", "EXPDATE", "2015-09-05", "YEARS", "3"))
@@ -106,9 +146,7 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCo
persistDeletedDomain("deleted.tld", DateTime.parse("2012-10-05T05:05:05Z"));
IllegalArgumentException e =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("deleted.tld"));
assertThat(e)
.hasMessageThat()
.isEqualTo("Domain 'deleted.tld' does not exist or is deleted");
assertThat(e).hasMessageThat().isEqualTo("Domain 'deleted.tld' does not exist or is deleted");
}
@Test
@@ -128,9 +166,7 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase<RenewDomainCo
IllegalArgumentException e =
assertThrows(
IllegalArgumentException.class, () -> runCommandForced("domain.tld", "--period 10"));
assertThat(e)
.hasMessageThat()
.isEqualTo("Cannot renew domains for 10 or more years");
assertThat(e).hasMessageThat().isEqualTo("Cannot renew domains for 10 or more years");
}
@Test

View File

@@ -66,13 +66,12 @@ public class ContactSettingsTest extends RegistrarSettingsActionTestCase {
@Test
public void testPost_updateContacts_success() throws Exception {
// Remove all the contacts but the first by updating with list of
// just it.
// Remove all the contacts but one by updating with a list of just it
ImmutableMap<String, String> adminContact1 =
ImmutableMap.of(
"name", "contact1",
"emailAddress", "contact1@email.com",
"phoneNumber", "+1.2125650001",
"name", "Marla Singer",
"emailAddress", "Marla.Singer@crr.com",
"phoneNumber", "+1.2128675309",
// Have to keep ADMIN or else expect FormException for at-least-one.
"types", "ADMIN,TECH");
@@ -83,15 +82,12 @@ public class ContactSettingsTest extends RegistrarSettingsActionTestCase {
action.handleJsonRequest(ImmutableMap.of("op", "update", "id", CLIENT_ID, "args", regMap));
assertThat(response).containsEntry("status", "SUCCESS");
RegistrarContact newContact =
new RegistrarContact.Builder()
.setParent(registrar)
.setName(adminContact1.get("name"))
.setEmailAddress(adminContact1.get("emailAddress"))
.setPhoneNumber(adminContact1.get("phoneNumber"))
.setTypes(ImmutableList.of(Type.ADMIN, Type.TECH))
.build();
assertThat(loadRegistrar(CLIENT_ID).getContacts()).containsExactly(newContact);
RegistrarContact foundContact =
Iterables.getOnlyElement(loadRegistrar(CLIENT_ID).getContacts());
assertThat(foundContact.getName()).isEqualTo(adminContact1.get("name"));
assertThat(foundContact.getEmailAddress()).isEqualTo(adminContact1.get("emailAddress"));
assertThat(foundContact.getPhoneNumber()).isEqualTo(adminContact1.get("phoneNumber"));
assertThat(foundContact.getTypes()).containsExactly(Type.ADMIN, Type.TECH);
assertMetric(CLIENT_ID, "update", "[OWNER]", "SUCCESS");
verifyNotificationEmailsSent();
}
@@ -188,41 +184,65 @@ public class ContactSettingsTest extends RegistrarSettingsActionTestCase {
@Test
public void testSuccess_setRegistryLockPassword() {
addPasswordToTechContact();
techContact = Iterables.getOnlyElement(loadRegistrar(CLIENT_ID).getContactsOfType(Type.TECH));
assertThat(techContact.verifyRegistryLockPassword("hellothere")).isTrue();
addPasswordToContactTwo();
String emailAddress = AppEngineRule.makeRegistrarContact2().getEmailAddress();
RegistrarContact newContactWithPassword =
loadRegistrar(CLIENT_ID).getContacts().stream()
.filter(rc -> rc.getEmailAddress().equals(emailAddress))
.findFirst()
.get();
assertThat(newContactWithPassword.verifyRegistryLockPassword("hellothere")).isTrue();
assertMetric(CLIENT_ID, "update", "[OWNER]", "SUCCESS");
}
@Test
public void testSuccess_setRegistryLockPassword_notOverriddenLater() {
addPasswordToTechContact();
techContact = Iterables.getOnlyElement(loadRegistrar(CLIENT_ID).getContactsOfType(Type.TECH));
assertThat(techContact.verifyRegistryLockPassword("hellothere")).isTrue();
addPasswordToContactTwo();
String emailAddress = AppEngineRule.makeRegistrarContact2().getEmailAddress();
RegistrarContact newContactWithPassword =
loadRegistrar(CLIENT_ID).getContacts().stream()
.filter(rc -> rc.getEmailAddress().equals(emailAddress))
.findFirst()
.get();
assertThat(newContactWithPassword.verifyRegistryLockPassword("hellothere")).isTrue();
techContact = Iterables.getOnlyElement(loadRegistrar(CLIENT_ID).getContactsOfType(Type.TECH));
Map<String, Object> techContactMap = techContact.toJsonMap();
techContactMap.put("name", "Some Other Name");
Map<String, Object> newContactMap = newContactWithPassword.toJsonMap();
newContactMap.put("name", "Some Other Name");
Map<String, Object> reqJson = loadRegistrar(CLIENT_ID).toJsonMap();
reqJson.put(
"contacts",
ImmutableList.of(AppEngineRule.makeRegistrarContact2().toJsonMap(), techContactMap));
ImmutableList.of(
AppEngineRule.makeRegistrarContact1().toJsonMap(),
newContactMap,
AppEngineRule.makeRegistrarContact3().toJsonMap()));
Map<String, Object> response =
action.handleJsonRequest(ImmutableMap.of("op", "update", "id", CLIENT_ID, "args", reqJson));
assertThat(response).containsAtLeastEntriesIn(ImmutableMap.of("status", "SUCCESS"));
techContact = Iterables.getOnlyElement(loadRegistrar(CLIENT_ID).getContactsOfType(Type.TECH));
assertThat(techContact.verifyRegistryLockPassword("hellothere")).isTrue();
newContactWithPassword =
loadRegistrar(CLIENT_ID).getContacts().stream()
.filter(rc -> rc.getEmailAddress().equals(emailAddress))
.findFirst()
.get();
assertThat(newContactWithPassword.verifyRegistryLockPassword("hellothere")).isTrue();
}
private void addPasswordToTechContact() {
techContact =
persistResource(techContact.asBuilder().setAllowedToSetRegistryLockPassword(true).build());
Map<String, Object> contactMap = techContact.toJsonMap();
private void addPasswordToContactTwo() {
RegistrarContact contact =
persistResource(
AppEngineRule.makeRegistrarContact2()
.asBuilder()
.setRegistryLockEmailAddress("johndoe@theregistrar.com")
.setAllowedToSetRegistryLockPassword(true)
.build());
Map<String, Object> contactMap = contact.toJsonMap();
contactMap.put("registryLockPassword", "hellothere");
Map<String, Object> reqJson = loadRegistrar(CLIENT_ID).toJsonMap();
reqJson.put(
"contacts",
ImmutableList.of(AppEngineRule.makeRegistrarContact2().toJsonMap(), contactMap));
ImmutableList.of(
AppEngineRule.makeRegistrarContact1().toJsonMap(),
contactMap,
AppEngineRule.makeRegistrarContact3().toJsonMap()));
Map<String, Object> response =
action.handleJsonRequest(ImmutableMap.of("op", "update", "id", CLIENT_ID, "args", reqJson));
assertThat(response).containsAtLeastEntriesIn(ImmutableMap.of("status", "SUCCESS"));
@@ -260,13 +280,16 @@ public class ContactSettingsTest extends RegistrarSettingsActionTestCase {
public void testPost_failure_setRegistryLockPassword_notAllowed() {
// "allowedToSetRegistryLockPassword" must be set through the back end first
// before we can set a password through the UI
Map<String, Object> contactMap =
techContact.asBuilder().setAllowedToSetRegistryLockPassword(true).build().toJsonMap();
Map<String, Object> contactMap = AppEngineRule.makeRegistrarContact2().toJsonMap();
contactMap.put("allowedToSetRegistryLockPassword", true);
contactMap.put("registryLockPassword", "hellothere");
Map<String, Object> reqJson = loadRegistrar(CLIENT_ID).toJsonMap();
reqJson.put(
"contacts",
ImmutableList.of(AppEngineRule.makeRegistrarContact2().toJsonMap(), contactMap));
ImmutableList.of(
AppEngineRule.makeRegistrarContact1().toJsonMap(),
contactMap,
AppEngineRule.makeRegistrarContact3().toJsonMap()));
Map<String, Object> response =
action.handleJsonRequest(ImmutableMap.of("op", "update", "id", CLIENT_ID, "args", reqJson));
@@ -304,6 +327,30 @@ public class ContactSettingsTest extends RegistrarSettingsActionTestCase {
assertMetric(CLIENT_ID, "update", "[OWNER]", "ERROR: FormException");
}
@Test
public void testPost_failure_removingRegistryLockContact() {
ImmutableMap<String, String> contact =
ImmutableMap.of(
"name", "contact1",
"emailAddress", "contact1@email.com",
"phoneNumber", "+1.2125650001",
// Have to keep ADMIN or else expect FormException for at-least-one.
"types", "ADMIN,TECH");
Map<String, Object> regMap = loadRegistrar(CLIENT_ID).toJsonMap();
regMap.put("contacts", ImmutableList.of(contact));
Map<String, Object> response =
action.handleJsonRequest(ImmutableMap.of("op", "update", "id", CLIENT_ID, "args", regMap));
assertThat(response)
.containsExactly(
"status",
"ERROR",
"results",
ImmutableList.of(),
"message",
"Cannot delete the contact Marla.Singer@crr.com that has registry lock enabled");
assertMetric(CLIENT_ID, "update", "[OWNER]", "ERROR: FormException");
}
@Test
public void testPost_failure_setRegistryLock_passwordTooShort() {
techContact =

View File

@@ -14,6 +14,7 @@
package google.registry.ui.server.registrar;
import static com.google.appengine.repackaged.com.google.common.collect.Iterables.getOnlyElement;
import static com.google.monitoring.metrics.contrib.LongMetricSubject.assertThat;
import static google.registry.config.RegistryConfig.getGSuiteOutgoingEmailAddress;
import static google.registry.config.RegistryConfig.getGSuiteOutgoingEmailDisplayName;
@@ -23,14 +24,12 @@ import static google.registry.security.JsonHttpTestUtils.createJsonPayload;
import static google.registry.testing.DatastoreHelper.createTlds;
import static google.registry.testing.DatastoreHelper.disallowRegistrarAccess;
import static google.registry.testing.DatastoreHelper.loadRegistrar;
import static google.registry.testing.DatastoreHelper.persistResource;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.appengine.api.users.User;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.truth.Truth;
import google.registry.model.ofy.Ofy;
@@ -95,21 +94,13 @@ public abstract class RegistrarSettingsActionTestCase {
// Add a technical contact to the registrar (in addition to the default admin contact created by
// AppEngineRule).
techContact =
persistResource(
new RegistrarContact.Builder()
.setParent(loadRegistrar(CLIENT_ID))
.setName("Jian-Yang")
.setEmailAddress("jyang@bachman.accelerator")
.setRegistryLockEmailAddress("jyang.registrylock@bachman.accelerator")
.setPhoneNumber("+1.1234567890")
.setTypes(ImmutableSet.of(RegistrarContact.Type.TECH))
.build());
getOnlyElement(loadRegistrar(CLIENT_ID).getContactsOfType(RegistrarContact.Type.TECH));
action.registrarAccessor = null;
action.appEngineServiceUtils = appEngineServiceUtils;
when(appEngineServiceUtils.getCurrentVersionHostname("backend")).thenReturn("backend.hostname");
action.jsonActionRunner = new JsonActionRunner(
ImmutableMap.of(), new JsonResponse(new ResponseImpl(rsp)));
action.jsonActionRunner =
new JsonActionRunner(ImmutableMap.of(), new JsonResponse(new ResponseImpl(rsp)));
action.sendEmailUtils =
new SendEmailUtils(
getGSuiteOutgoingEmailAddress(),

View File

@@ -18,6 +18,17 @@
"emailAddress": "etphonehome@example.com",
"gaeUserId": null,
"types": "ADMIN,BILLING,TECH,WHOIS"
},
{
"visibleInWhoisAsAdmin": false,
"faxNumber": null,
"phoneNumber": "+1.2128675309",
"name": "Marla Singer",
"visibleInWhoisAsTech": false,
"emailAddress": "Marla.Singer@crr.com",
"registryLockEmailAddress": "Marla.Singer.RegistryLock@crr.com",
"gaeUserId": "12345",
"types": "TECH"
}
],
"allowedTlds": [

View File

@@ -13,8 +13,7 @@ contacts:
ADDED:
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, registryLockEmailAddress=null, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
REMOVED:
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Marla Singer, emailAddress=Marla.Singer@crr.com, registryLockEmailAddress=Marla.Singer.RegistryLock@crr.com, phoneNumber=+1.2128675309, faxNumber=null, types=[TECH], gaeUserId=12345, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=John Doe, emailAddress=johndoe@theregistrar.com, registryLockEmailAddress=null, phoneNumber=+1.1234567890, faxNumber=null, types=[ADMIN], gaeUserId=31337, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Jian-Yang, emailAddress=jyang@bachman.accelerator, registryLockEmailAddress=jyang.registrylock@bachman.accelerator, phoneNumber=+1.1234567890, faxNumber=null, types=[TECH], gaeUserId=null, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=John Doe, emailAddress=johndoe@theregistrar.com, registryLockEmailAddress=null, phoneNumber=+1.1234567890, faxNumber=null, types=[ADMIN], gaeUserId=31337, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
FINAL CONTENTS:
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, registryLockEmailAddress=null, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, registryLockEmailAddress=null, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Marla Singer, emailAddress=Marla.Singer@crr.com, registryLockEmailAddress=Marla.Singer.RegistryLock@crr.com, phoneNumber=+1.2128675309, faxNumber=null, types=[TECH], gaeUserId=12345, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

@@ -0,0 +1,54 @@
-- Copyright 2020 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.
create table "DomainHost" (
domain_repo_id text not null,
ns_host_v_keys text
);
create table "HostResource" (
repo_id text not null,
creation_client_id text,
creation_time timestamptz,
current_sponsor_client_id text,
deletion_time timestamptz,
last_epp_update_client_id text,
last_epp_update_time timestamptz,
statuses text[],
fully_qualified_host_name text,
last_superordinate_change timestamptz,
last_transfer_time timestamptz,
superordinate_domain bytea,
primary key (repo_id)
);
create table "HostResource_inetAddresses" (
host_resource_repo_id text not null,
inet_addresses bytea
);
alter table if exists "DomainHost"
add constraint FKfmi7bdink53swivs390m2btxg
foreign key (domain_repo_id)
references "Domain";
alter table if exists "DomainHost"
add constraint FK_DomainHost_host_valid
foreign key (ns_host_v_keys)
references "HostResource";
alter table if exists "HostResource_inetAddresses"
add constraint FK6unwhfkcu3oq6q347fxvpagv
foreign key (host_resource_repo_id)
references "HostResource";

View File

@@ -0,0 +1,107 @@
-- Copyright 2020 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.
create table "Contact" (
repo_id text not null,
creation_client_id text not null,
creation_time timestamptz not null,
current_sponsor_client_id text not null,
deletion_time timestamptz,
last_epp_update_client_id text,
last_epp_update_time timestamptz,
statuses text[],
auth_info_repo_id text,
auth_info_value text,
contact_id text,
disclose_types_addr text[],
disclose_show_email boolean,
disclose_show_fax boolean,
disclose_mode_flag boolean,
disclose_types_name text[],
disclose_types_org text[],
disclose_show_voice boolean,
email text,
fax_phone_extension text,
fax_phone_number text,
addr_i18n_city text,
addr_i18n_country_code text,
addr_i18n_state text,
addr_i18n_street_line1 text,
addr_i18n_street_line2 text,
addr_i18n_street_line3 text,
addr_i18n_zip text,
addr_i18n_name text,
addr_i18n_org text,
addr_i18n_type text,
last_transfer_time timestamptz,
addr_local_city text,
addr_local_country_code text,
addr_local_state text,
addr_local_street_line1 text,
addr_local_street_line2 text,
addr_local_street_line3 text,
addr_local_zip text,
addr_local_name text,
addr_local_org text,
addr_local_type text,
search_name text,
voice_phone_extension text,
voice_phone_number text,
primary key (repo_id)
);
create index IDX3y752kr9uh4kh6uig54vemx0l on "Contact" (creation_time);
create index IDXbn8t4wp85fgxjl8q4ctlscx55 on "Contact" (current_sponsor_client_id);
create index IDXn1f711wicdnooa2mqb7g1m55o on "Contact" (deletion_time);
create index IDX1p3esngcwwu6hstyua6itn6ff on "Contact" (search_name);
alter table if exists "Contact"
add constraint UKoqd7n4hbx86hvlgkilq75olas unique (contact_id);
alter table "Domain" alter column creation_time set not null;
alter table "Domain" alter column creation_client_id set not null;
alter table "Domain" alter column current_sponsor_client_id set not null;
drop index IDX8ffrqm27qtj20jac056j7yq07;
create index IDXkjt9yaq92876dstimd93hwckh on "Domain" (current_sponsor_client_id);
alter table if exists "Contact"
add constraint FK1sfyj7o7954prbn1exk7lpnoe
foreign key (creation_client_id)
references "Registrar";
alter table if exists "Contact"
add constraint FK93c185fx7chn68uv7nl6uv2s0
foreign key (current_sponsor_client_id)
references "Registrar";
alter table if exists "Contact"
add constraint FKmb7tdiv85863134w1wogtxrb2
foreign key (last_epp_update_client_id)
references "Registrar";
alter table if exists "Domain"
add constraint FK2jc69qyg2tv9hhnmif6oa1cx1
foreign key (creation_client_id)
references "Registrar";
alter table if exists "Domain"
add constraint FK2u3srsfbei272093m3b3xwj23
foreign key (current_sponsor_client_id)
references "Registrar";
alter table if exists "Domain"
add constraint FKjc0r9r5y1lfbt4gpbqw4wsuvq
foreign key (last_epp_update_client_id)
references "Registrar";

View File

@@ -26,6 +26,55 @@
primary key (revision_id)
);
create table "Contact" (
repo_id text not null,
creation_client_id text not null,
creation_time timestamptz not null,
current_sponsor_client_id text not null,
deletion_time timestamptz,
last_epp_update_client_id text,
last_epp_update_time timestamptz,
statuses text[],
auth_info_repo_id text,
auth_info_value text,
contact_id text,
disclose_types_addr text[],
disclose_show_email boolean,
disclose_show_fax boolean,
disclose_mode_flag boolean,
disclose_types_name text[],
disclose_types_org text[],
disclose_show_voice boolean,
email text,
fax_phone_extension text,
fax_phone_number text,
addr_i18n_city text,
addr_i18n_country_code text,
addr_i18n_state text,
addr_i18n_street_line1 text,
addr_i18n_street_line2 text,
addr_i18n_street_line3 text,
addr_i18n_zip text,
addr_i18n_name text,
addr_i18n_org text,
addr_i18n_type text,
last_transfer_time timestamptz,
addr_local_city text,
addr_local_country_code text,
addr_local_state text,
addr_local_street_line1 text,
addr_local_street_line2 text,
addr_local_street_line3 text,
addr_local_zip text,
addr_local_name text,
addr_local_org text,
addr_local_type text,
search_name text,
voice_phone_extension text,
voice_phone_number text,
primary key (repo_id)
);
create table "Cursor" (
scope text not null,
type text not null,
@@ -44,9 +93,9 @@
create table "Domain" (
repo_id text not null,
creation_client_id text,
creation_time timestamptz,
current_sponsor_client_id text,
creation_client_id text not null,
creation_time timestamptz not null,
current_sponsor_client_id text not null,
deletion_time timestamptz,
last_epp_update_client_id text,
last_epp_update_time timestamptz,
@@ -67,6 +116,11 @@
primary key (repo_id)
);
create table "DomainHost" (
domain_repo_id text not null,
ns_host_v_keys text
);
create table "GracePeriod" (
id bigserial not null,
billing_event_one_time bytea,
@@ -77,6 +131,27 @@
primary key (id)
);
create table "HostResource" (
repo_id text not null,
creation_client_id text not null,
creation_time timestamptz not null,
current_sponsor_client_id text not null,
deletion_time timestamptz,
last_epp_update_client_id text,
last_epp_update_time timestamptz,
statuses text[],
fully_qualified_host_name text,
last_superordinate_change timestamptz,
last_transfer_time timestamptz,
superordinate_domain bytea,
primary key (repo_id)
);
create table "HostResource_inetAddresses" (
host_resource_repo_id text not null,
inet_addresses bytea
);
create table "Lock" (
resource_name text not null,
tld text not null,
@@ -201,6 +276,13 @@
should_publish boolean not null,
primary key (revision_id)
);
create index IDX3y752kr9uh4kh6uig54vemx0l on "Contact" (creation_time);
create index IDXbn8t4wp85fgxjl8q4ctlscx55 on "Contact" (current_sponsor_client_id);
create index IDXn1f711wicdnooa2mqb7g1m55o on "Contact" (deletion_time);
create index IDX1p3esngcwwu6hstyua6itn6ff on "Contact" (search_name);
alter table if exists "Contact"
add constraint UKoqd7n4hbx86hvlgkilq75olas unique (contact_id);
create index IDX8nr0ke9mrrx4ewj6pd2ag4rmr on "Domain" (creation_time);
create index IDX8ffrqm27qtj20jac056j7yq07 on "Domain" (current_sponsor_client_id);
create index IDX5mnf0wn20tno4b9do88j61klr on "Domain" (deletion_time);
@@ -222,6 +304,16 @@ create index reservedlist_name_idx on "ReservedList" (name);
foreign key (revision_id)
references "ClaimsList";
alter table if exists "DomainHost"
add constraint FKeq1guccbre1yk3oosgp2io554
foreign key (domain_repo_id)
references "Domain";
alter table if exists "HostResource_inetAddresses"
add constraint FK6unwhfkcu3oq6q347fxvpagv
foreign key (host_resource_repo_id)
references "HostResource";
alter table if exists "PremiumEntry"
add constraint FKo0gw90lpo1tuee56l0nb6y6g5
foreign key (revision_id)

View File

@@ -75,6 +75,59 @@ CREATE SEQUENCE public."ClaimsList_revision_id_seq"
ALTER SEQUENCE public."ClaimsList_revision_id_seq" OWNED BY public."ClaimsList".revision_id;
--
-- Name: Contact; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."Contact" (
repo_id text NOT NULL,
creation_client_id text NOT NULL,
creation_time timestamp with time zone NOT NULL,
current_sponsor_client_id text NOT NULL,
deletion_time timestamp with time zone,
last_epp_update_client_id text,
last_epp_update_time timestamp with time zone,
statuses text[],
auth_info_repo_id text,
auth_info_value text,
contact_id text,
disclose_types_addr text[],
disclose_show_email boolean,
disclose_show_fax boolean,
disclose_mode_flag boolean,
disclose_types_name text[],
disclose_types_org text[],
disclose_show_voice boolean,
email text,
fax_phone_extension text,
fax_phone_number text,
addr_i18n_city text,
addr_i18n_country_code text,
addr_i18n_state text,
addr_i18n_street_line1 text,
addr_i18n_street_line2 text,
addr_i18n_street_line3 text,
addr_i18n_zip text,
addr_i18n_name text,
addr_i18n_org text,
addr_i18n_type text,
last_transfer_time timestamp with time zone,
addr_local_city text,
addr_local_country_code text,
addr_local_state text,
addr_local_street_line1 text,
addr_local_street_line2 text,
addr_local_street_line3 text,
addr_local_zip text,
addr_local_name text,
addr_local_org text,
addr_local_type text,
search_name text,
voice_phone_extension text,
voice_phone_number text
);
--
-- Name: Cursor; Type: TABLE; Schema: public; Owner: -
--
@@ -93,9 +146,9 @@ CREATE TABLE public."Cursor" (
CREATE TABLE public."Domain" (
repo_id text NOT NULL,
creation_client_id text,
creation_time timestamp with time zone,
current_sponsor_client_id text,
creation_client_id text NOT NULL,
creation_time timestamp with time zone NOT NULL,
current_sponsor_client_id text NOT NULL,
deletion_time timestamp with time zone,
last_epp_update_client_id text,
last_epp_update_time timestamp with time zone,
@@ -116,6 +169,46 @@ CREATE TABLE public."Domain" (
);
--
-- Name: DomainHost; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."DomainHost" (
domain_repo_id text NOT NULL,
ns_host_v_keys text
);
--
-- Name: HostResource; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."HostResource" (
repo_id text NOT NULL,
creation_client_id text,
creation_time timestamp with time zone,
current_sponsor_client_id text,
deletion_time timestamp with time zone,
last_epp_update_client_id text,
last_epp_update_time timestamp with time zone,
statuses text[],
fully_qualified_host_name text,
last_superordinate_change timestamp with time zone,
last_transfer_time timestamp with time zone,
superordinate_domain bytea
);
--
-- Name: HostResource_inetAddresses; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."HostResource_inetAddresses" (
host_resource_repo_id text NOT NULL,
inet_addresses bytea
);
--
-- Name: Lock; Type: TABLE; Schema: public; Owner: -
--
@@ -374,6 +467,14 @@ ALTER TABLE ONLY public."ClaimsList"
ADD CONSTRAINT "ClaimsList_pkey" PRIMARY KEY (revision_id);
--
-- Name: Contact Contact_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Contact"
ADD CONSTRAINT "Contact_pkey" PRIMARY KEY (repo_id);
--
-- Name: Cursor Cursor_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -390,6 +491,14 @@ ALTER TABLE ONLY public."Domain"
ADD CONSTRAINT "Domain_pkey" PRIMARY KEY (repo_id);
--
-- Name: HostResource HostResource_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."HostResource"
ADD CONSTRAINT "HostResource_pkey" PRIMARY KEY (repo_id);
--
-- Name: Lock Lock_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -462,6 +571,21 @@ ALTER TABLE ONLY public."RegistryLock"
ADD CONSTRAINT idx_registry_lock_repo_id_revision_id UNIQUE (repo_id, revision_id);
--
-- Name: Contact ukoqd7n4hbx86hvlgkilq75olas; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Contact"
ADD CONSTRAINT ukoqd7n4hbx86hvlgkilq75olas UNIQUE (contact_id);
--
-- Name: idx1p3esngcwwu6hstyua6itn6ff; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx1p3esngcwwu6hstyua6itn6ff ON public."Contact" USING btree (search_name);
--
-- Name: idx1rcgkdd777bpvj0r94sltwd5y; Type: INDEX; Schema: public; Owner: -
--
@@ -469,6 +593,13 @@ ALTER TABLE ONLY public."RegistryLock"
CREATE INDEX idx1rcgkdd777bpvj0r94sltwd5y ON public."Domain" USING btree (fully_qualified_domain_name);
--
-- Name: idx3y752kr9uh4kh6uig54vemx0l; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx3y752kr9uh4kh6uig54vemx0l ON public."Contact" USING btree (creation_time);
--
-- Name: idx5mnf0wn20tno4b9do88j61klr; Type: INDEX; Schema: public; Owner: -
--
@@ -476,13 +607,6 @@ CREATE INDEX idx1rcgkdd777bpvj0r94sltwd5y ON public."Domain" USING btree (fully_
CREATE INDEX idx5mnf0wn20tno4b9do88j61klr ON public."Domain" USING btree (deletion_time);
--
-- Name: idx8ffrqm27qtj20jac056j7yq07; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idx8ffrqm27qtj20jac056j7yq07 ON public."Domain" USING btree (current_sponsor_client_id);
--
-- Name: idx8nr0ke9mrrx4ewj6pd2ag4rmr; Type: INDEX; Schema: public; Owner: -
--
@@ -504,6 +628,27 @@ CREATE INDEX idx_registry_lock_registrar_id ON public."RegistryLock" USING btree
CREATE INDEX idx_registry_lock_verification_code ON public."RegistryLock" USING btree (verification_code);
--
-- Name: idxbn8t4wp85fgxjl8q4ctlscx55; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxbn8t4wp85fgxjl8q4ctlscx55 ON public."Contact" USING btree (current_sponsor_client_id);
--
-- Name: idxkjt9yaq92876dstimd93hwckh; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxkjt9yaq92876dstimd93hwckh ON public."Domain" USING btree (current_sponsor_client_id);
--
-- Name: idxn1f711wicdnooa2mqb7g1m55o; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxn1f711wicdnooa2mqb7g1m55o ON public."Contact" USING btree (deletion_time);
--
-- Name: idxrwl38wwkli1j7gkvtywi9jokq; Type: INDEX; Schema: public; Owner: -
--
@@ -546,6 +691,22 @@ CREATE INDEX registrarpoc_gae_user_id_idx ON public."RegistrarPoc" USING btree (
CREATE INDEX reservedlist_name_idx ON public."ReservedList" USING btree (name);
--
-- Name: Contact fk1sfyj7o7954prbn1exk7lpnoe; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Contact"
ADD CONSTRAINT fk1sfyj7o7954prbn1exk7lpnoe FOREIGN KEY (creation_client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: Domain fk2jc69qyg2tv9hhnmif6oa1cx1; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Domain"
ADD CONSTRAINT fk2jc69qyg2tv9hhnmif6oa1cx1 FOREIGN KEY (creation_client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: RegistryLock fk2lhcwpxlnqijr96irylrh1707; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -554,6 +715,14 @@ ALTER TABLE ONLY public."RegistryLock"
ADD CONSTRAINT fk2lhcwpxlnqijr96irylrh1707 FOREIGN KEY (relock_revision_id) REFERENCES public."RegistryLock"(revision_id);
--
-- Name: Domain fk2u3srsfbei272093m3b3xwj23; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Domain"
ADD CONSTRAINT fk2u3srsfbei272093m3b3xwj23 FOREIGN KEY (current_sponsor_client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: ClaimsEntry fk6sc6at5hedffc0nhdcab6ivuq; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -562,6 +731,38 @@ ALTER TABLE ONLY public."ClaimsEntry"
ADD CONSTRAINT fk6sc6at5hedffc0nhdcab6ivuq FOREIGN KEY (revision_id) REFERENCES public."ClaimsList"(revision_id);
--
-- Name: HostResource_inetAddresses fk6unwhfkcu3oq6q347fxvpagv; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."HostResource_inetAddresses"
ADD CONSTRAINT fk6unwhfkcu3oq6q347fxvpagv FOREIGN KEY (host_resource_repo_id) REFERENCES public."HostResource"(repo_id);
--
-- Name: Contact fk93c185fx7chn68uv7nl6uv2s0; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Contact"
ADD CONSTRAINT fk93c185fx7chn68uv7nl6uv2s0 FOREIGN KEY (current_sponsor_client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: DomainHost fk_domainhost_host_valid; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."DomainHost"
ADD CONSTRAINT fk_domainhost_host_valid FOREIGN KEY (ns_host_v_keys) REFERENCES public."HostResource"(repo_id);
--
-- Name: DomainHost fkfmi7bdink53swivs390m2btxg; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."DomainHost"
ADD CONSTRAINT fkfmi7bdink53swivs390m2btxg FOREIGN KEY (domain_repo_id) REFERENCES public."Domain"(repo_id);
--
-- Name: ReservedEntry fkgq03rk0bt1hb915dnyvd3vnfc; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -570,6 +771,22 @@ ALTER TABLE ONLY public."ReservedEntry"
ADD CONSTRAINT fkgq03rk0bt1hb915dnyvd3vnfc FOREIGN KEY (revision_id) REFERENCES public."ReservedList"(revision_id);
--
-- Name: Domain fkjc0r9r5y1lfbt4gpbqw4wsuvq; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Domain"
ADD CONSTRAINT fkjc0r9r5y1lfbt4gpbqw4wsuvq FOREIGN KEY (last_epp_update_client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: Contact fkmb7tdiv85863134w1wogtxrb2; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Contact"
ADD CONSTRAINT fkmb7tdiv85863134w1wogtxrb2 FOREIGN KEY (last_epp_update_client_id) REFERENCES public."Registrar"(client_id);
--
-- Name: PremiumEntry fko0gw90lpo1tuee56l0nb6y6g5; Type: FK CONSTRAINT; Schema: public; Owner: -
--

View File

@@ -78,6 +78,7 @@ ext {
'com.googlecode.json-simple:json-simple:1.1.1',
'com.ibm.icu:icu4j:57.1',
'com.jcraft:jsch:0.1.55',
'com.squareup:javapoet:1.12.1',
'com.sun.activation:javax.activation:1.2.0',
'com.sun.xml.bind:jaxb-impl:2.2.11',
'com.sun.xml.bind:jaxb-osgi:2.2.11',

25
processor/build.gradle Normal file
View File

@@ -0,0 +1,25 @@
// Copyright 2020 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.
plugins {
id 'java-library'
}
dependencies {
def deps = rootProject.dependencyMap
compile deps['com.google.code.findbugs:jsr305']
compile deps['com.google.guava:guava']
compile deps['com.squareup:javapoet']
compile deps['javax.persistence:javax.persistence-api']
}

View File

@@ -0,0 +1,24 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.github.kevinstern:software-and-algorithms:1.0
com.github.stephenc.jcip:jcip-annotations:1.0-1
com.google.auto:auto-common:0.10
com.google.code.findbugs:jFormatString:3.0.0
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotation:2.3.3
com.google.errorprone:error_prone_annotations:2.3.3
com.google.errorprone:error_prone_check_api:2.3.3
com.google.errorprone:error_prone_core:2.3.3
com.google.errorprone:error_prone_type_annotations:2.3.3
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.protobuf:protobuf-java:3.4.0
com.googlecode.java-diff-utils:diffutils:1.3.0
org.checkerframework:checker-qual:2.5.3
org.checkerframework:dataflow:2.5.3
org.checkerframework:javacutil:2.5.3
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.pcollections:pcollections:2.1.2

View File

@@ -0,0 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.

View File

@@ -0,0 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.

View File

@@ -0,0 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.

View File

@@ -0,0 +1,18 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
antlr:antlr:2.7.7
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.2
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.27
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:4.1.1
net.sf.saxon:Saxon-HE:9.9.1-5
org.antlr:antlr4-runtime:4.7.2
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,24 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.github.kevinstern:software-and-algorithms:1.0
com.github.stephenc.jcip:jcip-annotations:1.0-1
com.google.auto:auto-common:0.10
com.google.code.findbugs:jFormatString:3.0.0
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotation:2.3.3
com.google.errorprone:error_prone_annotations:2.3.3
com.google.errorprone:error_prone_check_api:2.3.3
com.google.errorprone:error_prone_core:2.3.3
com.google.errorprone:error_prone_type_annotations:2.3.3
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.protobuf:protobuf-java:3.4.0
com.googlecode.java-diff-utils:diffutils:1.3.0
org.checkerframework:checker-qual:2.5.3
org.checkerframework:dataflow:2.5.3
org.checkerframework:javacutil:2.5.3
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.pcollections:pcollections:2.1.2

View File

@@ -0,0 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.errorprone:javac:9+181-r4173-1

View File

@@ -0,0 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.5

View File

@@ -0,0 +1,11 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.5
org.jacoco:org.jacoco.ant:0.8.5
org.jacoco:org.jacoco.core:0.8.5
org.jacoco:org.jacoco.report:0.8.5
org.ow2.asm:asm-analysis:7.2
org.ow2.asm:asm-commons:7.2
org.ow2.asm:asm-tree:7.2
org.ow2.asm:asm:7.2

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,24 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.github.kevinstern:software-and-algorithms:1.0
com.github.stephenc.jcip:jcip-annotations:1.0-1
com.google.auto:auto-common:0.10
com.google.code.findbugs:jFormatString:3.0.0
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotation:2.3.3
com.google.errorprone:error_prone_annotations:2.3.3
com.google.errorprone:error_prone_check_api:2.3.3
com.google.errorprone:error_prone_core:2.3.3
com.google.errorprone:error_prone_type_annotations:2.3.3
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.protobuf:protobuf-java:3.4.0
com.googlecode.java-diff-utils:diffutils:1.3.0
org.checkerframework:checker-qual:2.5.3
org.checkerframework:dataflow:2.5.3
org.checkerframework:javacutil:2.5.3
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.pcollections:pcollections:2.1.2

View File

@@ -0,0 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

View File

@@ -0,0 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.

View File

@@ -0,0 +1,12 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.2-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.squareup:javapoet:1.12.1
javax.persistence:javax.persistence-api:2.2
org.checkerframework:checker-qual:2.10.0

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