diff --git a/java/google/registry/ui/css/admin-settings.css b/java/google/registry/ui/css/admin-settings.css index 52df054af..2b6f04207 100644 --- a/java/google/registry/ui/css/admin-settings.css +++ b/java/google/registry/ui/css/admin-settings.css @@ -56,3 +56,29 @@ div#tlds.editing .kd-errormessage { margin-left: 0.5em; } +#ote-results-table { + margin-left: 0.5em; + margin-top: -5px; + border-top: 0; + padding-top: 0; +} + +.ote-fulfilled { + background-color: #9df797; +} + +.ote-semifulfilled { + background-color: #fcd18e; +} + +.ote-unfulfilled { + background-color: #ffa9a9; +} + +.ote-results-header { + height: 20px; +} + +.ote-results-header-cell { + vertical-align: bottom; +} diff --git a/java/google/registry/ui/css/registrar_imports_raw.css b/java/google/registry/ui/css/registrar_imports_raw.css index 8bb831cc7..3b1b547ca 100644 --- a/java/google/registry/ui/css/registrar_imports_raw.css +++ b/java/google/registry/ui/css/registrar_imports_raw.css @@ -1,10 +1,11 @@ -@import 'kd_components.css'; -@import 'registry.css'; +@import 'admin-settings.css'; @import 'console.css'; -@import 'forms.css'; -@import 'epp.css'; -@import 'dashboard.css'; -@import 'resources.css'; -@import 'security-settings.css'; @import 'contact-settings.css'; @import 'contact-us.css'; +@import 'dashboard.css'; +@import 'epp.css'; +@import 'forms.css'; +@import 'kd_components.css'; +@import 'registry.css'; +@import 'resources.css'; +@import 'security-settings.css'; diff --git a/java/google/registry/ui/externs/json.js b/java/google/registry/ui/externs/json.js index a1203d781..d429ec64a 100644 --- a/java/google/registry/ui/externs/json.js +++ b/java/google/registry/ui/externs/json.js @@ -34,12 +34,25 @@ registry.json.ote = {}; /** * @typedef {{ - * clientId: string, + * description: string, + * requirement: number, + * timesPerformed: number, * completed: boolean * }} */ +registry.json.ote.OteStatusDetail; + + +/** + * @typedef {{ + * clientId: string, + * completed: boolean, + * details: !Array. + * }} + */ registry.json.ote.OteStatusResult; + /** * @typedef {{ * status: string, diff --git a/java/google/registry/ui/js/registrar/admin_settings.js b/java/google/registry/ui/js/registrar/admin_settings.js index 4955a3788..bc26e102d 100644 --- a/java/google/registry/ui/js/registrar/admin_settings.js +++ b/java/google/registry/ui/js/registrar/admin_settings.js @@ -102,20 +102,17 @@ registry.registrar.AdminSettings.prototype.oteStatusCheck_ = function( /** @type {!registry.json.ote.OteStatusResponse} */ (e.target.getResponseJson( registry.registrar.AdminSettings.PARSER_BREAKER_)); - var message; + var oteResultParent = goog.dom.getRequiredElement('ote-status-area-parent'); if (response.status === 'SUCCESS') { var results = response.results[0]; - message = 'Passed: '.concat(results.completed); + goog.soy.renderElement( + oteResultParent, registry.soy.registrar.admin.oteResultsTable, + {completed: results.completed, detailsList: results.details}); } else { - message = 'Error: '.concat(response.message); + goog.soy.renderElement( + oteResultParent, registry.soy.registrar.admin.oteErrorArea, + {message: response.message}); } - var textParent = goog.dom.getRequiredElement('ote-status-area-parent'); - if (!textParent.hasChildNodes()) { - var textElement = document.createElement('p'); - textElement.id = 'ote-status-area'; - textParent.appendChild(textElement); - } - textParent.firstElementChild.textContent = message; }, 'POST', goog.json.serialize({'clientId': clientId}), { 'X-CSRF-Token': xsrfToken, 'Content-Type': 'application/json; charset=UTF-8' diff --git a/java/google/registry/ui/soy/registrar/AdminSettings.soy b/java/google/registry/ui/soy/registrar/AdminSettings.soy index b9643b079..1a1c43541 100644 --- a/java/google/registry/ui/soy/registrar/AdminSettings.soy +++ b/java/google/registry/ui/soy/registrar/AdminSettings.soy @@ -17,6 +17,7 @@ /** Registrar admin settings page for view and edit. */ {template .settings} {@param allowedTlds: list} + {@param type: string} // the registrar type, e.g. REAL, OTE, TEST, etc.

Administrator settings

@@ -48,7 +49,9 @@

Generate new OT&E accounts here

- {call .oteStatus /} + {call .oteStatus} + {param registrarType: $type /} + {/call}
{/template} @@ -67,15 +70,63 @@ {/template} {template .oteStatus} + {@param registrarType: string} {/template} + +{template .oteResultsTable} + {@param completed: bool} + {@param detailsList: list<[description: string, timesPerformed: int, requirement: int, completed: bool]>} + + {if $completed} + + + + + {else} + + + + + {/if} + + + + + {for $detail in $detailsList} + {if $detail.completed} + + + + + {elseif $detail.timesPerformed > 0} + + + + + {else} + + + + + {/if} + {/for} +
Status:Completed
Status:Not Completed
Test NameActions Performed
{$detail.description}Completed
{$detail.description}{$detail.timesPerformed} of {$detail.requirement}
{$detail.description}Not started
+{/template} + +{template .oteErrorArea} + {@param message: string} +

Error: {$message}

+{/template} diff --git a/javatests/google/registry/model/OteStatsTest.java b/javatests/google/registry/model/OteStatsTest.java index f8e84df71..a4777e131 100644 --- a/javatests/google/registry/model/OteStatsTest.java +++ b/javatests/google/registry/model/OteStatsTest.java @@ -18,7 +18,6 @@ import static com.google.common.truth.Truth.assertThat; import google.registry.model.OteStats.StatType; import google.registry.testing.AppEngineRule; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,23 +28,17 @@ public final class OteStatsTest { @Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build(); - @Before - public void init() throws Exception { - OteStatsTestHelper.setupHistoryEntries("blobio"); - } - @Test - public void testSuccess_allPass() { + public void testSuccess_allPass() throws Exception { + OteStatsTestHelper.setupCompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); assertThat(stats.getFailures()).isEmpty(); assertThat(stats.getSize()).isEqualTo(30); } @Test - public void testSuccess_someFailures() { - OteStatsTestHelper.deleteHostDeleteHistoryEntry(); - OteStatsTestHelper.deleteDomainCreateHistoryEntry(); - OteStatsTestHelper.deleteDomainRestoreHistoryEntry(); + public void testSuccess_incomplete() throws Exception { + OteStatsTestHelper.setupIncompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); assertThat(stats.getFailures()) .containsExactly( @@ -55,7 +48,8 @@ public final class OteStatsTest { } @Test - public void testSuccess_toString() { + public void testSuccess_toString() throws Exception { + OteStatsTestHelper.setupCompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); String expected = "contact creates: 0\n" @@ -95,8 +89,8 @@ public final class OteStatsTest { } @Test - public void testMissingHostDeletes_toString() { - OteStatsTestHelper.deleteHostDeleteHistoryEntry(); + public void testIncomplete_toString() throws Exception { + OteStatsTestHelper.setupIncompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); String expected = "contact creates: 0\n" @@ -107,17 +101,17 @@ public final class OteStatsTest { + "contact transfer requests: 0\n" + "contact updates: 0\n" + "domain autorenews: 0\n" - + "domain creates: 5\n" + + "domain creates: 4\n" + "domain creates ascii: 4\n" - + "domain creates idn: 1\n" + + "domain creates idn: 0\n" + "domain creates start date sunrise: 1\n" + "domain creates with claims notice: 1\n" + "domain creates with fee: 1\n" + "domain creates with sec dns: 1\n" - + "domain creates without sec dns: 4\n" + + "domain creates without sec dns: 3\n" + "domain deletes: 1\n" + "domain renews: 0\n" - + "domain restores: 1\n" + + "domain restores: 0\n" + "domain transfer approves: 1\n" + "domain transfer cancels: 1\n" + "domain transfer rejects: 1\n" @@ -131,7 +125,7 @@ public final class OteStatsTest { + "host deletes: 0\n" + "host updates: 10\n" + "unclassified flows: 0\n" - + "TOTAL: 38"; + + "TOTAL: 34"; assertThat(stats.toString()).isEqualTo(expected); } } diff --git a/javatests/google/registry/model/OteStatsTestHelper.java b/javatests/google/registry/model/OteStatsTestHelper.java index e5f4972e5..95a9ca1c1 100644 --- a/javatests/google/registry/model/OteStatsTestHelper.java +++ b/javatests/google/registry/model/OteStatsTestHelper.java @@ -14,7 +14,6 @@ package google.registry.model; -import static google.registry.testing.DatastoreHelper.deleteResource; import static google.registry.testing.DatastoreHelper.persistPremiumList; import static google.registry.testing.DatastoreHelper.persistResource; import static google.registry.testing.TestDataHelper.loadBytes; @@ -27,12 +26,39 @@ import java.io.IOException; public final class OteStatsTestHelper { - private static HistoryEntry hostDeleteHistoryEntry; - private static HistoryEntry domainCreateHistoryEntry; - private static HistoryEntry domainRestoreHistoryEntry; + public static void setupCompleteOte(String baseClientId) throws IOException { + setupIncompleteOte(baseClientId); + String oteAccount1 = String.format("%s-1", baseClientId); + persistResource( + new HistoryEntry.Builder() + .setClientId(oteAccount1) + .setType(Type.DOMAIN_CREATE) + .setXmlBytes(getBytes("domain_create_idn.xml")) + .build()); + persistResource( + new HistoryEntry.Builder() + .setClientId(oteAccount1) + .setType(Type.DOMAIN_RESTORE) + .setXmlBytes(getBytes("domain_restore.xml")) + .build()); + persistResource( + new HistoryEntry.Builder() + .setClientId(oteAccount1) + .setType(Type.HOST_DELETE) + .setXmlBytes(getBytes("host_delete.xml")) + .build()); + } - // TODO(b/122830156): Have this replicate the exact OT&E workflow with the correct client IDs - public static void setupHistoryEntries(String baseClientId) throws IOException { + /** + * Sets up an incomplete OT&E registrar. It is missing the following entries: + * + * - DOMAIN_CREATES_IDN + * - DOMAIN_RESTORES + * - HOST_DELETES + * + * TODO(b/122830156): Have this replicate the exact OT&E workflow with the correct client IDs + */ + public static void setupIncompleteOte(String baseClientId) throws IOException { persistPremiumList("default_sandbox_list", "sandbox,USD 1000"); OteAccountBuilder.forClientId(baseClientId).addContact("email@example.com").buildAndPersist(); String oteAccount1 = String.format("%s-1", baseClientId); @@ -42,13 +68,6 @@ public final class OteStatsTestHelper { .setType(Type.DOMAIN_CREATE) .setXmlBytes(getBytes("domain_create_sunrise.xml")) .build()); - domainCreateHistoryEntry = - persistResource( - new HistoryEntry.Builder() - .setClientId(oteAccount1) - .setType(Type.DOMAIN_CREATE) - .setXmlBytes(getBytes("domain_create_idn.xml")) - .build()); persistResource( new HistoryEntry.Builder() .setClientId(oteAccount1) @@ -73,13 +92,6 @@ public final class OteStatsTestHelper { .setType(Type.DOMAIN_DELETE) .setXmlBytes(getBytes("domain_delete.xml")) .build()); - domainRestoreHistoryEntry = - persistResource( - new HistoryEntry.Builder() - .setClientId(oteAccount1) - .setType(Type.DOMAIN_RESTORE) - .setXmlBytes(getBytes("domain_restore.xml")) - .build()); persistResource( new HistoryEntry.Builder() .setClientId(oteAccount1) @@ -116,13 +128,6 @@ public final class OteStatsTestHelper { .setType(Type.HOST_CREATE) .setXmlBytes(getBytes("host_create_complete.xml")) .build()); - hostDeleteHistoryEntry = - persistResource( - new HistoryEntry.Builder() - .setClientId(oteAccount1) - .setType(Type.HOST_DELETE) - .setXmlBytes(getBytes("host_delete.xml")) - .build()); // Persist 10 host updates for a total of 25 history entries. Since these also sort last by // modification time, when these cause all tests to pass, only the first will be recorded and // the rest will be skipped. @@ -138,18 +143,6 @@ public final class OteStatsTestHelper { } } - public static void deleteHostDeleteHistoryEntry() { - deleteResource(hostDeleteHistoryEntry); - } - - public static void deleteDomainCreateHistoryEntry() { - deleteResource(domainCreateHistoryEntry); - } - - public static void deleteDomainRestoreHistoryEntry() { - deleteResource(domainRestoreHistoryEntry); - } - private static byte[] getBytes(String filename) throws IOException { return loadBytes(OteStatsTestHelper.class, filename).read(); } diff --git a/javatests/google/registry/server/Fixture.java b/javatests/google/registry/server/Fixture.java index 8840697bf..8cda8c67e 100644 --- a/javatests/google/registry/server/Fixture.java +++ b/javatests/google/registry/server/Fixture.java @@ -28,7 +28,6 @@ import static google.registry.testing.DatastoreHelper.persistResource; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.googlecode.objectify.Key; -import google.registry.model.OteAccountBuilder; import google.registry.model.OteStatsTestHelper; import google.registry.model.contact.ContactAddress; import google.registry.model.contact.ContactResource; @@ -65,9 +64,9 @@ public enum Fixture { // Used for OT&E TLDs persistPremiumList("default_sandbox_list"); - OteAccountBuilder.forClientId("oteunfinished").addContact("email@example.com").buildAndPersist(); try { - OteStatsTestHelper.setupHistoryEntries("otefinished"); + OteStatsTestHelper.setupCompleteOte("otefinished"); + OteStatsTestHelper.setupIncompleteOte("oteunfinished"); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/javatests/google/registry/tools/server/VerifyOteActionTest.java b/javatests/google/registry/tools/server/VerifyOteActionTest.java index 5df96ebae..580fdc480 100644 --- a/javatests/google/registry/tools/server/VerifyOteActionTest.java +++ b/javatests/google/registry/tools/server/VerifyOteActionTest.java @@ -22,7 +22,6 @@ import google.registry.model.OteStatsTestHelper; import google.registry.testing.AppEngineRule; import java.util.Map; import java.util.regex.Pattern; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,28 +35,23 @@ public class VerifyOteActionTest { private final VerifyOteAction action = new VerifyOteAction(); - @Before - public void init() throws Exception { - OteStatsTestHelper.setupHistoryEntries("blobio"); - } - @Test - public void testSuccess_summarize_allPass() { + public void testSuccess_summarize_allPass() throws Exception { + OteStatsTestHelper.setupCompleteOte("blobio"); assertThat(getResponse(true)) .isEqualTo("# actions: 30 - Reqs: [----------------] 16/16 - Overall: PASS"); } @Test - public void testFailure_summarize_someFailures() { - OteStatsTestHelper.deleteDomainCreateHistoryEntry(); - OteStatsTestHelper.deleteDomainRestoreHistoryEntry(); - OteStatsTestHelper.deleteHostDeleteHistoryEntry(); + public void testFailure_summarize_someFailures() throws Exception { + OteStatsTestHelper.setupIncompleteOte("blobio"); assertThat(getResponse(true)) .isEqualTo("# actions: 34 - Reqs: [-.-----.------.-] 13/16 - Overall: FAIL"); } @Test - public void testSuccess_passNotSummarized() { + public void testSuccess_passNotSummarized() throws Exception { + OteStatsTestHelper.setupCompleteOte("blobio"); String expectedOteStatus = "domain creates idn: 1\n" + "domain creates start date sunrise: 1\n" @@ -86,10 +80,10 @@ public class VerifyOteActionTest { } @Test - public void testFailure_missingHostDelete() { - OteStatsTestHelper.deleteHostDeleteHistoryEntry(); + public void testFailure_incomplete() throws Exception { + OteStatsTestHelper.setupIncompleteOte("blobio"); String expectedOteStatus = - "domain creates idn: 1\n" + "domain creates idn: 0\n" + "domain creates start date sunrise: 1\n" + "domain creates with claims notice: 1\n" + "domain creates with fee: 1\n" @@ -97,7 +91,7 @@ public class VerifyOteActionTest { + ".*" + "domain deletes: 1\n" + ".*" - + "domain restores: 1\n" + + "domain restores: 0\n" + "domain transfer approves: 1\n" + "domain transfer cancels: 1\n" + "domain transfer rejects: 1\n" @@ -109,7 +103,7 @@ public class VerifyOteActionTest { + "host deletes: 0\n" + "host updates: 10\n" + ".*" - + "Requirements passed: 15/16\n" + + "Requirements passed: 13/16\n" + "Overall OT&E status: FAIL\n"; Pattern expectedOteStatusPattern = Pattern.compile(expectedOteStatus, Pattern.DOTALL); assertThat(getResponse(false)).containsMatch(expectedOteStatusPattern); diff --git a/javatests/google/registry/ui/server/registrar/OteStatusActionTest.java b/javatests/google/registry/ui/server/registrar/OteStatusActionTest.java index 89c223509..4fbc935f4 100644 --- a/javatests/google/registry/ui/server/registrar/OteStatusActionTest.java +++ b/javatests/google/registry/ui/server/registrar/OteStatusActionTest.java @@ -51,10 +51,7 @@ public final class OteStatusActionTest { @Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build(); @Before - public void init() throws Exception { - OteStatsTestHelper.setupHistoryEntries(BASE_CLIENT_ID); - persistNewRegistrar(CLIENT_ID, "SomeRegistrar", Type.OTE, null); - + public void init() { ImmutableSetMultimap authValues = OteAccountBuilder.createClientIdToTldMap(BASE_CLIENT_ID).keySet().stream() .collect(toImmutableSetMultimap(Function.identity(), ignored -> Role.OWNER)); @@ -63,7 +60,9 @@ public final class OteStatusActionTest { @Test @SuppressWarnings("unchecked") - public void testSuccess_finishedOte() { + public void testSuccess_finishedOte() throws Exception { + OteStatsTestHelper.setupCompleteOte(BASE_CLIENT_ID); + Map actionResult = action.handleJsonRequest(ImmutableMap.of("clientId", CLIENT_ID)); assertThat(actionResult).containsEntry("status", "SUCCESS"); assertThat(actionResult).containsEntry("message", "OT&E check completed successfully"); @@ -76,8 +75,8 @@ public final class OteStatusActionTest { @Test @SuppressWarnings("unchecked") - public void testSuccess_unfinishedOte() { - OteStatsTestHelper.deleteHostDeleteHistoryEntry(); + public void testSuccess_incomplete() throws Exception { + OteStatsTestHelper.setupIncompleteOte(BASE_CLIENT_ID); Map actionResult = action.handleJsonRequest(ImmutableMap.of("clientId", CLIENT_ID)); assertThat(actionResult).containsEntry("status", "SUCCESS"); @@ -92,6 +91,16 @@ public final class OteStatusActionTest { "description", StatType.HOST_DELETES.getDescription(), "requirement", StatType.HOST_DELETES.getRequirement(), "timesPerformed", 0, + "completed", false), + ImmutableMap.of( + "description", StatType.DOMAIN_RESTORES.getDescription(), + "requirement", StatType.DOMAIN_RESTORES.getRequirement(), + "timesPerformed", 0, + "completed", false), + ImmutableMap.of( + "description", StatType.DOMAIN_CREATES_IDN.getDescription(), + "requirement", StatType.DOMAIN_CREATES_IDN.getRequirement(), + "timesPerformed", 0, "completed", false)); }