mirror of
https://github.com/google/nomulus
synced 2026-01-30 17:42:20 +00:00
Compare commits
6 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9c40648d0 | ||
|
|
22a879e655 | ||
|
|
62433c2238 | ||
|
|
90945bcc30 | ||
|
|
f134c4bf37 | ||
|
|
44921c29d6 |
@@ -162,7 +162,10 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
// values.
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
for (Entry<Field, Object> entry : ModelUtils.getFieldValues(o).entrySet()) {
|
||||
result.put(entry.getKey().getName(), toMapRecursive(entry.getValue()));
|
||||
Field field = entry.getKey();
|
||||
if (!field.isAnnotationPresent(IgnoredInDiffableMap.class)) {
|
||||
result.put(field.getName(), toMapRecursive(entry.getValue()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else if (o instanceof Map) {
|
||||
@@ -191,6 +194,12 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
/** Marker to indicate that this filed should be ignored by {@link #toDiffableFieldMap}. */
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target(FIELD)
|
||||
protected @interface IgnoredInDiffableMap {}
|
||||
|
||||
/** Returns a map of all object fields (including sensitive data) that's used to produce diffs. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> toDiffableFieldMap() {
|
||||
|
||||
@@ -16,20 +16,24 @@ package google.registry.model.eppcommon;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.annotation.AlsoLoad;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.OnLoad;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.JsonMapBuilder;
|
||||
import google.registry.model.Jsonifiable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PostLoad;
|
||||
import javax.persistence.Transient;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
@@ -53,15 +57,17 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
public class Address extends ImmutableObject implements Jsonifiable {
|
||||
|
||||
/** The schema validation will enforce that this has 3 lines at most. */
|
||||
// TODO(shicong): Remove this field after migration. We need to figure out how to generate same
|
||||
// XML from streetLine[1,2,3].
|
||||
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
|
||||
@Transient
|
||||
List<String> street;
|
||||
|
||||
@Ignore String streetLine1;
|
||||
@Ignore @XmlTransient @IgnoredInDiffableMap String streetLine1;
|
||||
|
||||
@Ignore String streetLine2;
|
||||
@Ignore @XmlTransient @IgnoredInDiffableMap String streetLine2;
|
||||
|
||||
@Ignore String streetLine3;
|
||||
@Ignore @XmlTransient @IgnoredInDiffableMap String streetLine3;
|
||||
|
||||
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
|
||||
String city;
|
||||
@@ -86,18 +92,6 @@ public class Address extends ImmutableObject implements Jsonifiable {
|
||||
}
|
||||
}
|
||||
|
||||
public String getStreetLine1() {
|
||||
return streetLine1;
|
||||
}
|
||||
|
||||
public String getStreetLine2() {
|
||||
return streetLine2;
|
||||
}
|
||||
|
||||
public String getStreetLine13() {
|
||||
return streetLine3;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
@@ -144,6 +138,9 @@ public class Address extends ImmutableObject implements Jsonifiable {
|
||||
street == null || (!street.isEmpty() && street.size() <= 3),
|
||||
"Street address must have [1-3] lines: %s", street);
|
||||
getInstance().street = street;
|
||||
getInstance().streetLine1 = street.get(0);
|
||||
getInstance().streetLine2 = street.size() >= 2 ? street.get(1) : null;
|
||||
getInstance().streetLine3 = street.size() == 3 ? street.get(2) : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -171,8 +168,14 @@ public class Address extends ImmutableObject implements Jsonifiable {
|
||||
}
|
||||
}
|
||||
|
||||
@OnLoad
|
||||
void setStreetForCloudSql() {
|
||||
/**
|
||||
* Sets {@link #streetLine1}, {@link #streetLine2} and {@link #streetLine3} after loading the
|
||||
* entity from Datastore.
|
||||
*
|
||||
* <p>This callback method is used by Objectify to set streetLine[1,2,3] fields as they are not
|
||||
* persisted in the Datastore. TODO(shicong): Delete this method after database migration.
|
||||
*/
|
||||
void onLoad(@AlsoLoad("street") List<String> street) {
|
||||
if (street == null || street.size() == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -180,4 +183,22 @@ public class Address extends ImmutableObject implements Jsonifiable {
|
||||
streetLine2 = street.size() >= 2 ? street.get(1) : null;
|
||||
streetLine3 = street.size() >= 3 ? street.get(2) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link #street} after loading the entity from Cloud SQL.
|
||||
*
|
||||
* <p>This callback method is used by Hibernate to set {@link #street} field as it is not
|
||||
* persisted in Cloud SQL. We are doing this because the street list field is exposed by Address
|
||||
* class and is used everywhere in our code base. Also, setting/reading a list of strings is more
|
||||
* convenient.
|
||||
*/
|
||||
@PostLoad
|
||||
void postLoad() {
|
||||
street =
|
||||
streetLine1 == null
|
||||
? null
|
||||
: Stream.of(streetLine1, streetLine2, streetLine3)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,20 +29,26 @@ public class CurrencyToBillingMapUserType extends MapUserType {
|
||||
|
||||
@Override
|
||||
public Object toEntityTypeMap(Map<String, String> map) {
|
||||
return map.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> CurrencyUnit.of(entry.getKey()),
|
||||
entry ->
|
||||
new BillingAccountEntry(CurrencyUnit.of(entry.getKey()), entry.getValue())));
|
||||
return map == null
|
||||
? null
|
||||
: map.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> CurrencyUnit.of(entry.getKey()),
|
||||
entry ->
|
||||
new BillingAccountEntry(
|
||||
CurrencyUnit.of(entry.getKey()), entry.getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> toDbSupportedMap(Object map) {
|
||||
return ((Map<CurrencyUnit, BillingAccountEntry>) map)
|
||||
.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> entry.getKey().getCode(), entry -> entry.getValue().getAccountId()));
|
||||
return map == null
|
||||
? null
|
||||
: ((Map<CurrencyUnit, BillingAccountEntry>) map)
|
||||
.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> entry.getKey().getCode(),
|
||||
entry -> entry.getValue().getAccountId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// 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.registrar;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Data access object for {@link Registrar}. */
|
||||
public class RegistrarDao {
|
||||
|
||||
private RegistrarDao() {}
|
||||
|
||||
/** Persists a new or updates an existing registrar in Cloud SQL. */
|
||||
public static void saveNew(Registrar registrar) {
|
||||
checkArgumentNotNull(registrar, "registrar must be specified");
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(registrar));
|
||||
}
|
||||
|
||||
/** Updates an existing registrar in Cloud SQL, throws excpetion if it does not exist. */
|
||||
public static void update(Registrar registrar) {
|
||||
checkArgumentNotNull(registrar, "registrar must be specified");
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
checkArgument(
|
||||
checkExists(registrar.getClientId()),
|
||||
"A registrar of this id does not exist: %s.",
|
||||
registrar.getClientId());
|
||||
jpaTm().getEntityManager().merge(registrar);
|
||||
});
|
||||
}
|
||||
|
||||
/** Returns whether the registrar of the given id exists. */
|
||||
public static boolean checkExists(String clientId) {
|
||||
checkArgumentNotNull(clientId, "clientId must be specified");
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"SELECT 1 FROM Registrar WHERE clientIdentifier = :clientIdentifier",
|
||||
Integer.class)
|
||||
.setParameter("clientIdentifier", clientId)
|
||||
.setMaxResults(1)
|
||||
.getResultList()
|
||||
.size()
|
||||
> 0);
|
||||
}
|
||||
|
||||
/** Loads the registrar by its id, returns empty if it doesn't exist. */
|
||||
public static Optional<Registrar> load(String clientId) {
|
||||
checkArgumentNotNull(clientId, "clientId must be specified");
|
||||
return Optional.ofNullable(
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(Registrar.class, clientId)));
|
||||
}
|
||||
}
|
||||
132
core/src/main/java/google/registry/schema/server/Lock.java
Normal file
132
core/src/main/java/google/registry/schema/server/Lock.java
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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.server;
|
||||
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.schema.server.Lock.LockId;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* A lock on some shared resource.
|
||||
*
|
||||
* <p>Locks are either specific to a tld or global to the entire system, in which case a tld of
|
||||
* {@link GLOBAL} is used.
|
||||
*
|
||||
* <p>This uses a compound primary key as defined in {@link LockId}.
|
||||
*/
|
||||
@Entity
|
||||
@Table
|
||||
@IdClass(LockId.class)
|
||||
public class Lock {
|
||||
|
||||
/** The resource name used to create the lock. */
|
||||
@Column(nullable = false)
|
||||
@Id
|
||||
String resourceName;
|
||||
|
||||
/** The tld used to create the lock. */
|
||||
@Column(nullable = false)
|
||||
@Id
|
||||
String tld;
|
||||
|
||||
/**
|
||||
* Unique log ID of the request that owns this lock.
|
||||
*
|
||||
* <p>When that request is no longer running (is finished), the lock can be considered implicitly
|
||||
* released.
|
||||
*
|
||||
* <p>See {@link RequestStatusCheckerImpl#getLogId} for details about how it's created in
|
||||
* practice.
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
String requestLogId;
|
||||
|
||||
/** When the lock was acquired. Used for logging. */
|
||||
@Column(nullable = false)
|
||||
ZonedDateTime acquiredTime;
|
||||
|
||||
/** When the lock can be considered implicitly released. */
|
||||
@Column(nullable = false)
|
||||
ZonedDateTime expirationTime;
|
||||
|
||||
/** The scope of a lock that is not specific to a single tld. */
|
||||
static final String GLOBAL = "GLOBAL";
|
||||
|
||||
/**
|
||||
* Validate input and create a new {@link Lock} for the given resource name in the specified tld.
|
||||
*/
|
||||
private Lock(
|
||||
String resourceName,
|
||||
String tld,
|
||||
String requestLogId,
|
||||
DateTime acquiredTime,
|
||||
Duration leaseLength) {
|
||||
this.resourceName = checkArgumentNotNull(resourceName, "The resource name cannot be null");
|
||||
this.tld = checkArgumentNotNull(tld, "The tld cannot be null. For a global lock, use GLOBAL");
|
||||
this.requestLogId =
|
||||
checkArgumentNotNull(requestLogId, "The requestLogId of the lock cannot be null");
|
||||
this.acquiredTime =
|
||||
DateTimeUtils.toZonedDateTime(
|
||||
checkArgumentNotNull(acquiredTime, "The acquired time of the lock cannot be null"));
|
||||
checkArgumentNotNull(leaseLength, "The lease length of the lock cannot be null");
|
||||
this.expirationTime = DateTimeUtils.toZonedDateTime(acquiredTime.plus(leaseLength));
|
||||
}
|
||||
|
||||
// Hibernate requires a default constructor.
|
||||
private Lock() {}
|
||||
|
||||
/** Constructs a {@link Lock} object. */
|
||||
public static Lock create(
|
||||
String resourceName,
|
||||
String tld,
|
||||
String requestLogId,
|
||||
DateTime acquiredTime,
|
||||
Duration leaseLength) {
|
||||
checkArgumentNotNull(
|
||||
tld, "The tld cannot be null. To create a global lock, use the createGlobal method");
|
||||
return new Lock(resourceName, tld, requestLogId, acquiredTime, leaseLength);
|
||||
}
|
||||
|
||||
/** Constructs a {@link Lock} object with a {@link GLOBAL} scope. */
|
||||
public static Lock createGlobal(
|
||||
String resourceName, String requestLogId, DateTime acquiredTime, Duration leaseLength) {
|
||||
return new Lock(resourceName, GLOBAL, requestLogId, acquiredTime, leaseLength);
|
||||
}
|
||||
|
||||
static class LockId extends ImmutableObject implements Serializable {
|
||||
|
||||
String resourceName;
|
||||
|
||||
String tld;
|
||||
|
||||
private LockId() {}
|
||||
|
||||
LockId(String resourceName, String tld) {
|
||||
this.resourceName = checkArgumentNotNull(resourceName, "The resource name cannot be null");
|
||||
this.tld = tld;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// 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.server;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.schema.server.Lock.GLOBAL;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import google.registry.schema.server.Lock.LockId;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Data access object class for {@link Lock}. */
|
||||
public class LockDao {
|
||||
|
||||
/** Saves the {@link Lock} object to Cloud SQL. */
|
||||
public static void saveNew(Lock lock) {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
jpaTm().getEntityManager().persist(lock);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and returns a {@link Lock} object with the given resourceName and tld from Cloud SQL if
|
||||
* it exists, else empty.
|
||||
*/
|
||||
public static Optional<Lock> load(String resourceName, String tld) {
|
||||
checkArgumentNotNull(resourceName, "The resource name of the lock to load cannot be null");
|
||||
checkArgumentNotNull(tld, "The tld of the lock to load cannot be null");
|
||||
return Optional.ofNullable(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> jpaTm().getEntityManager().find(Lock.class, new LockId(resourceName, tld))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a global {@link Lock} object with the given resourceName from Cloud SQL if it exists,
|
||||
* else empty.
|
||||
*/
|
||||
public static Optional<Lock> load(String resourceName) {
|
||||
checkArgumentNotNull(resourceName, "The resource name of the lock to load cannot be null");
|
||||
return Optional.ofNullable(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm().getEntityManager().find(Lock.class, new LockId(resourceName, GLOBAL))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given {@link Lock} object from Cloud SQL. This method is idempotent and will simply
|
||||
* return if the lock has already been deleted.
|
||||
*/
|
||||
public static void delete(Lock lock) {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
Optional<Lock> loadedLock = load(lock.resourceName, lock.tld);
|
||||
if (loadedLock.isPresent()) {
|
||||
jpaTm().getEntityManager().remove(loadedLock.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Predicates.isNull;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
||||
import static google.registry.util.RegistrarUtils.normalizeRegistrarName;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
@@ -28,6 +29,7 @@ import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.model.registry.Registry;
|
||||
@@ -53,6 +55,8 @@ import org.joda.time.DateTime;
|
||||
/** Shared base class for commands to create or update a {@link Registrar}. */
|
||||
abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||
|
||||
static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Parameter(
|
||||
description = "Client identifier of the registrar account",
|
||||
required = true)
|
||||
@@ -458,4 +462,26 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||
stageEntityChange(oldRegistrar, newRegistrar);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String execute() throws Exception {
|
||||
// Save registrar to Datastore and output its response
|
||||
logger.atInfo().log(super.execute());
|
||||
|
||||
String cloudSqlMessage;
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
getChangedEntities().forEach(newEntity -> saveToCloudSql((Registrar) newEntity)));
|
||||
cloudSqlMessage =
|
||||
String.format("Updated %d entities in Cloud SQL.\n", getChangedEntities().size());
|
||||
} catch (Throwable t) {
|
||||
cloudSqlMessage = "Unexpected error saving registrar to Cloud SQL from nomulus tool command";
|
||||
logger.atSevere().withCause(t).log(cloudSqlMessage);
|
||||
}
|
||||
return cloudSqlMessage;
|
||||
}
|
||||
|
||||
abstract void saveToCloudSql(Registrar registrar);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.schema.registrar.RegistrarDao;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -69,6 +70,11 @@ final class CreateRegistrarCommand extends CreateOrUpdateRegistrarCommand
|
||||
registrarState = Optional.ofNullable(registrarState).orElse(ACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
void saveToCloudSql(Registrar registrar) {
|
||||
RegistrarDao.saveNew(registrar);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
Registrar getOldRegistrar(final String clientId) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DatastoreServiceUtils.getNameOrId;
|
||||
@@ -45,9 +46,9 @@ import javax.annotation.Nullable;
|
||||
public abstract class MutatingCommand extends ConfirmingCommand implements CommandWithRemoteApi {
|
||||
|
||||
/**
|
||||
* A mutation of a specific entity, represented by an old and a new version of the entity.
|
||||
* Storing the old version is necessary to enable checking that the existing entity has not been
|
||||
* modified when applying a mutation that was created outside the same transaction.
|
||||
* A mutation of a specific entity, represented by an old and a new version of the entity. Storing
|
||||
* the old version is necessary to enable checking that the existing entity has not been modified
|
||||
* when applying a mutation that was created outside the same transaction.
|
||||
*/
|
||||
private static class EntityChange {
|
||||
|
||||
@@ -169,8 +170,8 @@ public abstract class MutatingCommand extends ConfirmingCommand implements Comma
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of lists of EntityChange actions to commit. Each list should be executed in
|
||||
* order inside a single transaction.
|
||||
* Returns a set of lists of EntityChange actions to commit. Each list should be executed in order
|
||||
* inside a single transaction.
|
||||
*/
|
||||
private ImmutableSet<ImmutableList<EntityChange>> getCollatedEntityChangeBatches() {
|
||||
ImmutableSet.Builder<ImmutableList<EntityChange>> batches = new ImmutableSet.Builder<>();
|
||||
@@ -221,4 +222,11 @@ public abstract class MutatingCommand extends ConfirmingCommand implements Comma
|
||||
? "No entity changes to apply."
|
||||
: changedEntitiesMap.values().stream().map(Object::toString).collect(joining("\n"));
|
||||
}
|
||||
|
||||
/** Returns the collection of the new entity in the {@link EntityChange}. */
|
||||
protected ImmutableList<ImmutableObject> getChangedEntities() {
|
||||
return changedEntitiesMap.values().stream()
|
||||
.map(entityChange -> entityChange.newEntity)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.schema.registrar.RegistrarDao;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Command to update a Registrar. */
|
||||
@@ -49,4 +50,9 @@ final class UpdateRegistrarCommand extends CreateOrUpdateRegistrarCommand {
|
||||
+ " contact.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void saveToCloudSql(Registrar registrar) {
|
||||
RegistrarDao.update(registrar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +119,9 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
// handler, registrar-settings really only supports read and update.
|
||||
String op = Optional.ofNullable((String) input.get(OP_PARAM)).orElse("read");
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, ?> args = (Map<String, Object>)
|
||||
Optional.<Object>ofNullable(input.get(ARGS_PARAM)).orElse(ImmutableMap.of());
|
||||
Map<String, ?> args =
|
||||
(Map<String, Object>)
|
||||
Optional.<Object>ofNullable(input.get(ARGS_PARAM)).orElse(ImmutableMap.of());
|
||||
|
||||
logger.atInfo().log("Received request '%s' on registrar '%s' with args %s", op, clientId, args);
|
||||
String status = "SUCCESS";
|
||||
@@ -296,8 +297,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
.ifPresent(builder::setEmailAddress);
|
||||
builder.setPhoneNumber(
|
||||
RegistrarFormFields.PHONE_NUMBER_FIELD.extractUntyped(args).orElse(null));
|
||||
builder.setFaxNumber(
|
||||
RegistrarFormFields.FAX_NUMBER_FIELD.extractUntyped(args).orElse(null));
|
||||
builder.setFaxNumber(RegistrarFormFields.FAX_NUMBER_FIELD.extractUntyped(args).orElse(null));
|
||||
builder.setLocalizedAddress(
|
||||
RegistrarFormFields.L10N_ADDRESS_FIELD.extractUntyped(args).orElse(null));
|
||||
|
||||
@@ -357,9 +357,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
* <p>On success, returns {@code builder.build()}.
|
||||
*/
|
||||
private Registrar checkNotChangedUnlessAllowed(
|
||||
Registrar.Builder builder,
|
||||
Registrar originalRegistrar,
|
||||
Role allowedRole) {
|
||||
Registrar.Builder builder, Registrar originalRegistrar, Role allowedRole) {
|
||||
Registrar updatedRegistrar = builder.build();
|
||||
if (updatedRegistrar.equals(originalRegistrar)) {
|
||||
return updatedRegistrar;
|
||||
@@ -374,9 +372,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
}
|
||||
Map<?, ?> diffs =
|
||||
DiffUtils.deepDiff(
|
||||
originalRegistrar.toDiffableFieldMap(),
|
||||
updatedRegistrar.toDiffableFieldMap(),
|
||||
true);
|
||||
originalRegistrar.toDiffableFieldMap(), updatedRegistrar.toDiffableFieldMap(), true);
|
||||
throw new ForbiddenException(
|
||||
String.format("Unauthorized: only %s can change fields %s", allowedRole, diffs.keySet()));
|
||||
}
|
||||
@@ -400,9 +396,10 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
Set<String> emails = new HashSet<>();
|
||||
for (RegistrarContact contact : updatedContacts) {
|
||||
if (!emails.add(contact.getEmailAddress())) {
|
||||
throw new ContactRequirementException(String.format(
|
||||
"One email address (%s) cannot be used for multiple contacts",
|
||||
contact.getEmailAddress()));
|
||||
throw new ContactRequirementException(
|
||||
String.format(
|
||||
"One email address (%s) cannot be used for multiple contacts",
|
||||
contact.getEmailAddress()));
|
||||
}
|
||||
}
|
||||
// Check that required contacts don't go away, once they are set.
|
||||
|
||||
@@ -21,7 +21,6 @@ import static google.registry.security.JsonResponseHelper.Status.ERROR;
|
||||
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
|
||||
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Throwables;
|
||||
@@ -34,6 +33,7 @@ import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarContact;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.Method;
|
||||
import google.registry.request.HttpException.ForbiddenException;
|
||||
import google.registry.request.JsonActionRunner;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
@@ -123,10 +123,16 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
!Strings.isNullOrEmpty(postInput.fullyQualifiedDomainName),
|
||||
"Missing key for fullyQualifiedDomainName");
|
||||
checkNotNull(postInput.isLock, "Missing key for isLock");
|
||||
checkArgumentPresent(authResult.userAuthInfo(), "User is not logged in");
|
||||
UserAuthInfo userAuthInfo =
|
||||
authResult
|
||||
.userAuthInfo()
|
||||
.orElseThrow(() -> new ForbiddenException("User is not logged in"));
|
||||
|
||||
boolean isAdmin = authResult.userAuthInfo().get().isUserAdmin();
|
||||
verifyRegistryLockPassword(postInput);
|
||||
boolean isAdmin = userAuthInfo.isUserAdmin();
|
||||
String userEmail = userAuthInfo.user().getEmail();
|
||||
if (!isAdmin) {
|
||||
verifyRegistryLockPassword(postInput, userEmail);
|
||||
}
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
@@ -135,12 +141,12 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
? domainLockUtils.createRegistryLockRequest(
|
||||
postInput.fullyQualifiedDomainName,
|
||||
postInput.clientId,
|
||||
postInput.pocId,
|
||||
userEmail,
|
||||
isAdmin,
|
||||
clock)
|
||||
: domainLockUtils.createRegistryUnlockRequest(
|
||||
postInput.fullyQualifiedDomainName, postInput.clientId, isAdmin, clock);
|
||||
sendVerificationEmail(registryLock, postInput.isLock);
|
||||
sendVerificationEmail(registryLock, userEmail, postInput.isLock);
|
||||
});
|
||||
String action = postInput.isLock ? "lock" : "unlock";
|
||||
return JsonResponseHelper.create(SUCCESS, String.format("Successful %s", action));
|
||||
@@ -152,7 +158,7 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
}
|
||||
}
|
||||
|
||||
private void sendVerificationEmail(RegistryLock lock, boolean isLock) {
|
||||
private void sendVerificationEmail(RegistryLock lock, String userEmail, boolean isLock) {
|
||||
try {
|
||||
String url =
|
||||
new URIBuilder()
|
||||
@@ -165,8 +171,7 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
.toString();
|
||||
String body = String.format(VERIFICATION_EMAIL_TEMPLATE, lock.getDomainName(), url);
|
||||
ImmutableList<InternetAddress> recipients =
|
||||
ImmutableList.of(
|
||||
new InternetAddress(authResult.userAuthInfo().get().user().getEmail(), true));
|
||||
ImmutableList.of(new InternetAddress(userEmail, true));
|
||||
String action = isLock ? "lock" : "unlock";
|
||||
sendEmailService.sendEmail(
|
||||
EmailMessage.newBuilder()
|
||||
@@ -180,30 +185,25 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyRegistryLockPassword(RegistryLockPostInput postInput)
|
||||
private void verifyRegistryLockPassword(RegistryLockPostInput postInput, String userEmail)
|
||||
throws RegistrarAccessDeniedException {
|
||||
// Verify that the user can access the registrar and that the user is either an admin or has
|
||||
// Verify that the user can access the registrar and that the user has
|
||||
// registry lock enabled and provided a correct password
|
||||
checkArgument(authResult.userAuthInfo().isPresent(), "Auth result not present");
|
||||
Registrar registrar = registrarAccessor.getRegistrar(postInput.clientId);
|
||||
checkArgument(
|
||||
registrar.isRegistryLockAllowed(), "Registry lock not allowed for this registrar");
|
||||
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
|
||||
if (!userAuthInfo.isUserAdmin()) {
|
||||
checkArgument(!Strings.isNullOrEmpty(postInput.pocId), "Missing key for pocId");
|
||||
checkArgument(!Strings.isNullOrEmpty(postInput.password), "Missing key for password");
|
||||
RegistrarContact registrarContact =
|
||||
registrar.getContacts().stream()
|
||||
.filter(contact -> contact.getEmailAddress().equals(postInput.pocId))
|
||||
.findFirst()
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format("Unknown registrar POC ID %s", postInput.pocId)));
|
||||
checkArgument(
|
||||
registrarContact.verifyRegistryLockPassword(postInput.password),
|
||||
"Incorrect registry lock password for contact");
|
||||
}
|
||||
checkArgument(!Strings.isNullOrEmpty(postInput.password), "Missing key for password");
|
||||
RegistrarContact registrarContact =
|
||||
registrar.getContacts().stream()
|
||||
.filter(contact -> contact.getEmailAddress().equals(userEmail))
|
||||
.findFirst()
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format("Unknown user email %s", userEmail)));
|
||||
checkArgument(
|
||||
registrarContact.verifyRegistryLockPassword(postInput.password),
|
||||
"Incorrect registry lock password for contact");
|
||||
}
|
||||
|
||||
/** Value class that represents the expected input body from the UI request. */
|
||||
@@ -211,7 +211,6 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
private String clientId;
|
||||
private String fullyQualifiedDomainName;
|
||||
private Boolean isLock;
|
||||
private String pocId;
|
||||
private String password;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,17 +25,12 @@
|
||||
<class>google.registry.schema.domain.RegistryLock</class>
|
||||
<class>google.registry.schema.tmch.ClaimsList</class>
|
||||
<class>google.registry.schema.cursor.Cursor</class>
|
||||
<class>google.registry.model.transfer.BaseTransferObject</class>
|
||||
<class>google.registry.schema.server.Lock</class>
|
||||
<class>google.registry.schema.tld.PremiumList</class>
|
||||
<class>google.registry.schema.tld.PremiumEntry</class>
|
||||
<class>google.registry.schema.tld.ReservedList</class>
|
||||
<class>google.registry.model.domain.secdns.DelegationSignerData</class>
|
||||
<class>google.registry.model.domain.DesignatedContact</class>
|
||||
<class>google.registry.model.domain.DomainBase</class>
|
||||
<class>google.registry.model.domain.GracePeriod</class>
|
||||
<class>org.joda.time.Period</class>
|
||||
<class>google.registry.model.transfer.TransferData</class>
|
||||
<class>google.registry.model.eppcommon.Trid</class>
|
||||
|
||||
<!-- Customized type converters -->
|
||||
<class>google.registry.persistence.BloomFilterConverter</class>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// 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.model.eppcommon;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Tests for {@link Address}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class AddressTest {
|
||||
@Test
|
||||
public void onLoad_setsIndividualStreetLinesSuccessfully() {
|
||||
Address address = new Address();
|
||||
address.onLoad(ImmutableList.of("line1", "line2", "line3"));
|
||||
assertThat(address.streetLine1).isEqualTo("line1");
|
||||
assertThat(address.streetLine2).isEqualTo("line2");
|
||||
assertThat(address.streetLine3).isEqualTo("line3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoad_setsOnlyNonNullStreetLines() {
|
||||
Address address = new Address();
|
||||
address.onLoad(ImmutableList.of("line1", "line2"));
|
||||
assertThat(address.streetLine1).isEqualTo("line1");
|
||||
assertThat(address.streetLine2).isEqualTo("line2");
|
||||
assertThat(address.streetLine3).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoad_doNothingIfInputIsNull() {
|
||||
Address address = new Address();
|
||||
address.onLoad(null);
|
||||
assertThat(address.streetLine1).isNull();
|
||||
assertThat(address.streetLine2).isNull();
|
||||
assertThat(address.streetLine3).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postLoad_setsStreetListSuccessfully() {
|
||||
Address address = new Address();
|
||||
address.streetLine1 = "line1";
|
||||
address.streetLine2 = "line2";
|
||||
address.streetLine3 = "line3";
|
||||
address.postLoad();
|
||||
assertThat(address.street).containsExactly("line1", "line2", "line3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postLoad_setsOnlyNonNullStreetLines() {
|
||||
Address address = new Address();
|
||||
address.streetLine1 = "line1";
|
||||
address.streetLine2 = "line2";
|
||||
address.postLoad();
|
||||
assertThat(address.street).containsExactly("line1", "line2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postLoad_doNothingIfInputIsNull() {
|
||||
Address address = new Address();
|
||||
address.postLoad();
|
||||
assertThat(address.street).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// 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 static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.truth.Expect;
|
||||
import java.util.Collections;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Entity;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests to verify persistence.xml is valid. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class PersistenceXmlTest {
|
||||
|
||||
@ClassRule public static final Expect expect = Expect.create();
|
||||
|
||||
@Test
|
||||
public void verifyClassTags_containOnlyRequiredClasses() {
|
||||
ImmutableList<Class> managedClassed = PersistenceXmlUtility.getManagedClasses();
|
||||
|
||||
ImmutableList<Class> unnecessaryClasses =
|
||||
managedClassed.stream()
|
||||
.filter(
|
||||
clazz ->
|
||||
!clazz.isAnnotationPresent(Entity.class)
|
||||
&& !AttributeConverter.class.isAssignableFrom(clazz))
|
||||
.collect(toImmutableList());
|
||||
|
||||
ImmutableSet<Class> duplicateClasses =
|
||||
managedClassed.stream()
|
||||
.filter(clazz -> Collections.frequency(managedClassed, clazz) > 1)
|
||||
.collect(toImmutableSet());
|
||||
|
||||
expect
|
||||
.withMessage("Found duplicate <class> tags defined in persistence.xml.")
|
||||
.that(duplicateClasses)
|
||||
.isEmpty();
|
||||
|
||||
expect
|
||||
.withMessage(
|
||||
"Found unnecessary <class> tags defined in persistence.xml. Only entity class and"
|
||||
+ " implementation of AttributeConverter are required to be added in"
|
||||
+ " persistence.xml.")
|
||||
.that(unnecessaryClasses)
|
||||
.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,17 @@ import google.registry.model.domain.DomainBaseSqlTest;
|
||||
import google.registry.model.registry.RegistryLockDaoTest;
|
||||
import google.registry.persistence.transaction.JpaEntityCoverage;
|
||||
import google.registry.schema.cursor.CursorDaoTest;
|
||||
import google.registry.schema.registrar.RegistrarDaoTest;
|
||||
import google.registry.schema.server.LockDaoTest;
|
||||
import google.registry.schema.tld.PremiumListDaoTest;
|
||||
import google.registry.schema.tld.ReservedListDaoTest;
|
||||
import google.registry.schema.tmch.ClaimsListDaoTest;
|
||||
import google.registry.tools.CreateRegistrarCommandTest;
|
||||
import google.registry.tools.CreateReservedListCommandTest;
|
||||
import google.registry.tools.DomainLockUtilsTest;
|
||||
import google.registry.tools.LockDomainCommandTest;
|
||||
import google.registry.tools.UnlockDomainCommandTest;
|
||||
import google.registry.tools.UpdateRegistrarCommandTest;
|
||||
import google.registry.tools.UpdateReservedListCommandTest;
|
||||
import google.registry.tools.server.CreatePremiumListActionTest;
|
||||
import google.registry.tools.server.UpdatePremiumListActionTest;
|
||||
@@ -53,18 +57,22 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||
@SuiteClasses({
|
||||
ClaimsListDaoTest.class,
|
||||
CreatePremiumListActionTest.class,
|
||||
CreateRegistrarCommandTest.class,
|
||||
CreateReservedListCommandTest.class,
|
||||
CursorDaoTest.class,
|
||||
DomainLockUtilsTest.class,
|
||||
LockDaoTest.class,
|
||||
LockDomainCommandTest.class,
|
||||
DomainBaseSqlTest.class,
|
||||
PremiumListDaoTest.class,
|
||||
RegistrarDaoTest.class,
|
||||
RegistryLockDaoTest.class,
|
||||
RegistryLockGetActionTest.class,
|
||||
RegistryLockVerifyActionTest.class,
|
||||
ReservedListDaoTest.class,
|
||||
UnlockDomainCommandTest.class,
|
||||
UpdatePremiumListActionTest.class,
|
||||
UpdateRegistrarCommandTest.class,
|
||||
UpdateReservedListCommandTest.class
|
||||
})
|
||||
public class SqlIntegrationTestSuite {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// 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.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RegistrarDao}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RegistrarDaoTest extends EntityTestCase {
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
public final JpaIntegrationWithCoverageRule jpaRule =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
|
||||
|
||||
private Registrar testRegistrar;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
testRegistrar =
|
||||
new Registrar.Builder()
|
||||
.setType(Registrar.Type.TEST)
|
||||
.setClientId("registrarId")
|
||||
.setRegistrarName("registrarName")
|
||||
.setLocalizedAddress(
|
||||
new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 Example Boulevard."))
|
||||
.setCity("Williamsburg")
|
||||
.setState("NY")
|
||||
.setZip("11211")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveNew_worksSuccessfully() {
|
||||
assertThat(RegistrarDao.checkExists("registrarId")).isFalse();
|
||||
RegistrarDao.saveNew(testRegistrar);
|
||||
assertThat(RegistrarDao.checkExists("registrarId")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update_worksSuccessfully() {
|
||||
RegistrarDao.saveNew(testRegistrar);
|
||||
Registrar persisted = RegistrarDao.load("registrarId").get();
|
||||
assertThat(persisted.getRegistrarName()).isEqualTo("registrarName");
|
||||
RegistrarDao.update(persisted.asBuilder().setRegistrarName("changedRegistrarName").build());
|
||||
persisted = RegistrarDao.load("registrarId").get();
|
||||
assertThat(persisted.getRegistrarName()).isEqualTo("changedRegistrarName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update_throwsExceptionWhenEntityDoesNotExist() {
|
||||
assertThat(RegistrarDao.checkExists("registrarId")).isFalse();
|
||||
assertThrows(IllegalArgumentException.class, () -> RegistrarDao.update(testRegistrar));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load_worksSuccessfully() {
|
||||
assertThat(RegistrarDao.checkExists("registrarId")).isFalse();
|
||||
RegistrarDao.saveNew(testRegistrar);
|
||||
Registrar persisted = RegistrarDao.load("registrarId").get();
|
||||
|
||||
assertThat(persisted.getClientId()).isEqualTo("registrarId");
|
||||
assertThat(persisted.getRegistrarName()).isEqualTo("registrarName");
|
||||
assertThat(persisted.getCreationTime()).isEqualTo(fakeClock.nowUtc());
|
||||
assertThat(persisted.getLocalizedAddress())
|
||||
.isEqualTo(
|
||||
new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 Example Boulevard."))
|
||||
.setCity("Williamsburg")
|
||||
.setState("NY")
|
||||
.setZip("11211")
|
||||
.setCountryCode("US")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// 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.server;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.RollbackException;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link Lock}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class LockDaoTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
public final JpaIntegrationWithCoverageRule jpaRule =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
|
||||
|
||||
@Test
|
||||
public void save_worksSuccessfully() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void save_failsWhenLockAlreadyExists() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
Lock lock2 =
|
||||
Lock.create("testResource", "tld", "testLogId2", fakeClock.nowUtc(), Duration.millis(4));
|
||||
RollbackException thrown = assertThrows(RollbackException.class, () -> LockDao.saveNew(lock2));
|
||||
assertThat(thrown.getCause().getCause().getCause().getMessage())
|
||||
.contains("duplicate key value violates unique constraint");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void save_worksSuccesfullyGlobalLock() {
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load_worksSuccessfully() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load_worksSuccessfullyGlobalLock() {
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load_worksSuccesfullyLockDoesNotExist() {
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_worksSuccesfully() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
LockDao.delete(lock);
|
||||
returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_worksSuccessfullyGlobalLock() {
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
LockDao.delete(lock);
|
||||
returnedLock = LockDao.load("testResource");
|
||||
assertThat(returnedLock.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_succeedsLockDoesntExist() {
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.delete(lock);
|
||||
}
|
||||
}
|
||||
@@ -33,12 +33,17 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Range;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||
import google.registry.schema.registrar.RegistrarDao;
|
||||
import google.registry.testing.CertificateSamples;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mock;
|
||||
@@ -46,6 +51,12 @@ import org.mockito.Mock;
|
||||
/** Unit tests for {@link CreateRegistrarCommand}. */
|
||||
public class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarCommand> {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
public final JpaIntegrationWithCoverageRule jpaRule =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
|
||||
|
||||
@Mock private AppEngineConnection connection;
|
||||
|
||||
@Before
|
||||
@@ -100,6 +111,28 @@ public class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarC
|
||||
eq(new byte[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_alsoSaveToCloudSql() throws Exception {
|
||||
runCommandForced(
|
||||
"--name=blobio",
|
||||
"--password=\"some_password\"",
|
||||
"--registrar_type=REAL",
|
||||
"--iana_id=8",
|
||||
"--passcode=01234",
|
||||
"--icann_referral_email=foo@bar.test",
|
||||
"--street=\"123 Fake St\"",
|
||||
"--city Fakington",
|
||||
"--state MA",
|
||||
"--zip 00351",
|
||||
"--cc US",
|
||||
"clientz");
|
||||
|
||||
Optional<Registrar> registrar = Registrar.loadByClientId("clientz");
|
||||
assertThat(registrar).isPresent();
|
||||
assertThat(registrar.get().verifyPassword("some_password")).isTrue();
|
||||
assertThat(RegistrarDao.checkExists("clientz")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_quotedPassword() throws Exception {
|
||||
runCommandForced(
|
||||
|
||||
@@ -32,16 +32,36 @@ import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
import google.registry.model.registrar.Registrar.Type;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||
import google.registry.schema.registrar.RegistrarDao;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import java.util.Optional;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link UpdateRegistrarCommand}. */
|
||||
public class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarCommand> {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
public final JpaIntegrationWithCoverageRule jpaRule =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
|
||||
|
||||
@Test
|
||||
public void testSuccess_alsoUpdateInCloudSql() throws Exception {
|
||||
assertThat(loadRegistrar("NewRegistrar").verifyPassword("some_password")).isFalse();
|
||||
RegistrarDao.saveNew(loadRegistrar("NewRegistrar"));
|
||||
runCommand("--password=some_password", "--force", "NewRegistrar");
|
||||
assertThat(loadRegistrar("NewRegistrar").verifyPassword("some_password")).isTrue();
|
||||
assertThat(RegistrarDao.load("NewRegistrar").get().verifyPassword("some_password")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_password() throws Exception {
|
||||
assertThat(loadRegistrar("NewRegistrar").verifyPassword("some_password")).isFalse();
|
||||
|
||||
@@ -132,6 +132,7 @@ public final class RegistryLockPostActionTest {
|
||||
createAction(
|
||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
|
||||
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
|
||||
// we should still email the admin user's email address
|
||||
assertSuccess(response, "unlock", "johndoe@theregistrar.com");
|
||||
}
|
||||
|
||||
@@ -171,7 +172,7 @@ public final class RegistryLockPostActionTest {
|
||||
|
||||
@Test
|
||||
public void testSuccess_adminUser() throws Exception {
|
||||
// Admin user should be able to lock/unlock regardless
|
||||
// Admin user should be able to lock/unlock regardless -- and we use the admin user's email
|
||||
action =
|
||||
createAction(
|
||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
|
||||
@@ -179,6 +180,20 @@ public final class RegistryLockPostActionTest {
|
||||
assertSuccess(response, "lock", "johndoe@theregistrar.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_adminUser_doesNotRequirePassword() throws Exception {
|
||||
action =
|
||||
createAction(
|
||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
|
||||
Map<String, ?> response =
|
||||
action.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "example.tld",
|
||||
"isLock", true));
|
||||
assertSuccess(response, "lock", "johndoe@theregistrar.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noInput() {
|
||||
Map<String, ?> response = action.handleJsonRequest(null);
|
||||
@@ -231,20 +246,21 @@ public final class RegistryLockPostActionTest {
|
||||
ImmutableMap.of(
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "example.tld",
|
||||
"isLock", true,
|
||||
"pocId", "Marla.Singer@crr.com"));
|
||||
"isLock", true));
|
||||
assertFailureWithMessage(response, "Missing key for password");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notEnabledForRegistrarContact() {
|
||||
action =
|
||||
createAction(
|
||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, false)));
|
||||
Map<String, ?> response =
|
||||
action.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "example.tld",
|
||||
"isLock", true,
|
||||
"pocId", "johndoe@theregistrar.com",
|
||||
"password", "hi"));
|
||||
assertFailureWithMessage(response, "Incorrect registry lock password for contact");
|
||||
}
|
||||
@@ -257,7 +273,6 @@ public final class RegistryLockPostActionTest {
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "example.tld",
|
||||
"isLock", true,
|
||||
"pocId", "Marla.Singer@crr.com",
|
||||
"password", "badPassword"));
|
||||
assertFailureWithMessage(response, "Incorrect registry lock password for contact");
|
||||
}
|
||||
@@ -270,36 +285,10 @@ public final class RegistryLockPostActionTest {
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "bad.tld",
|
||||
"isLock", true,
|
||||
"pocId", "Marla.Singer@crr.com",
|
||||
"password", "hi"));
|
||||
assertFailureWithMessage(response, "Unknown domain bad.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noPocId() {
|
||||
Map<String, ?> response =
|
||||
action.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "bad.tld",
|
||||
"isLock", true,
|
||||
"password", "hi"));
|
||||
assertFailureWithMessage(response, "Missing key for pocId");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_invalidPocId() {
|
||||
Map<String, ?> response =
|
||||
action.handleJsonRequest(
|
||||
ImmutableMap.of(
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "bad.tld",
|
||||
"isLock", true,
|
||||
"pocId", "someotherpoc@crr.com",
|
||||
"password", "hi"));
|
||||
assertFailureWithMessage(response, "Unknown registrar POC ID someotherpoc@crr.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_previousLockUnlocked() throws Exception {
|
||||
RegistryLockDao.save(
|
||||
@@ -357,7 +346,6 @@ public final class RegistryLockPostActionTest {
|
||||
"isLock", lock,
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "example.tld",
|
||||
"pocId", "Marla.Singer@crr.com",
|
||||
"password", "hi");
|
||||
}
|
||||
|
||||
|
||||
22
db/src/main/resources/sql/flyway/V18__create_lock.sql
Normal file
22
db/src/main/resources/sql/flyway/V18__create_lock.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
-- 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 "Lock" (
|
||||
resource_name text not null,
|
||||
tld text not null,
|
||||
acquired_time timestamptz not null,
|
||||
expiration_time timestamptz not null,
|
||||
request_log_id text not null,
|
||||
primary key (resource_name, tld)
|
||||
);
|
||||
@@ -77,6 +77,15 @@
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table "Lock" (
|
||||
resource_name text not null,
|
||||
tld text not null,
|
||||
acquired_time timestamptz not null,
|
||||
expiration_time timestamptz not null,
|
||||
request_log_id text not null,
|
||||
primary key (resource_name, tld)
|
||||
);
|
||||
|
||||
create table "PremiumEntry" (
|
||||
revision_id int8 not null,
|
||||
domain_label text not null,
|
||||
|
||||
@@ -116,6 +116,19 @@ CREATE TABLE public."Domain" (
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: Lock; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public."Lock" (
|
||||
resource_name text NOT NULL,
|
||||
tld text NOT NULL,
|
||||
acquired_time timestamp with time zone NOT NULL,
|
||||
expiration_time timestamp with time zone NOT NULL,
|
||||
request_log_id text NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: PremiumEntry; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
@@ -374,6 +387,14 @@ ALTER TABLE ONLY public."Domain"
|
||||
ADD CONSTRAINT "Domain_pkey" PRIMARY KEY (repo_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: Lock Lock_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public."Lock"
|
||||
ADD CONSTRAINT "Lock_pkey" PRIMARY KEY (resource_name, tld);
|
||||
|
||||
|
||||
--
|
||||
-- Name: PremiumEntry PremiumEntry_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
@@ -27,13 +27,14 @@ fi
|
||||
|
||||
environment="$1"
|
||||
dest="$2"
|
||||
gcs_prefix="storage.googleapis.com/domain-registry-maven-repository"
|
||||
gcs_prefix="gcs://domain-registry-maven-repository"
|
||||
|
||||
# Let Gradle put its caches (dependency cache and build cache) in the source
|
||||
# tree. This allows sharing of the caches between steps in a Cloud Build
|
||||
# task. (See ./cloudbuild-nomulus.yaml, which calls this script in several
|
||||
# steps). If left at their default location, the caches will be lost after
|
||||
# each step.
|
||||
# Note: must be consistent with value in ./cloudbuild-nomulus.yaml
|
||||
export GRADLE_USER_HOME="./cloudbuild-caches"
|
||||
|
||||
if [ "${environment}" == tool ]
|
||||
@@ -41,8 +42,8 @@ then
|
||||
mkdir -p "${dest}"
|
||||
|
||||
./gradlew clean :core:buildToolImage \
|
||||
-PmavenUrl=https://"${gcs_prefix}"/maven \
|
||||
-PpluginsUrl=https://"${gcs_prefix}"/plugins
|
||||
-PmavenUrl="${gcs_prefix}"/maven \
|
||||
-PpluginsUrl="${gcs_prefix}"/plugins
|
||||
|
||||
mv core/build/libs/nomulus.jar "${dest}"
|
||||
else
|
||||
@@ -50,8 +51,8 @@ else
|
||||
mkdir -p "${dest}"
|
||||
|
||||
./gradlew clean stage -Penvironment="${environment}" \
|
||||
-PmavenUrl=https://"${gcs_prefix}"/maven \
|
||||
-PpluginsUrl=https://"${gcs_prefix}"/plugins
|
||||
-PmavenUrl="${gcs_prefix}"/maven \
|
||||
-PpluginsUrl="${gcs_prefix}"/plugins
|
||||
|
||||
for service in default pubapi backend tools
|
||||
do
|
||||
|
||||
@@ -21,7 +21,15 @@ steps:
|
||||
args: ['mkdir', 'nomulus']
|
||||
# Run tests
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
args: ['./gradlew', 'test', '-PskipDockerIncompatibleTests=true']
|
||||
# Set home for Gradle caches. Must be consistent with last step below
|
||||
# and ./build_nomulus_for_env.sh
|
||||
env: [ 'GRADLE_USER_HOME=./cloudbuild-caches' ]
|
||||
args: ['./gradlew',
|
||||
'test',
|
||||
'-PskipDockerIncompatibleTests=true',
|
||||
'-PmavenUrl=gcs://domain-registry-maven-repository/maven',
|
||||
'-PpluginsUrl=gcs://domain-registry-maven-repository/plugins'
|
||||
]
|
||||
# Build the tool binary and image.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
args: ['release/build_nomulus_for_env.sh', 'tool', 'output']
|
||||
@@ -70,20 +78,23 @@ steps:
|
||||
# server/schema compatibility tests.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
entrypoint: /bin/bash
|
||||
# Set home for Gradle caches. Must be consistent with second step above
|
||||
# and ./build_nomulus_for_env.sh
|
||||
env: [ 'GRADLE_USER_HOME=./cloudbuild-caches' ]
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -e
|
||||
./gradlew \
|
||||
:db:publish \
|
||||
-PmavenUrl=https://storage.googleapis.com/domain-registry-maven-repository/maven \
|
||||
-PpluginsUrl=https://storage.googleapis.com/domain-registry-maven-repository/plugins \
|
||||
-PmavenUrl=gcs://domain-registry-maven-repository/maven \
|
||||
-PpluginsUrl=gcs://domain-registry-maven-repository/plugins \
|
||||
-Ppublish_repo=gcs://${PROJECT_ID}-deployed-tags/maven \
|
||||
-Pschema_version=${TAG_NAME}
|
||||
./gradlew \
|
||||
:core:publish \
|
||||
-PmavenUrl=https://storage.googleapis.com/domain-registry-maven-repository/maven \
|
||||
-PpluginsUrl=https://storage.googleapis.com/domain-registry-maven-repository/plugins \
|
||||
-PmavenUrl=gcs://domain-registry-maven-repository/maven \
|
||||
-PpluginsUrl=gcs://domain-registry-maven-repository/plugins \
|
||||
-Ppublish_repo=gcs://${PROJECT_ID}-deployed-tags/maven \
|
||||
-Pnomulus_version=${TAG_NAME}
|
||||
# Upload schema jar for use by schema deployment.
|
||||
|
||||
@@ -19,8 +19,8 @@ steps:
|
||||
- ./gradlew
|
||||
- :proxy:test
|
||||
- :proxy:buildProxyImage
|
||||
- -PmavenUrl=https://storage.googleapis.com/domain-registry-maven-repository/maven
|
||||
- -PpluginsUrl=https://storage.googleapis.com/domain-registry-maven-repository/plugins
|
||||
- -PmavenUrl=gcs://domain-registry-maven-repository/maven
|
||||
- -PpluginsUrl=gcs://domain-registry-maven-repository/plugins
|
||||
# Tag and push the image. We can't let Cloud Build's default processing do that for us
|
||||
# because we need to push the image before we can sign it in the following step.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
|
||||
Reference in New Issue
Block a user