mirror of
https://github.com/google/nomulus.git
synced 2025-06-11 15:04:46 +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
|
@ -49,6 +49,7 @@ import google.registry.testing.AppEngineRule;
|
|||
import google.registry.testing.DatastoreHelper;
|
||||
import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.SqlHelper;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.testing.UserInfo;
|
||||
import google.registry.util.AppEngineServiceUtils;
|
||||
|
@ -275,6 +276,37 @@ public final class DomainLockUtilsTest {
|
|||
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
|
||||
void testFailure_createUnlock_alreadyPendingUnlock() {
|
||||
RegistryLock lock =
|
||||
|
@ -317,7 +349,7 @@ public final class DomainLockUtilsTest {
|
|||
domainLockUtils.saveNewRegistryLockRequest(
|
||||
"asdf.tld", "TheRegistrar", POC_ID, false)))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Unknown domain asdf.tld");
|
||||
.isEqualTo("Domain doesn't exist");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -98,12 +98,9 @@ class LockDomainCommandTest extends CommandTestCase<LockDomainCommand> {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testFailure_domainDoesntExist() {
|
||||
IllegalArgumentException e =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--client=NewRegistrar", "missing.tld"));
|
||||
assertThat(e).hasMessageThat().isEqualTo("Domain 'missing.tld' does not exist or is deleted");
|
||||
void testFailure_domainDoesntExist() throws Exception {
|
||||
runCommandForced("--client=NewRegistrar", "missing.tld");
|
||||
assertInStdout("Failed domains:\n[missing.tld (Domain doesn't exist)]");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -108,19 +108,16 @@ class UnlockDomainCommandTest extends CommandTestCase<UnlockDomainCommand> {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testFailure_domainDoesntExist() {
|
||||
IllegalArgumentException e =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--client=TheRegistrar", "missing.tld"));
|
||||
assertThat(e).hasMessageThat().isEqualTo("Domain 'missing.tld' does not exist or is deleted");
|
||||
void testFailure_domainDoesntExist() throws Exception {
|
||||
runCommandForced("--client=NewRegistrar", "missing.tld");
|
||||
assertInStdout("Failed domains:\n[missing.tld (Domain doesn't exist)]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_alreadyUnlockedDomain_performsNoAction() throws Exception {
|
||||
void testSuccess_alreadyUnlockedDomain_staysUnlocked() throws Exception {
|
||||
DomainBase domain = persistActiveDomain("example.tld");
|
||||
runCommandForced("--client=TheRegistrar", "example.tld");
|
||||
assertThat(reloadResource(domain)).isEqualTo(domain);
|
||||
assertThat(reloadResource(domain).getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -358,7 +358,7 @@ public final class RegistryLockPostActionTest {
|
|||
"domainName", "bad.tld",
|
||||
"isLock", true,
|
||||
"password", "hi"));
|
||||
assertFailureWithMessage(response, "Unknown domain bad.tld");
|
||||
assertFailureWithMessage(response, "Domain doesn't exist");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue