mirror of
https://github.com/google/nomulus.git
synced 2025-06-13 16:04:45 +02:00
Run the (Un)lockDomainCommand in an outer JPA txn (#688)
* Run the (Un)lockDomainCommand in an outer JPA txn There are a couple things going on here in this commit. First, we add an external JPA transaction in the LockOrUnlockDomainCommand class. This doesn't appear to do much, but it avoids a situation similar to deadlock if an error occurs in Datastore when saving the domain object. Specifically, DomainLockUtils relies on the fact that any error in Datastore will be re-thrown in the JPA transaction, meaning that any Datastore error will back out of the SQL transaction as well. However, this is no longer true if we are already in a Datastore transaction when calling DomainLockUtils (unless, again, we are also in a JPA transaction). Basically, we require that the outer transaction is the JPA one. Secondly, this just allows for more breakglass operations in the lock or unlock domain commands -- in a situation where things possibly go haywire, we should allow admins to make sure with certainty that a domain is locked or unlocked. * Add more robustness and tests for admins locking locked domains * Fix expected exception message in tests
This commit is contained in:
parent
8ab83ed4b3
commit
c2207fe7f5
8 changed files with 89 additions and 115 deletions
|
@ -117,7 +117,7 @@ public final class DomainLockUtils {
|
||||||
RegistryLock newLock =
|
RegistryLock newLock =
|
||||||
RegistryLockDao.save(lock.asBuilder().setLockCompletionTimestamp(now).build());
|
RegistryLockDao.save(lock.asBuilder().setLockCompletionTimestamp(now).build());
|
||||||
setAsRelock(newLock);
|
setAsRelock(newLock);
|
||||||
tm().transact(() -> applyLockStatuses(newLock, now));
|
tm().transact(() -> applyLockStatuses(newLock, now, isAdmin));
|
||||||
return newLock;
|
return newLock;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ public final class DomainLockUtils {
|
||||||
createLockBuilder(domainName, registrarId, registrarPocId, isAdmin)
|
createLockBuilder(domainName, registrarId, registrarPocId, isAdmin)
|
||||||
.setLockCompletionTimestamp(now)
|
.setLockCompletionTimestamp(now)
|
||||||
.build());
|
.build());
|
||||||
tm().transact(() -> applyLockStatuses(newLock, now));
|
tm().transact(() -> applyLockStatuses(newLock, now, isAdmin));
|
||||||
setAsRelock(newLock);
|
setAsRelock(newLock);
|
||||||
return newLock;
|
return newLock;
|
||||||
});
|
});
|
||||||
|
@ -222,18 +222,18 @@ public final class DomainLockUtils {
|
||||||
String domainName, String registrarId, @Nullable String registrarPocId, boolean isAdmin) {
|
String domainName, String registrarId, @Nullable String registrarPocId, boolean isAdmin) {
|
||||||
DateTime now = jpaTm().getTransactionTime();
|
DateTime now = jpaTm().getTransactionTime();
|
||||||
DomainBase domainBase = getDomain(domainName, registrarId, now);
|
DomainBase domainBase = getDomain(domainName, registrarId, now);
|
||||||
verifyDomainNotLocked(domainBase);
|
verifyDomainNotLocked(domainBase, isAdmin);
|
||||||
|
|
||||||
// Multiple pending actions are not allowed
|
// Multiple pending actions are not allowed for non-admins
|
||||||
RegistryLockDao.getMostRecentByRepoId(domainBase.getRepoId())
|
RegistryLockDao.getMostRecentByRepoId(domainBase.getRepoId())
|
||||||
.ifPresent(
|
.ifPresent(
|
||||||
previousLock ->
|
previousLock ->
|
||||||
checkArgument(
|
checkArgument(
|
||||||
previousLock.isLockRequestExpired(now)
|
previousLock.isLockRequestExpired(now)
|
||||||
|| previousLock.getUnlockCompletionTimestamp().isPresent(),
|
|| previousLock.getUnlockCompletionTimestamp().isPresent()
|
||||||
|
|| isAdmin,
|
||||||
"A pending or completed lock action already exists for %s",
|
"A pending or completed lock action already exists for %s",
|
||||||
previousLock.getDomainName()));
|
previousLock.getDomainName()));
|
||||||
|
|
||||||
return new RegistryLock.Builder()
|
return new RegistryLock.Builder()
|
||||||
.setVerificationCode(stringGenerator.createString(VERIFICATION_CODE_LENGTH))
|
.setVerificationCode(stringGenerator.createString(VERIFICATION_CODE_LENGTH))
|
||||||
.setDomainName(domainName)
|
.setDomainName(domainName)
|
||||||
|
@ -250,6 +250,8 @@ public final class DomainLockUtils {
|
||||||
Optional<RegistryLock> lockOptional =
|
Optional<RegistryLock> lockOptional =
|
||||||
RegistryLockDao.getMostRecentVerifiedLockByRepoId(domainBase.getRepoId());
|
RegistryLockDao.getMostRecentVerifiedLockByRepoId(domainBase.getRepoId());
|
||||||
|
|
||||||
|
verifyDomainLocked(domainBase, isAdmin);
|
||||||
|
|
||||||
RegistryLock.Builder newLockBuilder;
|
RegistryLock.Builder newLockBuilder;
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
// Admins should always be able to unlock domains in case we get in a bad state
|
// Admins should always be able to unlock domains in case we get in a bad state
|
||||||
|
@ -265,7 +267,6 @@ public final class DomainLockUtils {
|
||||||
.setLockCompletionTimestamp(now)
|
.setLockCompletionTimestamp(now)
|
||||||
.setRegistrarId(registrarId));
|
.setRegistrarId(registrarId));
|
||||||
} else {
|
} else {
|
||||||
verifyDomainLocked(domainBase);
|
|
||||||
RegistryLock lock =
|
RegistryLock lock =
|
||||||
lockOptional.orElseThrow(
|
lockOptional.orElseThrow(
|
||||||
() ->
|
() ->
|
||||||
|
@ -293,16 +294,17 @@ public final class DomainLockUtils {
|
||||||
.setRegistrarId(registrarId);
|
.setRegistrarId(registrarId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyDomainNotLocked(DomainBase domainBase) {
|
private static void verifyDomainNotLocked(DomainBase domainBase, boolean isAdmin) {
|
||||||
checkArgument(
|
checkArgument(
|
||||||
!domainBase.getStatusValues().containsAll(REGISTRY_LOCK_STATUSES),
|
isAdmin || !domainBase.getStatusValues().containsAll(REGISTRY_LOCK_STATUSES),
|
||||||
"Domain %s is already locked",
|
"Domain %s is already locked",
|
||||||
domainBase.getDomainName());
|
domainBase.getDomainName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyDomainLocked(DomainBase domainBase) {
|
private static void verifyDomainLocked(DomainBase domainBase, boolean isAdmin) {
|
||||||
checkArgument(
|
checkArgument(
|
||||||
!Sets.intersection(domainBase.getStatusValues(), REGISTRY_LOCK_STATUSES).isEmpty(),
|
isAdmin || !Sets.intersection(domainBase.getStatusValues(), REGISTRY_LOCK_STATUSES)
|
||||||
|
.isEmpty(),
|
||||||
"Domain %s is already unlocked",
|
"Domain %s is already unlocked",
|
||||||
domainBase.getDomainName());
|
domainBase.getDomainName());
|
||||||
}
|
}
|
||||||
|
@ -311,7 +313,7 @@ public final class DomainLockUtils {
|
||||||
DomainBase domain =
|
DomainBase domain =
|
||||||
loadByForeignKeyCached(DomainBase.class, domainName, now)
|
loadByForeignKeyCached(DomainBase.class, domainName, now)
|
||||||
.orElseThrow(
|
.orElseThrow(
|
||||||
() -> new IllegalArgumentException(String.format("Unknown domain %s", domainName)));
|
() -> new IllegalArgumentException("Domain doesn't exist"));
|
||||||
// The user must have specified either the correct registrar ID or the admin registrar ID
|
// The user must have specified either the correct registrar ID or the admin registrar ID
|
||||||
checkArgument(
|
checkArgument(
|
||||||
registryAdminRegistrarId.equals(registrarId)
|
registryAdminRegistrarId.equals(registrarId)
|
||||||
|
@ -330,9 +332,9 @@ public final class DomainLockUtils {
|
||||||
String.format("Invalid verification code %s", verificationCode)));
|
String.format("Invalid verification code %s", verificationCode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyLockStatuses(RegistryLock lock, DateTime lockTime) {
|
private void applyLockStatuses(RegistryLock lock, DateTime lockTime, boolean isAdmin) {
|
||||||
DomainBase domain = getDomain(lock.getDomainName(), lock.getRegistrarId(), lockTime);
|
DomainBase domain = getDomain(lock.getDomainName(), lock.getRegistrarId(), lockTime);
|
||||||
verifyDomainNotLocked(domain);
|
verifyDomainNotLocked(domain, isAdmin);
|
||||||
|
|
||||||
DomainBase newDomain =
|
DomainBase newDomain =
|
||||||
domain
|
domain
|
||||||
|
@ -345,9 +347,7 @@ public final class DomainLockUtils {
|
||||||
|
|
||||||
private void removeLockStatuses(RegistryLock lock, boolean isAdmin, DateTime unlockTime) {
|
private void removeLockStatuses(RegistryLock lock, boolean isAdmin, DateTime unlockTime) {
|
||||||
DomainBase domain = getDomain(lock.getDomainName(), lock.getRegistrarId(), unlockTime);
|
DomainBase domain = getDomain(lock.getDomainName(), lock.getRegistrarId(), unlockTime);
|
||||||
if (!isAdmin) {
|
verifyDomainLocked(domain, isAdmin);
|
||||||
verifyDomainLocked(domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
DomainBase newDomain =
|
DomainBase newDomain =
|
||||||
domain
|
domain
|
||||||
|
|
|
@ -14,15 +14,7 @@
|
||||||
|
|
||||||
package google.registry.tools;
|
package google.registry.tools;
|
||||||
|
|
||||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
|
||||||
|
|
||||||
import com.beust.jcommander.Parameters;
|
import com.beust.jcommander.Parameters;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
|
||||||
import google.registry.model.domain.DomainBase;
|
|
||||||
import google.registry.model.eppcommon.StatusValue;
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A command to registry lock domain names.
|
* A command to registry lock domain names.
|
||||||
|
@ -32,25 +24,6 @@ import org.joda.time.DateTime;
|
||||||
@Parameters(separators = " =", commandDescription = "Registry lock a domain via EPP.")
|
@Parameters(separators = " =", commandDescription = "Registry lock a domain via EPP.")
|
||||||
public class LockDomainCommand extends LockOrUnlockDomainCommand {
|
public class LockDomainCommand extends LockOrUnlockDomainCommand {
|
||||||
|
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldApplyToDomain(String domain, DateTime now) {
|
|
||||||
DomainBase domainBase =
|
|
||||||
loadByForeignKey(DomainBase.class, domain, now)
|
|
||||||
.orElseThrow(
|
|
||||||
() ->
|
|
||||||
new IllegalArgumentException(
|
|
||||||
String.format("Domain '%s' does not exist or is deleted", domain)));
|
|
||||||
ImmutableSet<StatusValue> statusesToAdd =
|
|
||||||
Sets.difference(REGISTRY_LOCK_STATUSES, domainBase.getStatusValues()).immutableCopy();
|
|
||||||
if (statusesToAdd.isEmpty()) {
|
|
||||||
logger.atInfo().log("Domain '%s' is already locked and needs no updates.", domain);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createAndApplyRequest(String domain) {
|
protected void createAndApplyRequest(String domain) {
|
||||||
domainLockUtils.administrativelyApplyLock(domain, clientId, null, true);
|
domainLockUtils.administrativelyApplyLock(domain, clientId, null, true);
|
||||||
|
|
|
@ -15,24 +15,28 @@
|
||||||
package google.registry.tools;
|
package google.registry.tools;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||||
import static com.google.common.collect.Iterables.partition;
|
import static com.google.common.collect.Iterables.partition;
|
||||||
import static google.registry.model.eppcommon.StatusValue.SERVER_DELETE_PROHIBITED;
|
import static google.registry.model.eppcommon.StatusValue.SERVER_DELETE_PROHIBITED;
|
||||||
import static google.registry.model.eppcommon.StatusValue.SERVER_TRANSFER_PROHIBITED;
|
import static google.registry.model.eppcommon.StatusValue.SERVER_TRANSFER_PROHIBITED;
|
||||||
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
|
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
|
||||||
|
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||||
import static google.registry.util.CollectionUtils.findDuplicates;
|
import static google.registry.util.CollectionUtils.findDuplicates;
|
||||||
|
|
||||||
import com.beust.jcommander.Parameter;
|
import com.beust.jcommander.Parameter;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
import google.registry.config.RegistryConfig.Config;
|
||||||
import google.registry.model.eppcommon.StatusValue;
|
import google.registry.model.eppcommon.StatusValue;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/** Shared base class for commands to registry lock or unlock a domain via EPP. */
|
/**
|
||||||
|
* Shared base class for commands to registry lock or unlock a domain via EPP.
|
||||||
|
*/
|
||||||
public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand
|
public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand
|
||||||
implements CommandWithRemoteApi {
|
implements CommandWithRemoteApi {
|
||||||
|
|
||||||
|
@ -57,7 +61,8 @@ public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand
|
||||||
@Config("registryAdminClientId")
|
@Config("registryAdminClientId")
|
||||||
String registryAdminClientId;
|
String registryAdminClientId;
|
||||||
|
|
||||||
@Inject DomainLockUtils domainLockUtils;
|
@Inject
|
||||||
|
DomainLockUtils domainLockUtils;
|
||||||
|
|
||||||
protected ImmutableSet<String> getDomains() {
|
protected ImmutableSet<String> getDomains() {
|
||||||
return ImmutableSet.copyOf(mainParameters);
|
return ImmutableSet.copyOf(mainParameters);
|
||||||
|
@ -78,37 +83,34 @@ public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand
|
||||||
@Override
|
@Override
|
||||||
protected String execute() {
|
protected String execute() {
|
||||||
ImmutableSet.Builder<String> successfulDomainsBuilder = new ImmutableSet.Builder<>();
|
ImmutableSet.Builder<String> successfulDomainsBuilder = new ImmutableSet.Builder<>();
|
||||||
ImmutableSet.Builder<String> skippedDomainsBuilder = new ImmutableSet.Builder<>();
|
ImmutableMap.Builder<String, String> failedDomainsToReasons = new ImmutableMap.Builder<>();
|
||||||
ImmutableSet.Builder<String> failedDomainsBuilder = new ImmutableSet.Builder<>();
|
|
||||||
partition(getDomains(), BATCH_SIZE)
|
partition(getDomains(), BATCH_SIZE)
|
||||||
.forEach(
|
.forEach(
|
||||||
batch ->
|
batch ->
|
||||||
tm().transact(
|
// we require that the jpaTm is the outer transaction in DomainLockUtils
|
||||||
|
jpaTm().transact(() -> tm().transact(
|
||||||
() -> {
|
() -> {
|
||||||
for (String domain : batch) {
|
for (String domain : batch) {
|
||||||
if (shouldApplyToDomain(domain, tm().getTransactionTime())) {
|
|
||||||
try {
|
try {
|
||||||
createAndApplyRequest(domain);
|
createAndApplyRequest(domain);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.atSevere().withCause(t).log(
|
logger.atSevere().withCause(t).log(
|
||||||
"Error when (un)locking domain %s.", domain);
|
"Error when (un)locking domain %s.", domain);
|
||||||
failedDomainsBuilder.add(domain);
|
failedDomainsToReasons.put(domain, t.getMessage());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
successfulDomainsBuilder.add(domain);
|
successfulDomainsBuilder.add(domain);
|
||||||
} else {
|
|
||||||
skippedDomainsBuilder.add(domain);
|
|
||||||
}
|
}
|
||||||
}
|
})));
|
||||||
}));
|
|
||||||
ImmutableSet<String> successfulDomains = successfulDomainsBuilder.build();
|
ImmutableSet<String> successfulDomains = successfulDomainsBuilder.build();
|
||||||
ImmutableSet<String> skippedDomains = skippedDomainsBuilder.build();
|
ImmutableSet<String> failedDomains = failedDomainsToReasons.build().entrySet()
|
||||||
ImmutableSet<String> failedDomains = failedDomainsBuilder.build();
|
.stream()
|
||||||
|
.map(entry -> String.format("%s (%s)", entry.getKey(), entry.getValue()))
|
||||||
|
.collect(toImmutableSet());
|
||||||
return String.format(
|
return String.format(
|
||||||
"Successfully locked/unlocked domains:\n%s\nSkipped domains:\n%s\nFailed domains:\n%s",
|
"Successfully locked/unlocked domains:\n%s\nFailed domains:\n%s",
|
||||||
successfulDomains, skippedDomains, failedDomains);
|
successfulDomains, failedDomains);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean shouldApplyToDomain(String domain, DateTime now);
|
|
||||||
|
|
||||||
protected abstract void createAndApplyRequest(String domain);
|
protected abstract void createAndApplyRequest(String domain);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,16 +14,8 @@
|
||||||
|
|
||||||
package google.registry.tools;
|
package google.registry.tools;
|
||||||
|
|
||||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
|
||||||
|
|
||||||
import com.beust.jcommander.Parameters;
|
import com.beust.jcommander.Parameters;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
|
||||||
import google.registry.model.domain.DomainBase;
|
|
||||||
import google.registry.model.eppcommon.StatusValue;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A command to registry unlock domain names.
|
* A command to registry unlock domain names.
|
||||||
|
@ -33,25 +25,6 @@ import org.joda.time.DateTime;
|
||||||
@Parameters(separators = " =", commandDescription = "Registry unlock a domain via EPP.")
|
@Parameters(separators = " =", commandDescription = "Registry unlock a domain via EPP.")
|
||||||
public class UnlockDomainCommand extends LockOrUnlockDomainCommand {
|
public class UnlockDomainCommand extends LockOrUnlockDomainCommand {
|
||||||
|
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldApplyToDomain(String domain, DateTime now) {
|
|
||||||
DomainBase domainBase =
|
|
||||||
loadByForeignKey(DomainBase.class, domain, now)
|
|
||||||
.orElseThrow(
|
|
||||||
() ->
|
|
||||||
new IllegalArgumentException(
|
|
||||||
String.format("Domain '%s' does not exist or is deleted", domain)));
|
|
||||||
ImmutableSet<StatusValue> statusesToRemove =
|
|
||||||
Sets.intersection(domainBase.getStatusValues(), REGISTRY_LOCK_STATUSES).immutableCopy();
|
|
||||||
if (statusesToRemove.isEmpty()) {
|
|
||||||
logger.atInfo().log("Domain '%s' is already unlocked and needs no updates.", domain);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createAndApplyRequest(String domain) {
|
protected void createAndApplyRequest(String domain) {
|
||||||
domainLockUtils.administrativelyApplyUnlock(domain, clientId, true, Optional.empty());
|
domainLockUtils.administrativelyApplyUnlock(domain, clientId, true, Optional.empty());
|
||||||
|
|
|
@ -49,6 +49,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.DatastoreHelper;
|
import google.registry.testing.DatastoreHelper;
|
||||||
import google.registry.testing.DeterministicStringGenerator;
|
import google.registry.testing.DeterministicStringGenerator;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
|
import google.registry.testing.SqlHelper;
|
||||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||||
import google.registry.testing.UserInfo;
|
import google.registry.testing.UserInfo;
|
||||||
import google.registry.util.AppEngineServiceUtils;
|
import google.registry.util.AppEngineServiceUtils;
|
||||||
|
@ -275,6 +276,37 @@ public final class DomainLockUtilsTest {
|
||||||
standardDays(6).plus(standardSeconds(30))));
|
standardDays(6).plus(standardSeconds(30))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSuccess_adminCanLockLockedDomain_withNoSavedLock() {
|
||||||
|
// in the case of inconsistencies / errors, admins should have the ability to override
|
||||||
|
// whatever statuses exist on the domain
|
||||||
|
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||||
|
RegistryLock resultLock = domainLockUtils
|
||||||
|
.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, true);
|
||||||
|
verifyProperlyLockedDomain(true);
|
||||||
|
assertThat(resultLock.getLockCompletionTimestamp()).isEqualTo(Optional.of(clock.nowUtc()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSuccess_adminCanLockUnlockedDomain_withSavedLock() {
|
||||||
|
// in the case of inconsistencies / errors, admins should have the ability to override
|
||||||
|
// what the RegistryLock table says
|
||||||
|
SqlHelper.saveRegistryLock(new RegistryLock.Builder()
|
||||||
|
.setLockCompletionTimestamp(clock.nowUtc())
|
||||||
|
.setDomainName(DOMAIN_NAME)
|
||||||
|
.setVerificationCode("hi")
|
||||||
|
.setRegistrarId("TheRegistrar")
|
||||||
|
.setRepoId(domain.getRepoId())
|
||||||
|
.isSuperuser(false)
|
||||||
|
.setRegistrarPocId(POC_ID)
|
||||||
|
.build());
|
||||||
|
clock.advanceOneMilli();
|
||||||
|
RegistryLock resultLock = domainLockUtils
|
||||||
|
.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, true);
|
||||||
|
verifyProperlyLockedDomain(true);
|
||||||
|
assertThat(resultLock.getLockCompletionTimestamp()).isEqualTo(Optional.of(clock.nowUtc()));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFailure_createUnlock_alreadyPendingUnlock() {
|
void testFailure_createUnlock_alreadyPendingUnlock() {
|
||||||
RegistryLock lock =
|
RegistryLock lock =
|
||||||
|
@ -317,7 +349,7 @@ public final class DomainLockUtilsTest {
|
||||||
domainLockUtils.saveNewRegistryLockRequest(
|
domainLockUtils.saveNewRegistryLockRequest(
|
||||||
"asdf.tld", "TheRegistrar", POC_ID, false)))
|
"asdf.tld", "TheRegistrar", POC_ID, false)))
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.isEqualTo("Unknown domain asdf.tld");
|
.isEqualTo("Domain doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -98,12 +98,9 @@ class LockDomainCommandTest extends CommandTestCase<LockDomainCommand> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFailure_domainDoesntExist() {
|
void testFailure_domainDoesntExist() throws Exception {
|
||||||
IllegalArgumentException e =
|
runCommandForced("--client=NewRegistrar", "missing.tld");
|
||||||
assertThrows(
|
assertInStdout("Failed domains:\n[missing.tld (Domain doesn't exist)]");
|
||||||
IllegalArgumentException.class,
|
|
||||||
() -> runCommandForced("--client=NewRegistrar", "missing.tld"));
|
|
||||||
assertThat(e).hasMessageThat().isEqualTo("Domain 'missing.tld' does not exist or is deleted");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -108,19 +108,16 @@ class UnlockDomainCommandTest extends CommandTestCase<UnlockDomainCommand> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFailure_domainDoesntExist() {
|
void testFailure_domainDoesntExist() throws Exception {
|
||||||
IllegalArgumentException e =
|
runCommandForced("--client=NewRegistrar", "missing.tld");
|
||||||
assertThrows(
|
assertInStdout("Failed domains:\n[missing.tld (Domain doesn't exist)]");
|
||||||
IllegalArgumentException.class,
|
|
||||||
() -> runCommandForced("--client=TheRegistrar", "missing.tld"));
|
|
||||||
assertThat(e).hasMessageThat().isEqualTo("Domain 'missing.tld' does not exist or is deleted");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_alreadyUnlockedDomain_performsNoAction() throws Exception {
|
void testSuccess_alreadyUnlockedDomain_staysUnlocked() throws Exception {
|
||||||
DomainBase domain = persistActiveDomain("example.tld");
|
DomainBase domain = persistActiveDomain("example.tld");
|
||||||
runCommandForced("--client=TheRegistrar", "example.tld");
|
runCommandForced("--client=TheRegistrar", "example.tld");
|
||||||
assertThat(reloadResource(domain)).isEqualTo(domain);
|
assertThat(reloadResource(domain).getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -358,7 +358,7 @@ public final class RegistryLockPostActionTest {
|
||||||
"domainName", "bad.tld",
|
"domainName", "bad.tld",
|
||||||
"isLock", true,
|
"isLock", true,
|
||||||
"password", "hi"));
|
"password", "hi"));
|
||||||
assertFailureWithMessage(response, "Unknown domain bad.tld");
|
assertFailureWithMessage(response, "Domain doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue