Skip to content

Commit 7f1f880

Browse files
committed
Add unique index for not-deleted domain names
This is a backstop against multiple domain creations for the same domain name getting through
1 parent ff4c326 commit 7f1f880

File tree

11 files changed

+85
-35
lines changed

11 files changed

+85
-35
lines changed

core/src/test/java/google/registry/model/OteStatsTestHelper.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,19 @@
1414

1515
package google.registry.model;
1616

17+
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
1718
import static google.registry.testing.DatabaseHelper.createTld;
1819
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
1920
import static google.registry.testing.DatabaseHelper.persistActiveHost;
20-
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
2121
import static google.registry.testing.DatabaseHelper.persistDeletedHost;
22+
import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted;
2223
import static google.registry.testing.DatabaseHelper.persistPremiumList;
2324
import static google.registry.testing.DatabaseHelper.persistResource;
2425
import static google.registry.testing.TestDataHelper.loadBytes;
2526
import static google.registry.util.DateTimeUtils.END_OF_TIME;
2627
import static org.joda.money.CurrencyUnit.USD;
2728

29+
import google.registry.model.domain.Domain;
2830
import google.registry.model.domain.DomainHistory;
2931
import google.registry.model.eppcommon.Trid;
3032
import google.registry.model.host.HostHistory;
@@ -49,7 +51,7 @@ public static void setupCompleteOte(String baseClientId) throws IOException {
4951
.build());
5052
persistResource(
5153
new DomainHistory.Builder()
52-
.setDomain(persistActiveDomain("example.tld"))
54+
.setDomain(persistActiveDomain("restored.tld"))
5355
.setRegistrarId(oteAccount1)
5456
.setType(Type.DOMAIN_RESTORE)
5557
.setXmlBytes(getBytes("domain_restore.xml"))
@@ -84,79 +86,80 @@ public static void setupIncompleteOte(String baseClientId) throws IOException {
8486
DateTime now = DateTime.now(DateTimeZone.UTC);
8587
persistResource(
8688
new DomainHistory.Builder()
87-
.setDomain(persistActiveDomain("exampleone.tld"))
89+
.setDomain(loadOrCreateDomain("exampleone.tld"))
8890
.setRegistrarId(oteAccount1)
8991
.setType(Type.DOMAIN_CREATE)
9092
.setXmlBytes(getBytes("domain_create_sunrise.xml"))
9193
.setModificationTime(now)
9294
.build());
9395
persistResource(
9496
new DomainHistory.Builder()
95-
.setDomain(persistActiveDomain("example-one.tld"))
97+
.setDomain(loadOrCreateDomain("example-one.tld"))
9698
.setRegistrarId(oteAccount1)
9799
.setType(Type.DOMAIN_CREATE)
98100
.setXmlBytes(getBytes("domain_create_claim_notice.xml"))
99101
.setModificationTime(now)
100102
.build());
103+
Domain exampleDomain = loadOrCreateDomain("example.tld");
101104
persistResource(
102105
new DomainHistory.Builder()
103-
.setDomain(persistActiveDomain("example.tld"))
106+
.setDomain(exampleDomain)
104107
.setRegistrarId(oteAccount1)
105108
.setType(Type.DOMAIN_CREATE)
106109
.setXmlBytes(getBytes("domain_create_anchor_tenant_fee_standard.xml"))
107110
.setModificationTime(now)
108111
.build());
109112
persistResource(
110113
new DomainHistory.Builder()
111-
.setDomain(persistActiveDomain("example.tld"))
114+
.setDomain(exampleDomain)
112115
.setRegistrarId(oteAccount1)
113116
.setType(Type.DOMAIN_CREATE)
114117
.setXmlBytes(getBytes("domain_create_dsdata.xml"))
115118
.setModificationTime(now)
116119
.build());
117120
persistResource(
118121
new DomainHistory.Builder()
119-
.setDomain(persistDeletedDomain("example.tld", now))
122+
.setDomain(persistDomainAsDeleted(loadOrCreateDomain("deleted.tld"), now))
120123
.setRegistrarId(oteAccount1)
121124
.setType(Type.DOMAIN_DELETE)
122125
.setXmlBytes(getBytes("domain_delete.xml"))
123126
.setModificationTime(now)
124127
.build());
125128
persistResource(
126129
new DomainHistory.Builder()
127-
.setDomain(persistActiveDomain("example.tld"))
130+
.setDomain(exampleDomain)
128131
.setRegistrarId(oteAccount1)
129132
.setType(Type.DOMAIN_TRANSFER_APPROVE)
130133
.setXmlBytes(getBytes("domain_transfer_approve.xml"))
131134
.setModificationTime(now)
132135
.build());
133136
persistResource(
134137
new DomainHistory.Builder()
135-
.setDomain(persistActiveDomain("example.tld"))
138+
.setDomain(exampleDomain)
136139
.setRegistrarId(oteAccount1)
137140
.setType(Type.DOMAIN_TRANSFER_CANCEL)
138141
.setXmlBytes(getBytes("domain_transfer_cancel.xml"))
139142
.setModificationTime(now)
140143
.build());
141144
persistResource(
142145
new DomainHistory.Builder()
143-
.setDomain(persistActiveDomain("example.tld"))
146+
.setDomain(exampleDomain)
144147
.setRegistrarId(oteAccount1)
145148
.setType(Type.DOMAIN_TRANSFER_REJECT)
146149
.setXmlBytes(getBytes("domain_transfer_reject.xml"))
147150
.setModificationTime(now)
148151
.build());
149152
persistResource(
150153
new DomainHistory.Builder()
151-
.setDomain(persistActiveDomain("example.tld"))
154+
.setDomain(exampleDomain)
152155
.setRegistrarId(oteAccount1)
153156
.setType(Type.DOMAIN_TRANSFER_REQUEST)
154157
.setXmlBytes(getBytes("domain_transfer_request.xml"))
155158
.setModificationTime(now)
156159
.build());
157160
persistResource(
158161
new DomainHistory.Builder()
159-
.setDomain(persistActiveDomain("example.tld"))
162+
.setDomain(exampleDomain)
160163
.setRegistrarId(oteAccount1)
161164
.setType(Type.DOMAIN_UPDATE)
162165
.setXmlBytes(getBytes("domain_update_with_secdns.xml"))
@@ -189,4 +192,12 @@ public static void setupIncompleteOte(String baseClientId) throws IOException {
189192
private static byte[] getBytes(String filename) throws IOException {
190193
return loadBytes(OteStatsTestHelper.class, filename).read();
191194
}
195+
196+
private static Domain loadOrCreateDomain(String domainName) {
197+
return tm().transact(
198+
() ->
199+
EppResourceUtils.loadByForeignKey(
200+
Domain.class, domainName, tm().getTransactionTime()))
201+
.orElseGet(() -> persistActiveDomain(domainName));
202+
}
192203
}

core/src/test/java/google/registry/rdap/RdapJsonFormatterTest.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,19 @@ void beforeEach() {
112112
hostNotLinked =
113113
makeAndPersistHost(
114114
"ns5.cat.みんな", null, null, clock.nowUtc().minusYears(5), "unicoderegistrar");
115+
// Create an unused domain that references hostBoth and hostNoAddresses so that
116+
// they will have "associated" (ie, StatusValue.LINKED) status.
117+
Domain dog =
118+
persistResource(
119+
makeDomain("dog.みんな", null, null, null, hostBoth, hostNoAddresses, registrar));
115120
hostSuperordinatePendingTransfer =
116121
persistResource(
117122
makeAndPersistHost(
118123
"ns1.dog.みんな", null, null, clock.nowUtc().minusYears(6), "unicoderegistrar")
119124
.asBuilder()
120125
.setSuperordinateDomain(
121126
persistResource(
122-
makeDomain("dog.みんな", null, null, null, null, null, registrar)
123-
.asBuilder()
127+
dog.asBuilder()
124128
.addStatusValue(StatusValue.PENDING_TRANSFER)
125129
.setTransferData(
126130
new DomainTransferData.Builder()
@@ -150,9 +154,6 @@ void beforeEach() {
150154
.setCreationTimeForTest(clock.nowUtc())
151155
.setLastEppUpdateTime(null)
152156
.build());
153-
// Create an unused domain that references hostBoth and hostNoAddresses so that
154-
// they will have "associated" (ie, StatusValue.LINKED) status.
155-
persistResource(makeDomain("dog.みんな", null, null, null, hostBoth, hostNoAddresses, registrar));
156157

157158
// history entries
158159
// We create 3 "transfer approved" entries, to make sure we only save the last one

core/src/test/java/google/registry/reporting/spec11/Spec11EmailUtilsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ void testSuccess_dealsWithDeletedDomains() throws Exception {
253253
// Create an inactive domain and an active domain with the same name.
254254
persistResource(loadByEntity(aDomain).asBuilder().addStatusValue(SERVER_HOLD).build());
255255
Host host = persistActiveHost("ns1.example.com");
256-
aDomain = persistDomainWithHost("a.com", host);
256+
aDomain = persistResource(aDomain.asBuilder().setNameservers(host.createVKey()).build());
257257

258258
emailUtils.emailSpec11Reports(
259259
date,

core/src/test/java/google/registry/tools/DeleteAllocationTokensCommandTest.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,14 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase<DeleteAllocation
4343
private AllocationToken preNot2;
4444
private AllocationToken othrRed;
4545
private AllocationToken othrNot;
46+
private Domain exampleDomain;
47+
private Domain foobarDomain;
4648

4749
@BeforeEach
4850
void beforeEach() {
4951
createTlds("foo", "bar");
52+
exampleDomain = persistActiveDomain("example.foo");
53+
foobarDomain = persistActiveDomain("foo.bar");
5054
preRed1 = persistToken("prefix12345AA", null, true);
5155
preRed2 = persistToken("prefixgh8907a", null, true);
5256
preNot1 = persistToken("prefix2978204", null, false);
@@ -97,8 +101,8 @@ void test_dryRun_deletesNothing() throws Exception {
97101

98102
@Test
99103
void test_defaultOptions_doesntDeletePerDomainTokens() throws Exception {
100-
AllocationToken preDom1 = persistToken("prefixasdfg897as", "foo.bar", false);
101-
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", "foo.bar", true);
104+
AllocationToken preDom1 = persistToken("prefixasdfg897as", foobarDomain, false);
105+
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", foobarDomain, true);
102106
runCommandForced("--prefix", "prefix");
103107
assertNonexistent(preNot1, preNot2);
104108
assertThat(reloadTokens(preRed1, preRed2, preDom1, preDom2, othrRed, othrNot))
@@ -107,8 +111,8 @@ void test_defaultOptions_doesntDeletePerDomainTokens() throws Exception {
107111

108112
@Test
109113
void test_withDomains_doesDeletePerDomainTokens() throws Exception {
110-
AllocationToken preDom1 = persistToken("prefixasdfg897as", "foo.bar", false);
111-
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", "foo.bar", true);
114+
AllocationToken preDom1 = persistToken("prefixasdfg897as", foobarDomain, false);
115+
AllocationToken preDom2 = persistToken("prefix98HAZXadbn", foobarDomain, true);
112116
runCommandForced("--prefix", "prefix", "--with_domains");
113117
assertNonexistent(preNot1, preNot2, preDom1);
114118
assertThat(reloadTokens(preRed1, preRed2, preDom2, othrRed, othrNot))
@@ -164,17 +168,15 @@ void testFailure_emptyPrefix() {
164168
assertThat(thrown).hasMessageThat().isEqualTo("Provided prefix should not be blank");
165169
}
166170

167-
private static AllocationToken persistToken(
168-
String token, @Nullable String domainName, boolean redeemed) {
171+
private AllocationToken persistToken(String token, @Nullable Domain domain, boolean redeemed) {
169172
AllocationToken.Builder builder =
170173
new AllocationToken.Builder()
171174
.setToken(token)
172175
.setTokenType(SINGLE_USE)
173-
.setDomainName(domainName);
176+
.setDomainName(domain == null ? null : domain.getDomainName());
174177
if (redeemed) {
175-
String domainToPersist = domainName != null ? domainName : "example.foo";
176-
Domain domain = persistActiveDomain(domainToPersist);
177-
HistoryEntryId historyEntryId = new HistoryEntryId(domain.getRepoId(), 1051L);
178+
String repoId = domain == null ? exampleDomain.getRepoId() : domain.getRepoId();
179+
HistoryEntryId historyEntryId = new HistoryEntryId(repoId, 1051L);
178180
builder.setRedemptionHistoryId(historyEntryId);
179181
}
180182
return persistResource(builder.build());

core/src/test/resources/google/registry/rdap/rdapjson_host_pending_transfer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"objectClassName" : "nameserver",
3-
"handle" : "C-ROID",
3+
"handle" : "D-ROID",
44
"ldhName" : "ns1.dog.xn--q9jyb4c",
55
"unicodeName" : "ns1.dog.みんな",
66
"status" : ["active", "pending transfer"],
-44 KB
Loading

db/src/main/resources/sql/er_diagram/brief_er_diagram.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,19 +261,19 @@ <h2>System Information</h2>
261261
</tr>
262262
<tr>
263263
<td class="property_name">generated on</td>
264-
<td class="property_value">2025-10-10 17:24:50</td>
264+
<td class="property_value">2025-10-23 21:01:05</td>
265265
</tr>
266266
<tr>
267267
<td class="property_name">last flyway file</td>
268-
<td id="lastFlywayFile" class="property_value">V213__graceperiodhistory_history_revision_id_hash.sql</td>
268+
<td id="lastFlywayFile" class="property_value">V214__domain_unique_domain_name_active.sql</td>
269269
</tr>
270270
</tbody>
271271
</table>
272272
<p>&nbsp;</p>
273273
<p>&nbsp;</p>
274274
<svg viewBox="0.00 0.00 4903.00 3732.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="erDiagram" style="overflow: hidden; width: 100%; height: 800px">
275275
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 3728)">
276-
<title>SchemaCrawler_Diagram</title> <polygon fill="white" stroke="transparent" points="-4,4 -4,-3728 4899,-3728 4899,4 -4,4" /> <text text-anchor="start" x="4655" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">generated by</text> <text text-anchor="start" x="4738" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">SchemaCrawler 16.27.1</text> <text text-anchor="start" x="4654" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">generated on</text> <text text-anchor="start" x="4738" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">2025-10-10 17:24:50</text> <polygon fill="none" stroke="#888888" points="4651,-4 4651,-44 4887,-44 4887,-4 4651,-4" /> <!-- allocationtoken_a08ccbef -->
276+
<title>SchemaCrawler_Diagram</title> <polygon fill="white" stroke="transparent" points="-4,4 -4,-3728 4899,-3728 4899,4 -4,4" /> <text text-anchor="start" x="4655" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">generated by</text> <text text-anchor="start" x="4738" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">SchemaCrawler 16.27.1</text> <text text-anchor="start" x="4654" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">generated on</text> <text text-anchor="start" x="4738" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">2025-10-23 21:01:05</text> <polygon fill="none" stroke="#888888" points="4651,-4 4651,-44 4887,-44 4887,-4 4651,-4" /> <!-- allocationtoken_a08ccbef -->
277277
<g id="node1" class="node">
278278
<title>allocationtoken_a08ccbef</title> <polygon fill="#e9c2f2" stroke="transparent" points="481.5,-978 481.5,-997 667.5,-997 667.5,-978 481.5,-978" /> <text text-anchor="start" x="483.5" y="-984.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">public."AllocationToken"</text> <polygon fill="#e9c2f2" stroke="transparent" points="667.5,-978 667.5,-997 741.5,-997 741.5,-978 667.5,-978" /> <text text-anchor="start" x="702.5" y="-983.8" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text> <text text-anchor="start" x="483.5" y="-965.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">token</text> <text text-anchor="start" x="661.5" y="-964.8" font-family="Helvetica,sans-Serif" font-size="14.00"> </text> <text text-anchor="start" x="669.5" y="-964.8" font-family="Helvetica,sans-Serif" font-size="14.00">text not null</text> <text text-anchor="start" x="483.5" y="-945.8" font-family="Helvetica,sans-Serif" font-size="14.00">domain_name</text> <text text-anchor="start" x="661.5" y="-945.8" font-family="Helvetica,sans-Serif" font-size="14.00"> </text> <text text-anchor="start" x="669.5" y="-945.8" font-family="Helvetica,sans-Serif" font-size="14.00">text</text> <text text-anchor="start" x="483.5" y="-926.8" font-family="Helvetica,sans-Serif" font-size="14.00">redemption_domain_repo_id</text> <text text-anchor="start" x="661.5" y="-926.8" font-family="Helvetica,sans-Serif" font-size="14.00"> </text> <text text-anchor="start" x="669.5" y="-926.8" font-family="Helvetica,sans-Serif" font-size="14.00">text</text> <text text-anchor="start" x="483.5" y="-907.8" font-family="Helvetica,sans-Serif" font-size="14.00">token_type</text> <text text-anchor="start" x="661.5" y="-907.8" font-family="Helvetica,sans-Serif" font-size="14.00"> </text> <text text-anchor="start" x="669.5" y="-907.8" font-family="Helvetica,sans-Serif" font-size="14.00">text</text> <polygon fill="none" stroke="#888888" points="480.5,-901.5 480.5,-998.5 742.5,-998.5 742.5,-901.5 480.5,-901.5" />
279279
</g>

0 commit comments

Comments
 (0)