// Copyright 2017 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.flows; import static com.google.common.io.BaseEncoding.base64; import static com.google.common.truth.Truth.assertThat; import static google.registry.testing.TestDataHelper.loadFileWithSubstitutions; import static google.registry.testing.TestLogHandlerUtils.findFirstLogMessageByPrefix; import static java.nio.charset.StandardCharsets.UTF_8; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.testing.TestLogHandler; import google.registry.flows.annotations.ReportingSpec; import google.registry.model.eppcommon.Trid; import google.registry.model.eppinput.EppInput; import google.registry.model.eppoutput.EppOutput.ResponseOrGreeting; import google.registry.model.eppoutput.EppResponse; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.testing.ShardableTestCase; import java.util.Map; import java.util.logging.Logger; import org.json.simple.JSONValue; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link FlowReporter}. */ @RunWith(JUnit4.class) public class FlowReporterTest extends ShardableTestCase { static class TestCommandFlow implements Flow { @Override public ResponseOrGreeting run() throws EppException { return mock(EppResponse.class); } } @ReportingSpec(ActivityReportField.CONTACT_CHECK) static class TestReportingSpecCommandFlow implements Flow { @Override public ResponseOrGreeting run() throws EppException { return mock(EppResponse.class); } } private final FlowReporter flowReporter = new FlowReporter(); private final TestLogHandler handler = new TestLogHandler(); @Before public void before() { Logger.getLogger(FlowReporter.class.getCanonicalName()).addHandler(handler); flowReporter.trid = Trid.create("client-123", "server-456"); flowReporter.clientId = "TheRegistrar"; flowReporter.inputXmlBytes = "".getBytes(UTF_8); flowReporter.flowClass = TestCommandFlow.class; flowReporter.eppInput = mock(EppInput.class); when(flowReporter.eppInput.getCommandType()).thenReturn("info"); when(flowReporter.eppInput.getResourceType()).thenReturn(Optional.of("domain")); when(flowReporter.eppInput.getSingleTargetId()).thenReturn(Optional.of("target.foo")); when(flowReporter.eppInput.getTargetIds()).thenReturn(ImmutableList.of("target.foo")); } @Test public void testRecordToLogs_eppInput_basic() throws Exception { flowReporter.recordToLogs(); assertThat(parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-EPPINPUT: "))) .containsExactly( "xml", "\n", "xmlBytes", "PHhtbC8+"); // Base64-encoding of "". } @Test public void testRecordToLogs_eppInput_complex() throws Exception { String domainCreateXml = loadFileWithSubstitutions( getClass(), "domain_create_prettyprinted.xml", ImmutableMap.of()); flowReporter.inputXmlBytes = domainCreateXml.getBytes(UTF_8); flowReporter.recordToLogs(); assertThat(parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-EPPINPUT: "))) .containsExactly( "xml", domainCreateXml, "xmlBytes", base64().encode(domainCreateXml.getBytes(UTF_8))); } @Test public void testRecordToLogs_metadata_basic() throws Exception { flowReporter.recordToLogs(); assertThat(parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: "))) .containsExactly( "serverTrid", "server-456", "clientId", "TheRegistrar", "commandType", "info", "resourceType", "domain", "flowClassName", "TestCommandFlow", "targetId", "target.foo", "targetIds", ImmutableList.of("target.foo"), "tld", "foo", "tlds", ImmutableList.of("foo"), "icannActivityReportField", ""); } @Test public void testRecordToLogs_metadata_withReportingSpec() throws Exception { flowReporter.flowClass = TestReportingSpecCommandFlow.class; flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("flowClassName", "TestReportingSpecCommandFlow"); assertThat(json).containsEntry("icannActivityReportField", "srs-cont-check"); } @Test public void testRecordToLogs_metadata_noClientId() throws Exception { flowReporter.clientId = ""; flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("clientId", ""); } @Test public void testRecordToLogs_metadata_notResourceFlow_noResourceTypeOrTld() throws Exception { when(flowReporter.eppInput.getResourceType()).thenReturn(Optional.absent()); flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("resourceType", ""); assertThat(json).containsEntry("tld", ""); assertThat(json).containsEntry("tlds", ImmutableList.of()); } @Test public void testRecordToLogs_metadata_notDomainFlow_noTld() throws Exception { when(flowReporter.eppInput.getResourceType()).thenReturn(Optional.of("contact")); flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("resourceType", "contact"); assertThat(json).containsEntry("tld", ""); assertThat(json).containsEntry("tlds", ImmutableList.of()); } @Test public void testRecordToLogs_metadata_multipartDomainName_multipartTld() throws Exception { when(flowReporter.eppInput.getSingleTargetId()).thenReturn(Optional.of("target.co.uk")); when(flowReporter.eppInput.getTargetIds()).thenReturn(ImmutableList.of("target.co.uk")); flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("targetId", "target.co.uk"); assertThat(json).containsEntry("targetIds", ImmutableList.of("target.co.uk")); assertThat(json).containsEntry("tld", "co.uk"); assertThat(json).containsEntry("tlds", ImmutableList.of("co.uk")); } @Test public void testRecordToLogs_metadata_multipleTargetIds_uniqueTldSet() throws Exception { when(flowReporter.eppInput.getSingleTargetId()).thenReturn(Optional.absent()); when(flowReporter.eppInput.getTargetIds()) .thenReturn(ImmutableList.of("target.co.uk", "foo.uk", "bar.uk", "baz.com")); flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("targetId", ""); assertThat(json).containsEntry( "targetIds", ImmutableList.of("target.co.uk", "foo.uk", "bar.uk", "baz.com")); assertThat(json).containsEntry("tld", ""); assertThat(json).containsEntry("tlds", ImmutableList.of("co.uk", "uk", "com")); } @Test public void testRecordToLogs_metadata_uppercaseDomainName_lowercaseTld() throws Exception { when(flowReporter.eppInput.getSingleTargetId()).thenReturn(Optional.of("TARGET.FOO")); when(flowReporter.eppInput.getTargetIds()).thenReturn(ImmutableList.of("TARGET.FOO")); flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("targetId", "TARGET.FOO"); assertThat(json).containsEntry("targetIds", ImmutableList.of("TARGET.FOO")); assertThat(json).containsEntry("tld", "foo"); assertThat(json).containsEntry("tlds", ImmutableList.of("foo")); } @Test public void testRecordToLogs_metadata_invalidDomainName_stillGuessesTld() throws Exception { when(flowReporter.eppInput.getSingleTargetId()).thenReturn(Optional.of("")); when(flowReporter.eppInput.getTargetIds()).thenReturn(ImmutableList.of("")); flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("targetId", ""); assertThat(json).containsEntry("targetIds", ImmutableList.of("")); assertThat(json).containsEntry("tld", "com>"); assertThat(json).containsEntry("tlds", ImmutableList.of("com>")); } @Test public void testRecordToLogs_metadata_domainWithoutPeriod_noTld() throws Exception { when(flowReporter.eppInput.getSingleTargetId()).thenReturn(Optional.of("target,foo")); when(flowReporter.eppInput.getTargetIds()).thenReturn(ImmutableList.of("target,foo")); flowReporter.recordToLogs(); Map json = parseJsonMap(findFirstLogMessageByPrefix(handler, "FLOW-LOG-SIGNATURE-METADATA: ")); assertThat(json).containsEntry("targetId", "target,foo"); assertThat(json).containsEntry("targetIds", ImmutableList.of("target,foo")); assertThat(json).containsEntry("tld", ""); assertThat(json).containsEntry("tlds", ImmutableList.of()); } @SuppressWarnings("unchecked") private static Map parseJsonMap(String json) throws Exception { return (Map) JSONValue.parseWithException(json); } }