diff --git a/core/src/main/java/google/registry/model/OteStats.java b/core/src/main/java/google/registry/model/OteStats.java index 9da0070afb4..e2512743047 100644 --- a/core/src/main/java/google/registry/model/OteStats.java +++ b/core/src/main/java/google/registry/model/OteStats.java @@ -176,11 +176,12 @@ public String getDescription() { * Check if the {@link HistoryEntry} type matches as well as the {@link EppInput} if supplied. */ private boolean matches(HistoryEntry.Type historyType, Optional eppInput) { - if (eppInputFilter.isPresent() && eppInput.isPresent()) { - return typeFilter.test(historyType) && eppInputFilter.get().test(eppInput.get()); - } else { - return typeFilter.test(historyType); + if (!typeFilter.test(historyType)) { + return false; } + return eppInputFilter + .map(filter -> eppInput.isPresent() && filter.test(eppInput.get())) + .orElse(true); } } diff --git a/core/src/test/java/google/registry/model/OteStatsTest.java b/core/src/test/java/google/registry/model/OteStatsTest.java index becf63600fa..8c2fb2167fa 100644 --- a/core/src/test/java/google/registry/model/OteStatsTest.java +++ b/core/src/test/java/google/registry/model/OteStatsTest.java @@ -16,10 +16,17 @@ import static com.google.common.truth.Truth.assertThat; import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.persistActiveDomain; +import static google.registry.testing.DatabaseHelper.persistPremiumList; +import static google.registry.testing.DatabaseHelper.persistResource; +import static org.joda.money.CurrencyUnit.USD; import google.registry.model.OteStats.StatType; +import google.registry.model.domain.DomainHistory; +import google.registry.model.reporting.HistoryEntry.Type; import google.registry.persistence.transaction.JpaTestExtensions; import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension; +import java.time.Instant; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -60,39 +67,40 @@ void testSuccess_toString() throws Exception { OteStats stats = OteStats.getFromRegistrar("blobio"); String expected = """ - contact creates: 0 - contact deletes: 0 - contact transfer approves: 0 - contact transfer cancels: 0 - contact transfer rejects: 0 - contact transfer requests: 0 - contact updates: 0 - domain autorenews: 0 - domain creates: 5 - domain creates ascii: 4 - domain creates idn: 1 - domain creates start date sunrise: 1 - domain creates with claims notice: 1 - domain creates with fee: 1 - domain creates with sec dns: 1 - domain creates without sec dns: 4 - domain deletes: 1 - domain renews: 0 - domain restores: 1 - domain transfer approves: 1 - domain transfer cancels: 1 - domain transfer rejects: 1 - domain transfer requests: 1 - domain updates: 1 - domain updates with sec dns: 1 - domain updates without sec dns: 0 - host creates: 1 - host creates external: 0 - host creates subordinate: 1 - host deletes: 1 - host updates: 1 - unclassified flows: 0 - TOTAL: 30"""; + contact creates: 0 + contact deletes: 0 + contact transfer approves: 0 + contact transfer cancels: 0 + contact transfer rejects: 0 + contact transfer requests: 0 + contact updates: 0 + domain autorenews: 0 + domain creates: 5 + domain creates ascii: 4 + domain creates idn: 1 + domain creates start date sunrise: 1 + domain creates with claims notice: 1 + domain creates with fee: 1 + domain creates with sec dns: 1 + domain creates without sec dns: 4 + domain deletes: 1 + domain renews: 0 + domain restores: 1 + domain transfer approves: 1 + domain transfer cancels: 1 + domain transfer rejects: 1 + domain transfer requests: 1 + domain updates: 1 + domain updates with sec dns: 1 + domain updates without sec dns: 0 + host creates: 1 + host creates external: 0 + host creates subordinate: 1 + host deletes: 1 + host updates: 1 + unclassified flows: 0 + TOTAL: 30\ + """; assertThat(stats.toString()).isEqualTo(expected); } @@ -102,39 +110,72 @@ void testIncomplete_toString() throws Exception { OteStats stats = OteStats.getFromRegistrar("blobio"); String expected = """ - contact creates: 0 - contact deletes: 0 - contact transfer approves: 0 - contact transfer cancels: 0 - contact transfer rejects: 0 - contact transfer requests: 0 - contact updates: 0 - domain autorenews: 0 - domain creates: 4 - domain creates ascii: 4 - domain creates idn: 0 - domain creates start date sunrise: 1 - domain creates with claims notice: 1 - domain creates with fee: 1 - domain creates with sec dns: 1 - domain creates without sec dns: 3 - domain deletes: 1 - domain renews: 0 - domain restores: 0 - domain transfer approves: 1 - domain transfer cancels: 1 - domain transfer rejects: 1 - domain transfer requests: 1 - domain updates: 1 - domain updates with sec dns: 1 - domain updates without sec dns: 0 - host creates: 1 - host creates external: 0 - host creates subordinate: 1 - host deletes: 0 - host updates: 10 - unclassified flows: 0 - TOTAL: 34"""; + contact creates: 0 + contact deletes: 0 + contact transfer approves: 0 + contact transfer cancels: 0 + contact transfer rejects: 0 + contact transfer requests: 0 + contact updates: 0 + domain autorenews: 0 + domain creates: 4 + domain creates ascii: 4 + domain creates idn: 0 + domain creates start date sunrise: 1 + domain creates with claims notice: 1 + domain creates with fee: 1 + domain creates with sec dns: 1 + domain creates without sec dns: 3 + domain deletes: 1 + domain renews: 0 + domain restores: 0 + domain transfer approves: 1 + domain transfer cancels: 1 + domain transfer rejects: 1 + domain transfer requests: 1 + domain updates: 1 + domain updates with sec dns: 1 + domain updates without sec dns: 0 + host creates: 1 + host creates external: 0 + host creates subordinate: 1 + host deletes: 0 + host updates: 10 + unclassified flows: 0 + TOTAL: 34\ + """; assertThat(stats.toString()).isEqualTo(expected); } + + @Test + void testDomainCreateWithoutXmlBytes_doesNotSatisfyComplexRequirements() throws Exception { + persistPremiumList("default_sandbox_list", USD, "sandbox,USD 1000"); + OteAccountBuilder.forRegistrarId("blobio").buildAndPersist(); + String oteAccount1 = "blobio-1"; + Instant now = Instant.parse("2026-06-25T10:00:00Z"); + + // Persist a DOMAIN_CREATE history entry without XML bytes + persistResource( + new DomainHistory.Builder() + .setDomain(persistActiveDomain("example.tld")) + .setRegistrarId(oteAccount1) + .setType(Type.DOMAIN_CREATE) + .setXmlBytes(null) // explicitly null + .setModificationTime(now) + .build()); + + OteStats stats = OteStats.getFromRegistrar("blobio"); + + // It should count towards the basic DOMAIN_CREATES + assertThat(stats.getCount(StatType.DOMAIN_CREATES)).isEqualTo(1); + + // It should NOT count towards any stat type that requires EPP input filtering + assertThat(stats.getCount(StatType.DOMAIN_CREATES_ASCII)).isEqualTo(0); + assertThat(stats.getCount(StatType.DOMAIN_CREATES_IDN)).isEqualTo(0); + assertThat(stats.getCount(StatType.DOMAIN_CREATES_START_DATE_SUNRISE)).isEqualTo(0); + assertThat(stats.getCount(StatType.DOMAIN_CREATES_WITH_CLAIMS_NOTICE)).isEqualTo(0); + assertThat(stats.getCount(StatType.DOMAIN_CREATES_WITH_FEE)).isEqualTo(0); + assertThat(stats.getCount(StatType.DOMAIN_CREATES_WITH_SEC_DNS)).isEqualTo(0); + assertThat(stats.getCount(StatType.DOMAIN_CREATES_WITHOUT_SEC_DNS)).isEqualTo(0); + } }