mirror of
https://github.com/google/nomulus.git
synced 2025-07-06 19:23:31 +02:00
Add a nomulus tool command to enqueue a poll message (#1441)
* Add a nomulus tool command to enqueue a poll message
This commit is contained in:
parent
9275a4f078
commit
18d051ef87
5 changed files with 235 additions and 2 deletions
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.SYNTHETIC;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Tool to enqueue a poll message for a registrar.
|
||||
*
|
||||
* <p>The poll message in question must correspond to an existing domain owing to schema
|
||||
* limitations, but does not necessarily need to correspond to the owner of that domain if an
|
||||
* alternative <code>clientId</code> is provided.
|
||||
*
|
||||
* <p>If general broadcast messages are being sent to registrars (e.g. a notice of an upcoming
|
||||
* maintenance window), then it is recommended to use a well-known registry-owned domain for the
|
||||
* enqueueing of these poll messages, such as the nic domain.
|
||||
*/
|
||||
@Parameters(separators = " =", commandDescription = "Enqueue a poll message for a domain")
|
||||
class EnqueuePollMessageCommand extends MutatingCommand {
|
||||
|
||||
@Parameter(
|
||||
names = {"-m", "--message"},
|
||||
description = "The poll message to enqueue",
|
||||
required = true)
|
||||
String message;
|
||||
|
||||
@Parameter(
|
||||
names = {"-d", "--domain"},
|
||||
description = "The domain name to enqueue the poll message for",
|
||||
required = true)
|
||||
String domainName;
|
||||
|
||||
@Parameter(
|
||||
names = {"-c", "--client"},
|
||||
description =
|
||||
"Client identifier of the registrar to send the poll message to, if not the owning"
|
||||
+ " registrar of the domain")
|
||||
String clientId;
|
||||
|
||||
@Override
|
||||
protected final void init() {
|
||||
tm().transact(
|
||||
() -> {
|
||||
Optional<DomainBase> domainOpt =
|
||||
loadByForeignKey(DomainBase.class, domainName, tm().getTransactionTime());
|
||||
checkArgument(
|
||||
domainOpt.isPresent(), "Domain %s doesn't exist or isn't active", domainName);
|
||||
DomainBase domain = domainOpt.get();
|
||||
String registrarId =
|
||||
Optional.ofNullable(clientId).orElse(domain.getCurrentSponsorRegistrarId());
|
||||
HistoryEntry historyEntry =
|
||||
new DomainHistory.Builder()
|
||||
.setDomain(domain)
|
||||
.setType(SYNTHETIC)
|
||||
.setBySuperuser(true)
|
||||
.setReason("Manual enqueueing of poll message")
|
||||
.setModificationTime(tm().getTransactionTime())
|
||||
.setRequestedByRegistrar(false)
|
||||
.setRegistrarId(registrarId)
|
||||
.build();
|
||||
PollMessage.OneTime pollMessage =
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(registrarId)
|
||||
.setParent(historyEntry)
|
||||
.setEventTime(tm().getTransactionTime())
|
||||
.setMsg(message)
|
||||
.build();
|
||||
stageEntityChange(null, historyEntry);
|
||||
stageEntityChange(null, pollMessage);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -103,7 +103,8 @@ public abstract class MutatingCommand extends ConfirmingCommand implements Comma
|
|||
* workaround to handle cases when a SqlEntity instance does not have a primary key before being
|
||||
* persisted.
|
||||
*/
|
||||
private EntityChange(ImmutableObject oldEntity, ImmutableObject newEntity, VKey<?> vkey) {
|
||||
private EntityChange(
|
||||
@Nullable ImmutableObject oldEntity, @Nullable ImmutableObject newEntity, VKey<?> vkey) {
|
||||
type = ChangeType.get(oldEntity != null, newEntity != null);
|
||||
if (type == ChangeType.UPDATE) {
|
||||
checkArgument(
|
||||
|
@ -127,7 +128,7 @@ public abstract class MutatingCommand extends ConfirmingCommand implements Comma
|
|||
}
|
||||
|
||||
/** Returns a human-readable ID string for the entity being changed. */
|
||||
public String getEntityId() {
|
||||
String getEntityId() {
|
||||
return String.format(
|
||||
"%s@%s",
|
||||
key.getOfyKey().getKind(),
|
||||
|
|
|
@ -62,6 +62,7 @@ public final class RegistryTool {
|
|||
.put("delete_reserved_list", DeleteReservedListCommand.class)
|
||||
.put("delete_tld", DeleteTldCommand.class)
|
||||
.put("encrypt_escrow_deposit", EncryptEscrowDepositCommand.class)
|
||||
.put("enqueue_poll_message", EnqueuePollMessageCommand.class)
|
||||
.put("execute_epp", ExecuteEppCommand.class)
|
||||
.put("generate_allocation_tokens", GenerateAllocationTokensCommand.class)
|
||||
.put("generate_dns_report", GenerateDnsReportCommand.class)
|
||||
|
|
|
@ -111,6 +111,8 @@ interface RegistryToolComponent {
|
|||
|
||||
void inject(EncryptEscrowDepositCommand command);
|
||||
|
||||
void inject(EnqueuePollMessageCommand command);
|
||||
|
||||
void inject(GenerateAllocationTokensCommand command);
|
||||
|
||||
void inject(GenerateDnsReportCommand command);
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
// Copyright 2021 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.SYNTHETIC;
|
||||
import static google.registry.testing.DatabaseHelper.assertPollMessages;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.InjectExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link EnqueuePollMessageCommand}. */
|
||||
@DualDatabaseTest
|
||||
class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCommand> {
|
||||
|
||||
@RegisterExtension final InjectExtension inject = new InjectExtension();
|
||||
|
||||
private DomainBase domain;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
createTld("tld");
|
||||
inject.setStaticField(Ofy.class, "clock", fakeClock);
|
||||
domain = persistActiveDomain("example.tld");
|
||||
fakeClock.advanceOneMilli();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_domainAndMessage() throws Exception {
|
||||
runCommandForced("--domain=example.tld", "--message=This domain is bad");
|
||||
|
||||
HistoryEntry synthetic = getOnlyHistoryEntryOfType(domain, SYNTHETIC);
|
||||
assertAboutHistoryEntries()
|
||||
.that(synthetic)
|
||||
.bySuperuser(true)
|
||||
.and()
|
||||
.hasMetadataReason("Manual enqueueing of poll message")
|
||||
.and()
|
||||
.hasNoXml()
|
||||
.and()
|
||||
.hasRegistrarId("TheRegistrar")
|
||||
.and()
|
||||
.hasModificationTime(fakeClock.nowUtc())
|
||||
.and()
|
||||
.hasMetadataRequestedByRegistrar(false);
|
||||
assertPollMessages(
|
||||
"TheRegistrar",
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setParent(synthetic)
|
||||
.setMsg("This domain is bad")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_specifyClientId() throws Exception {
|
||||
runCommandForced(
|
||||
"--domain=example.tld", "--message=This domain needs work", "--client=NewRegistrar");
|
||||
|
||||
HistoryEntry synthetic = getOnlyHistoryEntryOfType(domain, SYNTHETIC);
|
||||
assertAboutHistoryEntries()
|
||||
.that(synthetic)
|
||||
.bySuperuser(true)
|
||||
.and()
|
||||
.hasMetadataReason("Manual enqueueing of poll message")
|
||||
.and()
|
||||
.hasNoXml()
|
||||
.and()
|
||||
.hasRegistrarId("NewRegistrar")
|
||||
.and()
|
||||
.hasModificationTime(fakeClock.nowUtc())
|
||||
.and()
|
||||
.hasMetadataRequestedByRegistrar(false);
|
||||
assertPollMessages(
|
||||
"NewRegistrar",
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setParent(synthetic)
|
||||
.setMsg("This domain needs work")
|
||||
.setRegistrarId("NewRegistrar")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testNonexistentDomain() throws Exception {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--domain=example2.tld", "--message=This domain needs help"));
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Domain example2.tld doesn't exist or isn't active");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testDomainIsRequired() {
|
||||
ParameterException thrown =
|
||||
assertThrows(ParameterException.class, () -> runCommandForced("--message=Foo bar"));
|
||||
assertThat(thrown).hasMessageThat().contains("The following option is required: -d, --domain");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testMessageIsRequired() {
|
||||
ParameterException thrown =
|
||||
assertThrows(ParameterException.class, () -> runCommandForced("--domain=example.tld"));
|
||||
assertThat(thrown).hasMessageThat().contains("The following option is required: -m, --message");
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue