Prober EPP components added (#202)

* Updated issues in rebasing

* Minor style change on prober/build.gradle

* Fixed warnings for java compilation

* Fixed files to pass all style tests

* Initial Commit.

* Deleted unfinished features. Added ActionHandler and its Unit Tests.

* Included prober subproject in settings.gradle

* Added Protocol Class and its Basic Unit Tests

* Added Changes Suggested by jianglai

* Fixed Gitignore to take out AutoValue generated code

* Removed AutoValue java files

* Added gitignore within prober

* Removed all generated java

* Final Changes in .gitignore

* Added Ssl and WebWhois Action Handlers and their unit tests in addition to the ProbingAction class

* Fixed build.gradle changes requested

* Removed Files irrelevant to current pull request

* Minor fixes to ActionHandler, as responded in comments, removed package-info, and updated settings.gradle

* Fully Updated ActionHandler (missing updated JavaDoc)

* Added changed Protocol and both Inbound and Outbound Markers

* Removed AutoVaue ignore clause from .gitignore

* removed unneccessary dependencies in build.gradle

* Fixed Javadoc and comments for ActionHandler

* Fixed comments and JavaDoc on other files

* EOL added

* Removed Unnecessary Files

* fixed .gradle files styles

* Removed outbound message from ActionHandler's fields and renamed Marker Interfaces

* Fixed javadoc for Marker Interfaced

* Modified Comments on ActionHandler

* Removed LocalAddress from Protocol

* Fixed Travis Build Issues

* Rebased to Master and added in modified Handlers and ProbingAction

* Fixed changes suggested by CydeWeys

* Added missing license headers and JavaDoc

* Minor fix in NewChannelAction JavaDoc

* Minor Style Fix

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Updated build.gradle file

* Modified license header dates

* Updated WebWhois tests.

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* SpotlessApply run to fix style issues

* Added license header and newline where appropriate.

* Javadoc style fix in tests and removed unused methods

* Refactored ProbingAction to minimize number of unnecessary methods

* Modified tests for WebWhois according to changes suggested by laijiang.

* Removed TestProvider from TestUtils.

* Rebased to Master and added in modified Handlers and ProbingAction

* Fixed changes suggested by CydeWeys

* Added missing license headers and JavaDoc

* Minor fix in NewChannelAction JavaDoc

* Minor Style Fix

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Updated build.gradle file

* Modified license header dates

* Updated WebWhois tests.

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* SpotlessApply run to fix style issues

* Added license header and newline where appropriate.

* Javadoc style fix in tests and removed unused methods

* Refactored ProbingAction to minimize number of unnecessary methods

* Modified tests for WebWhois according to changes suggested by laijiang.

* Removed TestProvider from TestUtils.

* Rebased to master

* Updated issues in rebasing

* Minor style change on prober/build.gradle

* Fixed warnings for java compilation

* Fixed files to pass all style tests

* Minor syle fixes after succesful rebase onto master

* Initial Commit.

* Added Protocol Class and its Basic Unit Tests

* Fixed Gitignore to take out AutoValue generated code

* Final Changes in .gitignore

* Minor fixes to ActionHandler, as responded in comments, removed package-info, and updated settings.gradle

* Removed AutoVaue ignore clause from .gitignore

* Rebased to Master and added in modified Handlers and ProbingAction

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Added missing license headers and JavaDoc

* Minor fix in NewChannelAction JavaDoc

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Modified license header dates

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* SpotlessApply run to fix style issues

* Added license header and newline where appropriate.

* Javadoc style fix in tests and removed unused methods

* Fixed files to pass all style tests

* Fixed changes suggested by CydeWeys

* Rebased to Master and added in modified Handlers and ProbingAction

* Added missing license headers and JavaDoc

* Minor fix in NewChannelAction JavaDoc

* Minor Style Fix

* Full WebWhoIs Sequence Added

* Refactored by responses suggested by jianglai.

* Updated build.gradle file

* Modified license header dates

* Updated WebWhois tests.

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* SpotlessApply run to fix style issues

* Added license header and newline where appropriate.

* Javadoc style fix in tests and removed unused methods

* Refactored ProbingAction to minimize number of unnecessary methods

* Modified tests for WebWhois according to changes suggested by laijiang.

* Removed TestProvider from TestUtils.

* Rebased to Master and added in modified Handlers and ProbingAction

* Fixed changes suggested by CydeWeys

* Added missing license headers and JavaDoc

* Minor fix in NewChannelAction JavaDoc

* Minor Style Fix

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Updated build.gradle file

* Modified license header dates

* Updated WebWhois tests.

* Added license header and newline where appropriate.

* Javadoc style fix in tests and removed unused methods

* Refactored ProbingAction to minimize number of unnecessary methods

* Modified tests for WebWhois according to changes suggested by laijiang.

* Removed TestProvider from TestUtils.

* Rebased to master

* Updated issues in rebasing

* Added circular linked list to utils

* License Header added

* Refactored probing sequence to be circular linked list iterator

* Modified ProbingStep tests to reflect new ProbingStep structure.

* Added circular linked list to utils

* Added circular linked list to utils

* License Header added

* License Header added

* Refactored probing sequence to be circular linked list iterator

* Modified ProbingStep tests to reflect new ProbingStep structure.

* Added missing license header to DefaultCircularLinkedListIterator

* Fixed changes suggested by CydeWeys

* Rebased to Master and added in modified Handlers and ProbingAction

* Added missing license headers and JavaDoc

* Minor fix in NewChannelAction JavaDoc

* Minor Style Fix

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Updated build.gradle file

* Fixed max column length to be 100

* Rebased to Master and added in modified Handlers and ProbingAction

* Modified license header dates

* Updated WebWhois tests.

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* Javadoc style fix in tests and removed unused methods

* Refactored ProbingAction to minimize number of unnecessary methods

* Modified tests for WebWhois according to changes suggested by laijiang.

* Fixed changes suggested by CydeWeys

* Added missing license headers and JavaDoc

* Minor fix in NewChannelAction JavaDoc

* Minor Style Fix

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Updated build.gradle file

* Modified license header dates

* Updated WebWhois tests.

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* SpotlessApply run to fix style issues

* Added license header and newline where appropriate.

* Javadoc style fix in tests and removed unused methods

* Refactored ProbingAction to minimize number of unnecessary methods

* Added circular linked list to utils

* Added circular linked list to utils

* License Header added

* License Header added

* Refactored probing sequence to be circular linked list iterator

* Refactored probing sequence to be circular linked list iterator

* Modified tests for WebWhois according to changes suggested by laijiang.

* Removed TestProvider from TestUtils.

* ProbingStepTest modified to have fewer unnecessary helper methods

* Updated issues in rebasing

* Fixed max column length to be 100

* Minor changes to pass style tests

* Successful rebase onto finished web-whois branch

* Removed need for TestTokens with Mockito mocks of Tokens

* Fixed style issues in DefaultCircularLinkedListIterator and AbstractCircularLinkedListIterator

* Modified CircularList according to changes suggested by jianglai.

* Added Protocol Class and its Basic Unit Tests

* Added Ssl and WebWhois Action Handlers and their unit tests in addition to the ProbingAction class

* Fixed changes suggested by CydeWeys

* Fixed changes suggested by CydeWeys

* Rebased to Master and added in modified Handlers and ProbingAction

* Rebased to Master and added in modified Handlers and ProbingAction

* Rebased to Master and added in modified Handlers and ProbingAction

* Rebased to Master and added in modified Handlers and ProbingAction

* Rebased to Master and added in modified Handlers and ProbingAction

* Added missing license headers and JavaDoc

* Minor Style Fix

* Minor Style Fix

* Full WebWhoIs Sequence Added

* Full WebWhoIs Sequence Added

* Full WebWhoIs Sequence Added

* Full WebWhoIs Sequence Added

* fixed build issues

* Refactored by responses suggested by jianglai.

* Updated build.gradle file

* Updated WebWhois tests.

* Added Basic EPP structure

* Added Basic EPP structure

* Prober Updated tests

* Prober Updated tests

* Fully functioning EPP sequences with modified WebWhois base.

* Fully functioning EPP sequences with modified WebWhois base.

* Added Modified test server infrastructure.

* Added Modified test server infrastructure.

* Allowed ActionHandler to pass status to next hanlder in pipeline (to be MetricsHandler).

* Allowed ActionHandler to pass status to next hanlder in pipeline (to be MetricsHandler).

* Javadoc on EppRequestMessage added

* Javadoc on EppRequestMessage added

* Updated EppServer to properly send successful Check responses.

* Updated EppServer to properly send successful Check responses.

* Allowed for expected failures in EPP actions.

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* Refactored WebWhois to accomodate jianglai's suggested changes and modified tests to reflect this refactoring

* Fully rebased branch to prober-web-whois after refactoring

* Added license header and newline where appropriate.

* Javadoc style fix in tests and removed unused methods

* Javadoc style fix in tests and removed unused methods

* Modified tests for WebWhois according to changes suggested by laijiang.

* Modified tests for WebWhois according to changes suggested by laijiang.

* Removed TestProvider from TestUtils.

* Rebased to master

* Fixed max column length to be 100

* Fixed files to pass all style tests

* Minor changes to pass style tests

* Successful rebase onto circular-list

* Epp Refactored to accomodate circular linked list PR

* Modified construction of Epp Probing Sequences to reflect CircularList change

* Renamed ProberModule provided Duration

* Removed unnecessary ServerSideException file

* Google-Java-Format run on all prober files

* Style fix on ProbingSequence and its unit tests

* Removed subclasses of EppRequestMessage and EppResponseMessage and fixed style and other minor issues

* Style changes implemented as suggested by jianglai

* Added style fixes suggested by mindhog
This commit is contained in:
Aman Sanger 2019-08-15 16:03:36 -04:00 committed by GitHub
parent 86fefa9a03
commit 57975898d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 6089 additions and 1083 deletions

View file

@ -22,6 +22,8 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import google.registry.monitoring.blackbox.connection.ProbingAction;
import google.registry.monitoring.blackbox.connection.Protocol;
import google.registry.monitoring.blackbox.exceptions.FailureException;
import google.registry.monitoring.blackbox.exceptions.UndeterminedStateException;
import google.registry.monitoring.blackbox.exceptions.UnrecoverableStateException;
@ -38,22 +40,20 @@ import org.mockito.Mockito;
/**
* Unit Tests on {@link ProbingSequence}
*
* <p>First tests the construction of sequences and ensures the ordering is exactly how
* we expect it to be.</p>
* <p>First tests the construction of sequences and ensures the ordering is exactly how we expect it
* to be.
*
* <p>Then tests the execution of each step, by ensuring the methods treatment of any kind
* of response from the {@link ProbingStep}s or {@link ProbingAction}s is what is expected.</p>
* <p>Then tests the execution of each step, by ensuring the methods treatment of any kind of
* response from the {@link ProbingStep}s or {@link ProbingAction}s is what is expected.
*
* <p>On every test that runs the sequence, in order for the sequence to stop, we throw an
* {@link UnrecoverableStateException}, using mocks of the steps or actions, as the sequences
* are run using the main thread (with {@link EmbeddedChannel}).</p>
* <p>On every test that runs the sequence, in order for the sequence to stop, we throw an {@link
* UnrecoverableStateException}, using mocks of the steps or actions, as the sequences are run using
* the main thread (with {@link EmbeddedChannel}).
*/
@RunWith(JUnit4.class)
public class ProbingSequenceTest {
/**
* Default mock {@link ProbingAction} returned when generating an action with a mockStep.
*/
/** Default mock {@link ProbingAction} returned when generating an action with a mockStep. */
private ProbingAction mockAction = Mockito.mock(ProbingAction.class);
/**
@ -62,10 +62,7 @@ public class ProbingSequenceTest {
*/
private ProbingStep mockStep = Mockito.mock(ProbingStep.class);
/**
* Default mock {@link Token} that is passed into each {@link ProbingSequence} tested.
*/
/** Default mock {@link Token} that is passed into each {@link ProbingSequence} tested. */
private Token mockToken = Mockito.mock(Token.class);
/**
@ -104,11 +101,12 @@ public class ProbingSequenceTest {
ProbingStep secondStep = Mockito.mock(ProbingStep.class);
ProbingStep thirdStep = Mockito.mock(ProbingStep.class);
ProbingSequence sequence = new ProbingSequence.Builder(mockToken)
.add(firstStep)
.add(secondStep)
.add(thirdStep)
.build();
ProbingSequence sequence =
new ProbingSequence.Builder(mockToken)
.add(firstStep)
.add(secondStep)
.add(thirdStep)
.build();
assertThat(sequence.get()).isEqualTo(firstStep);
sequence = sequence.next();
@ -128,12 +126,13 @@ public class ProbingSequenceTest {
ProbingStep secondStep = Mockito.mock(ProbingStep.class);
ProbingStep thirdStep = Mockito.mock(ProbingStep.class);
ProbingSequence sequence = new ProbingSequence.Builder(mockToken)
.add(thirdStep)
.add(secondStep)
.markFirstRepeated()
.add(firstStep)
.build();
ProbingSequence sequence =
new ProbingSequence.Builder(mockToken)
.add(thirdStep)
.add(secondStep)
.markFirstRepeated()
.add(firstStep)
.build();
assertThat(sequence.get()).isEqualTo(thirdStep);
sequence = sequence.next();
@ -145,47 +144,43 @@ public class ProbingSequenceTest {
sequence = sequence.next();
assertThat(sequence.get()).isEqualTo(secondStep);
}
@Test
public void testRunStep_Success() throws UndeterminedStateException {
//Always returns a succeeded future on call to mockAction.
// Always returns a succeeded future on call to mockAction.
doReturn(channel.newSucceededFuture()).when(mockAction).call();
// Has mockStep always return mockAction on call to generateAction
// Has mockStep always return mockAction on call to generateAction.
doReturn(mockAction).when(mockStep).generateAction(any(Token.class));
//Dummy step that server purpose of placeholder to test ability of ProbingSequence to move on.
// Dummy step that server purpose of placeholder to test ability of ProbingSequence to move on.
ProbingStep secondStep = Mockito.mock(ProbingStep.class);
ProbingAction secondAction = Mockito.mock(ProbingAction.class);
doReturn(channel.newFailedFuture(new UnrecoverableStateException(""))).when(secondAction)
doReturn(channel.newFailedFuture(new UnrecoverableStateException("")))
.when(secondAction)
.call();
doReturn(secondAction).when(secondStep).generateAction(mockToken);
//Build testable sequence from mocked components.
ProbingSequence sequence = new ProbingSequence.Builder(mockToken)
.add(mockStep)
.add(secondStep)
.build();
// Build testable sequence from mocked components.
ProbingSequence sequence =
new ProbingSequence.Builder(mockToken).add(mockStep).add(secondStep).build();
sequence.start();
// We expect to have only generated actions from mockStep once, and we expect to have called
// this generated action only once, as when we move on to secondStep, it terminates the
// sequence.
verify(mockStep).generateAction(any(Token.class));
verify(mockStep).generateAction(mockToken);
verify(mockAction).call();
// Similarly, we expect to generate actions and call the action from the secondStep once, as
// after calling it, the sequence should be terminated
verify(secondStep).generateAction(any(Token.class));
verify(secondStep).generateAction(mockToken);
verify(secondAction).call();
//We should have modified the token's channel after the first, succeeded step.
// We should have modified the token's channel after the first, succeeded step.
assertThat(mockToken.channel()).isEqualTo(channel);
}
@ -201,7 +196,7 @@ public class ProbingSequenceTest {
ProbingStep secondStep = Mockito.mock(ProbingStep.class);
ProbingAction secondAction = Mockito.mock(ProbingAction.class);
// Necessary for success of ProbingSequence runStep method as it calls get().protocol()
// Necessary for success of ProbingSequence runStep method as it calls get().protocol().
doReturn(mockProtocol).when(secondStep).protocol();
// We ensure that secondStep has necessary attributes to be successful step to pass on to
@ -220,18 +215,15 @@ public class ProbingSequenceTest {
doReturn(channel.newFailedFuture(new UnrecoverableStateException(""))).when(thirdAction).call();
doReturn(thirdAction).when(mockStep).generateAction(secondToken);
//Build testable sequence from mocked components.
ProbingSequence sequence = new ProbingSequence.Builder(mockToken)
.add(mockStep)
.add(secondStep)
.build();
// Build testable sequence from mocked components.
ProbingSequence sequence =
new ProbingSequence.Builder(mockToken).add(mockStep).add(secondStep).build();
sequence.start();
// We expect to have generated actions from mockStep twice (once for mockToken and once for
// secondToken), and we expectto have called each generated action only once, as when we move
// on to mockStep the second time, it will terminate the sequence after calling thirdAction.
verify(mockStep, times(2)).generateAction(any(Token.class));
verify(mockStep).generateAction(mockToken);
verify(mockStep).generateAction(secondToken);
verify(mockAction).call();
@ -239,23 +231,22 @@ public class ProbingSequenceTest {
// Similarly, we expect to generate actions and call the action from the secondStep once, as
// after calling it, we move on to mockStep again, which terminates the sequence.
verify(secondStep).generateAction(any(Token.class));
verify(secondStep).generateAction(mockToken);
verify(secondAction).call();
//We should have modified the token's channel after the first, succeeded step.
// We should have modified the token's channel after the first, succeeded step.
assertThat(mockToken.channel()).isEqualTo(channel);
}
/**
* Test for when we expect Failure within try catch block of generating and calling a
* {@link ProbingAction}.
* Test for when we expect Failure within try catch block of generating and calling a {@link
* ProbingAction}.
*
* @throws UndeterminedStateException - necessary for having mock return anything on a call to
* {@code generateAction}.
* @throws UndeterminedStateException - necessary for having mock return anything on a call to
* {@code generateAction}.
*/
private void testActionFailure() throws UndeterminedStateException {
//Dummy step that server purpose of placeholder to test ability of ProbingSequence to move on.
// Dummy step that server purpose of placeholder to test ability of ProbingSequence to move on.
ProbingStep secondStep = Mockito.mock(ProbingStep.class);
// We create a second token that when used to generate an action throws an
@ -264,18 +255,15 @@ public class ProbingSequenceTest {
doReturn(secondToken).when(mockToken).next();
doThrow(new UnrecoverableStateException("")).when(mockStep).generateAction(secondToken);
//Build testable sequence from mocked components.
ProbingSequence sequence = new ProbingSequence.Builder(mockToken)
.add(mockStep)
.add(secondStep)
.build();
// Build testable sequence from mocked components.
ProbingSequence sequence =
new ProbingSequence.Builder(mockToken).add(mockStep).add(secondStep).build();
sequence.start();
// We expect that we have generated actions twice. First, when we actually test generateAction
// with an actual call using mockToken, and second when we throw an
// UnrecoverableStateException with secondToken.
verify(mockStep, times(2)).generateAction(any(Token.class));
verify(mockStep).generateAction(mockToken);
verify(mockStep).generateAction(secondToken);
@ -296,17 +284,14 @@ public class ProbingSequenceTest {
// Returns mock action on call to generate action for ProbingStep.
doReturn(mockAction).when(mockStep).generateAction(mockToken);
//Tests generic behavior we expect when we fail in generating or calling an action.
// Tests generic behavior we expect when we fail in generating or calling an action.
testActionFailure();
// We only expect to have called this action once, as we only get it from one generateAction
// call.
verify(mockAction).call();
}
@Test
public void testRunStep_FailureGenerating() throws UndeterminedStateException {
// Create a mock first step that returns the dummy action when called to generate an action.

View file

@ -15,12 +15,14 @@
package google.registry.monitoring.blackbox;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.monitoring.blackbox.ProbingAction.CONNECTION_FUTURE_KEY;
import static google.registry.monitoring.blackbox.connection.ProbingAction.CONNECTION_FUTURE_KEY;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import com.google.common.collect.ImmutableList;
import google.registry.monitoring.blackbox.connection.ProbingAction;
import google.registry.monitoring.blackbox.connection.Protocol;
import google.registry.monitoring.blackbox.exceptions.UndeterminedStateException;
import google.registry.monitoring.blackbox.handlers.ActionHandler;
import google.registry.monitoring.blackbox.handlers.ConversionHandler;
@ -48,31 +50,26 @@ import org.mockito.Mockito;
*/
public class ProbingStepTest {
/**
* Basic Constants necessary for tests
*/
/** Basic Constants necessary for tests */
private static final String ADDRESS_NAME = "TEST_ADDRESS";
private static final String PROTOCOL_NAME = "TEST_PROTOCOL";
private static final int PROTOCOL_PORT = 0;
private static final String TEST_MESSAGE = "TEST_MESSAGE";
private static final String SECONDARY_TEST_MESSAGE = "SECONDARY_TEST_MESSAGE";
private static final LocalAddress address = new LocalAddress(ADDRESS_NAME);
private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);
private final Bootstrap bootstrap = new Bootstrap()
.group(eventLoopGroup)
.channel(LocalChannel.class);
/**
* Used for testing how well probing step can create connection to blackbox server
*/
@Rule
public NettyRule nettyRule = new NettyRule(eventLoopGroup);
private final Bootstrap bootstrap =
new Bootstrap().group(eventLoopGroup).channel(LocalChannel.class);
/** Used for testing how well probing step can create connection to blackbox server */
@Rule public NettyRule nettyRule = new NettyRule(eventLoopGroup);
/**
* The two main handlers we need in any test pipeline used that connects to {@link NettyRule's
* server}
**/
*/
private ActionHandler testHandler = new TestActionHandler();
private ChannelHandler conversionHandler = new ConversionHandler();
/**
@ -92,12 +89,13 @@ public class ProbingStepTest {
@Test
public void testProbingActionGenerate_embeddedChannel() throws UndeterminedStateException {
// Sets up Protocol to represent existing channel connection.
Protocol testProtocol = Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(PROTOCOL_PORT)
.setPersistentConnection(true)
.build();
Protocol testProtocol =
Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(PROTOCOL_PORT)
.setPersistentConnection(true)
.build();
// Sets up an embedded channel to contain the two handlers we created already.
EmbeddedChannel channel = new EmbeddedChannel(conversionHandler, testHandler);
@ -109,12 +107,13 @@ public class ProbingStepTest {
doReturn(channel).when(testToken).channel();
// Sets up generic {@link ProbingStep} that we are testing.
ProbingStep testStep = ProbingStep.builder()
.setMessageTemplate(new TestMessage(TEST_MESSAGE))
.setBootstrap(bootstrap)
.setDuration(Duration.ZERO)
.setProtocol(testProtocol)
.build();
ProbingStep testStep =
ProbingStep.builder()
.setMessageTemplate(new TestMessage(TEST_MESSAGE))
.setBootstrap(bootstrap)
.setDuration(Duration.ZERO)
.setProtocol(testProtocol)
.build();
ProbingAction testAction = testStep.generateAction(testToken);
@ -123,27 +122,27 @@ public class ProbingStepTest {
assertThat(testAction.outboundMessage().toString()).isEqualTo(SECONDARY_TEST_MESSAGE);
assertThat(testAction.host()).isEqualTo(SECONDARY_TEST_MESSAGE);
assertThat(testAction.protocol()).isEqualTo(testProtocol);
}
@Test
public void testProbingActionGenerate_newChannel() throws UndeterminedStateException {
// Sets up Protocol for when we create a new channel.
Protocol testProtocol = Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(PROTOCOL_PORT)
.setPersistentConnection(false)
.build();
Protocol testProtocol =
Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(PROTOCOL_PORT)
.setPersistentConnection(false)
.build();
// Sets up generic ProbingStep that we are testing.
ProbingStep testStep = ProbingStep.builder()
.setMessageTemplate(new TestMessage(TEST_MESSAGE))
.setBootstrap(bootstrap)
.setDuration(Duration.ZERO)
.setProtocol(testProtocol)
.build();
ProbingStep testStep =
ProbingStep.builder()
.setMessageTemplate(new TestMessage(TEST_MESSAGE))
.setBootstrap(bootstrap)
.setDuration(Duration.ZERO)
.setProtocol(testProtocol)
.build();
// Sets up testToken to return arbitrary values, and no channel. Used when we create a new
// channel.
@ -162,7 +161,5 @@ public class ProbingStepTest {
assertThat(testAction.outboundMessage().toString()).isEqualTo(ADDRESS_NAME);
assertThat(testAction.host()).isEqualTo(ADDRESS_NAME);
assertThat(testAction.protocol()).isEqualTo(testProtocol);
}
}

View file

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.monitoring.blackbox;
package google.registry.monitoring.blackbox.connection;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.monitoring.blackbox.ProbingAction.CONNECTION_FUTURE_KEY;
import static google.registry.monitoring.blackbox.connection.ProbingAction.CONNECTION_FUTURE_KEY;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -46,7 +46,7 @@ import org.junit.runners.JUnit4;
* Unit tests for {@link ProbingAction} subtypes
*
* <p>Attempts to test how well each {@link ProbingAction} works with an {@link ActionHandler}
* subtype when receiving to all possible types of responses</p>
* subtype when receiving to all possible types of responses
*/
@RunWith(JUnit4.class)
public class ProbingActionTest {
@ -58,53 +58,55 @@ public class ProbingActionTest {
private static final int TEST_PORT = 0;
private static final EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);
/**
* Used for testing how well probing step can create connection to blackbox server
*/
@Rule
public NettyRule nettyRule = new NettyRule(eventLoopGroup);
/** Used for testing how well probing step can create connection to blackbox server */
@Rule public NettyRule nettyRule = new NettyRule(eventLoopGroup);
/**
* We use custom Test {@link ActionHandler} and {@link ConversionHandler} so test depends only on
* {@link ProbingAction}
*/
private ActionHandler testHandler = new TestActionHandler();
private ChannelHandler conversionHandler = new ConversionHandler();
//TODO - Currently, this test fails to receive outbound messages from the embedded channel, which
// TODO - Currently, this test fails to receive outbound messages from the embedded channel, which
// we will fix in a later release.
@Ignore
@Test
public void testSuccess_existingChannel() {
//setup
// setup
EmbeddedChannel channel = new EmbeddedChannel(conversionHandler, testHandler);
channel.attr(CONNECTION_FUTURE_KEY).set(channel.newSucceededFuture());
// Sets up a Protocol corresponding to when a connection exists.
Protocol protocol = Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(TEST_PORT)
.setPersistentConnection(true)
.build();
Protocol protocol =
Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(TEST_PORT)
.setPersistentConnection(true)
.build();
// Sets up a ProbingAction that creates a channel using test specified attributes.
ProbingAction action = ProbingAction.builder()
.setChannel(channel)
.setProtocol(protocol)
.setDelay(Duration.ZERO)
.setOutboundMessage(new TestMessage(TEST_MESSAGE))
.setHost("")
.build();
ProbingAction action =
ProbingAction.builder()
.setChannel(channel)
.setProtocol(protocol)
.setDelay(Duration.ZERO)
.setOutboundMessage(new TestMessage(TEST_MESSAGE))
.setHost("")
.build();
//tests main function of ProbingAction
// tests main function of ProbingAction
ChannelFuture future = action.call();
//Obtains the outboundMessage passed through pipeline after delay
// Obtains the outboundMessage passed through pipeline after delay
Object msg = null;
while (msg == null) {
msg = channel.readOutbound();
}
//tests the passed message is exactly what we expect
// tests the passed message is exactly what we expect
assertThat(msg).isInstanceOf(ByteBuf.class);
String request = ((ByteBuf) msg).toString(UTF_8);
assertThat(request).isEqualTo(TEST_MESSAGE);
@ -112,7 +114,8 @@ public class ProbingActionTest {
// Ensures that we haven't marked future as done until response is received.
assertThat(future.isDone()).isFalse();
//after writing inbound, we should have a success
// After writing inbound, we should have a success as we use an EmbeddedChannel, ensuring all
// operations happen on the main thread - i.e. synchronously.
channel.writeInbound(Unpooled.wrappedBuffer(SECONDARY_TEST_MESSAGE.getBytes(US_ASCII)));
assertThat(future.isSuccess()).isTrue();
@ -121,42 +124,41 @@ public class ProbingActionTest {
@Test
public void testSuccess_newChannel() throws Exception {
//setup
// setup
LocalAddress address = new LocalAddress(ADDRESS_NAME);
Bootstrap bootstrap = new Bootstrap()
.group(eventLoopGroup)
.channel(LocalChannel.class);
Bootstrap bootstrap = new Bootstrap().group(eventLoopGroup).channel(LocalChannel.class);
// Sets up a Protocol corresponding to when a new connection is created.
Protocol protocol = Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(TEST_PORT)
.setPersistentConnection(false)
.build();
Protocol protocol =
Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> conversionHandler, () -> testHandler))
.setName(PROTOCOL_NAME)
.setPort(TEST_PORT)
.setPersistentConnection(false)
.build();
nettyRule.setUpServer(address);
// Sets up a ProbingAction with existing channel using test specified attributes.
ProbingAction action = ProbingAction.builder()
.setBootstrap(bootstrap)
.setProtocol(protocol)
.setDelay(Duration.ZERO)
.setOutboundMessage(new TestMessage(TEST_MESSAGE))
.setHost(ADDRESS_NAME)
.build();
ProbingAction action =
ProbingAction.builder()
.setBootstrap(bootstrap)
.setProtocol(protocol)
.setDelay(Duration.ZERO)
.setOutboundMessage(new TestMessage(TEST_MESSAGE))
.setHost(ADDRESS_NAME)
.build();
//tests main function of ProbingAction
// tests main function of ProbingAction
ChannelFuture future = action.call();
//Tests to see if message is properly sent to remote server
// Tests to see if message is properly sent to remote server
nettyRule.assertReceivedMessage(TEST_MESSAGE);
future = future.syncUninterruptibly();
//Tests to see that, since server responds, we have set future to true
// Tests to see that, since server responds, we have set future to true
assertThat(future.isSuccess()).isTrue();
assertThat(((TestActionHandler) testHandler).getResponse().toString()).isEqualTo(TEST_MESSAGE);
}
}

View file

@ -31,24 +31,20 @@ import io.netty.channel.ChannelPromise;
* {@link ChannelHandler} used in tests to convert {@link OutboundMessageType} to to {@link
* ByteBuf}s and convert {@link ByteBuf}s to {@link InboundMessageType}
*
* <p>Specific type of {@link OutboundMessageType} and {@link InboundMessageType}
* used for conversion is the {@link TestMessage} type.</p>
* <p>Specific type of {@link OutboundMessageType} and {@link InboundMessageType} used for
* conversion is the {@link TestMessage} type.
*/
public class ConversionHandler extends ChannelDuplexHandler {
/**
* Handles inbound conversion
*/
/** Handles inbound conversion */
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buf = (ByteBuf) msg;
ctx.fireChannelRead(new TestMessage(buf.toString(UTF_8)));
buf.release();
}
/**
* Handles outbound conversion
*/
/** Handles outbound conversion */
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
throws Exception {
@ -57,4 +53,3 @@ public class ConversionHandler extends ChannelDuplexHandler {
super.write(ctx, buf, promise);
}
}

View file

@ -0,0 +1,240 @@
// Copyright 2019 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.monitoring.blackbox.handlers;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.JUnitBackports.assertThrows;
import google.registry.monitoring.blackbox.exceptions.EppClientException;
import google.registry.monitoring.blackbox.exceptions.FailureException;
import google.registry.monitoring.blackbox.exceptions.UndeterminedStateException;
import google.registry.monitoring.blackbox.messages.EppRequestMessage;
import google.registry.monitoring.blackbox.messages.EppResponseMessage;
import google.registry.monitoring.blackbox.util.EppUtils;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.embedded.EmbeddedChannel;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* Unit tests for {@link EppActionHandler} and {@link EppMessageHandler} as well as integration
* tests for both of them.
*
* <p>Attempts to test how well {@link EppActionHandler} works when responding to all possible types
* of {@link EppResponseMessage}s with corresponding {@link EppRequestMessage} sent down channel
* pipeline.
*/
@RunWith(Parameterized.class)
public class EppActionHandlerTest {
private static final String USER_ID = "TEST_ID";
private static final String USER_PASSWORD = "TEST_PASSWORD";
private static final String USER_CLIENT_TRID = "prober-localhost-1234567891011-0";
private static final String FAILURE_TRID = "TEST_FAILURE_TRID";
private static final String DOMAIN_NAME = "TEST_DOMAIN_NAME.test";
private static final String SERVER_ID = "TEST_SERVER_ID";
@Parameter(0)
public EppRequestMessage message;
private EmbeddedChannel channel;
private EppActionHandler actionHandler = new EppActionHandler();
private EppMessageHandler messageHandler = new EppMessageHandler(EppUtils.getGreetingResponse());
// We test all relevant EPP actions
@Parameters(name = "{0}")
public static EppRequestMessage[] data() {
return new EppRequestMessage[] {
EppUtils.getHelloMessage(EppUtils.getGreetingResponse()),
EppUtils.getLoginMessage(EppUtils.getSuccessResponse(), USER_ID, USER_PASSWORD),
EppUtils.getCreateMessage(EppUtils.getSuccessResponse()),
EppUtils.getCreateMessage(EppUtils.getFailureResponse()),
EppUtils.getDeleteMessage(EppUtils.getSuccessResponse()),
EppUtils.getDeleteMessage(EppUtils.getFailureResponse()),
EppUtils.getLogoutMessage(EppUtils.getSuccessResponse()),
EppUtils.getCheckMessage(EppUtils.getDomainExistsResponse()),
EppUtils.getCheckMessage(EppUtils.getDomainNotExistsResponse())
};
}
/** Setup main three handlers to be used in pipeline. */
@Before
public void setup() throws EppClientException {
message.modifyMessage(USER_CLIENT_TRID, DOMAIN_NAME);
}
private void setupEmbeddedChannel(ChannelHandler... handlers) {
channel = new EmbeddedChannel(handlers);
}
private Document getResponse(EppResponseMessage response, boolean fail, String clTrid)
throws IOException, EppClientException {
if (response.name().equals("greeting")) {
if (fail) {
return EppUtils.getBasicResponse(true, clTrid, SERVER_ID);
} else {
return EppUtils.getGreeting();
}
} else if (response.name().equals("domainExists")) {
return EppUtils.getDomainCheck(!fail, clTrid, SERVER_ID, DOMAIN_NAME);
} else if (response.name().equals("domainNotExists")) {
return EppUtils.getDomainCheck(fail, clTrid, SERVER_ID, DOMAIN_NAME);
} else if (response.name().equals("success")) {
return EppUtils.getBasicResponse(!fail, clTrid, SERVER_ID);
} else {
return EppUtils.getBasicResponse(fail, clTrid, SERVER_ID);
}
}
@Test
public void testBasicAction_Success_Embedded()
throws SAXException, IOException, EppClientException, FailureException {
// We simply use an embedded channel in this instance
setupEmbeddedChannel(actionHandler);
ChannelFuture future = actionHandler.getFinishedFuture();
EppResponseMessage response = message.getExpectedResponse();
response.getDocument(
EppUtils.docToByteBuf(getResponse(message.getExpectedResponse(), false, USER_CLIENT_TRID)));
channel.writeInbound(response);
ChannelFuture unusedFuture = future.syncUninterruptibly();
assertThat(future.isSuccess()).isTrue();
}
@Test
public void testBasicAction_FailCode_Embedded()
throws SAXException, IOException, EppClientException, FailureException {
// We simply use an embedded channel in this instance
setupEmbeddedChannel(actionHandler);
ChannelFuture future = actionHandler.getFinishedFuture();
EppResponseMessage response = message.getExpectedResponse();
response.getDocument(
EppUtils.docToByteBuf(getResponse(message.getExpectedResponse(), true, USER_CLIENT_TRID)));
channel.writeInbound(response);
assertThrows(
FailureException.class,
() -> {
ChannelFuture unusedFuture = future.syncUninterruptibly();
});
}
@Test
public void testBasicAction_FailTRID_Embedded()
throws SAXException, IOException, EppClientException, FailureException {
// We simply use an embedded channel in this instance
setupEmbeddedChannel(actionHandler);
ChannelFuture future = actionHandler.getFinishedFuture();
EppResponseMessage response = message.getExpectedResponse();
response.getDocument(
EppUtils.docToByteBuf(getResponse(message.getExpectedResponse(), false, FAILURE_TRID)));
channel.writeInbound(response);
if (message.getExpectedResponse().name().equals("greeting")) {
ChannelFuture unusedFuture = future.syncUninterruptibly();
assertThat(future.isSuccess()).isTrue();
} else {
assertThrows(
FailureException.class,
() -> {
ChannelFuture unusedFuture = future.syncUninterruptibly();
});
}
}
@Test
public void testIntegratedAction_Success_Embedded()
throws IOException, SAXException, UndeterminedStateException {
// We simply use an embedded channel in this instance
setupEmbeddedChannel(messageHandler, actionHandler);
ChannelFuture future = actionHandler.getFinishedFuture();
channel.writeOutbound(message);
channel.writeInbound(
EppUtils.docToByteBuf(getResponse(message.getExpectedResponse(), false, USER_CLIENT_TRID)));
ChannelFuture unusedFuture = future.syncUninterruptibly();
assertThat(future.isSuccess()).isTrue();
}
@Test
public void testIntegratedAction_FailCode_Embedded()
throws IOException, SAXException, UndeterminedStateException {
// We simply use an embedded channel in this instance
setupEmbeddedChannel(messageHandler, actionHandler);
ChannelFuture future = actionHandler.getFinishedFuture();
channel.writeOutbound(message);
channel.writeInbound(
EppUtils.docToByteBuf(getResponse(message.getExpectedResponse(), true, USER_CLIENT_TRID)));
assertThrows(
FailureException.class,
() -> {
ChannelFuture unusedFuture = future.syncUninterruptibly();
});
}
@Test
public void testIntegratedAction_FailTRID_Embedded()
throws IOException, SAXException, UndeterminedStateException {
// We simply use an embedded channel in this instance
setupEmbeddedChannel(messageHandler, actionHandler);
ChannelFuture future = actionHandler.getFinishedFuture();
channel.writeOutbound(message);
channel.writeInbound(
EppUtils.docToByteBuf(getResponse(message.getExpectedResponse(), false, FAILURE_TRID)));
if (message.getExpectedResponse().name().equals("greeting")) {
ChannelFuture unusedFuture = future.syncUninterruptibly();
assertThat(future.isSuccess()).isTrue();
} else {
assertThrows(
FailureException.class,
() -> {
ChannelFuture unusedFuture = future.syncUninterruptibly();
});
}
}
}

View file

@ -16,8 +16,8 @@ package google.registry.monitoring.blackbox.handlers;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.monitoring.blackbox.ProbingAction.REMOTE_ADDRESS_KEY;
import static google.registry.monitoring.blackbox.Protocol.PROTOCOL_KEY;
import static google.registry.monitoring.blackbox.connection.ProbingAction.REMOTE_ADDRESS_KEY;
import static google.registry.monitoring.blackbox.connection.Protocol.PROTOCOL_KEY;
import static google.registry.testing.JUnitBackports.assertThrows;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -25,9 +25,9 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.truth.ThrowableSubject;
import google.registry.monitoring.blackbox.ProbingActionTest;
import google.registry.monitoring.blackbox.ProbingStepTest;
import google.registry.monitoring.blackbox.Protocol;
import google.registry.monitoring.blackbox.connection.ProbingActionTest;
import google.registry.monitoring.blackbox.connection.Protocol;
import google.registry.monitoring.blackbox.testservers.TestServer;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
@ -51,18 +51,18 @@ import org.junit.rules.ExternalResource;
/**
* Helper for setting up and testing client / server connection with netty.
*
* <p>Code based on and almost identical to {@code NettyRule} in the proxy.
* Used in {@link SslClientInitializerTest}, {@link ProbingActionTest}, and {@link ProbingStepTest}
* </p>
* <p>Code based on and almost identical to {@code NettyRule} in the proxy. Used in {@link
* SslClientInitializerTest}, {@link ProbingActionTest}, and {@link ProbingStepTest}
*/
public final class NettyRule extends ExternalResource {
private final EventLoopGroup eventLoopGroup;
// Handler attached to server's channel to record the request received.
private EchoHandler echoHandler;
// Handler attached to client's channel to record the response received.
private DumpHandler dumpHandler;
private Channel channel;
// All I/O operations are done inside the single thread within this event loop group, which is
@ -81,25 +81,20 @@ public final class NettyRule extends ExternalResource {
channel.writeAndFlush(Unpooled.wrappedBuffer(data.getBytes(US_ASCII)));
}
/**
* Sets up a server channel bound to the given local address.
*/
/** Sets up a server channel bound to the given local address. */
public void setUpServer(LocalAddress localAddress, ChannelHandler... handlers) {
checkState(echoHandler == null, "Can't call setUpServer twice");
echoHandler = new EchoHandler();
new TestServer(eventLoopGroup, localAddress,
new TestServer(
eventLoopGroup,
localAddress,
ImmutableList.<ChannelHandler>builder().add(handlers).add(echoHandler).build());
}
/**
* Sets up a client channel connecting to the give local address.
*/
/** Sets up a client channel connecting to the give local address. */
void setUpClient(
LocalAddress localAddress,
Protocol protocol,
String host,
ChannelHandler handler) {
LocalAddress localAddress, Protocol protocol, String host, ChannelHandler handler) {
checkState(echoHandler != null, "Must call setUpServer before setUpClient");
checkState(dumpHandler == null, "Can't call setUpClient twice");
dumpHandler = new DumpHandler();
@ -128,20 +123,17 @@ public final class NettyRule extends ExternalResource {
checkState(channel != null, "Must call setUpClient to finish NettyRule setup");
}
/**
* Test that custom setup to send message to current server sends right message
*/
/** Test that custom setup to send message to current server sends right message */
public void assertReceivedMessage(String message) throws Exception {
assertThat(echoHandler.getRequestFuture().get()).isEqualTo(message);
}
/**
* Test that a message can go through, both inbound and outbound.
*
* <p>The client writes the message to the server, which echos it back and saves the string in
* its promise. The client receives the echo and saves it in its promise. All these activities
* happens in the I/O thread, and this call itself returns immediately.
* <p>The client writes the message to the server, which echos it back and saves the string in its
* promise. The client receives the echo and saves it in its promise. All these activities happens
* in the I/O thread, and this call itself returns immediately.
*/
void assertThatMessagesWork() throws Exception {
checkReady();
@ -199,9 +191,7 @@ public final class NettyRule extends ExternalResource {
ctx.writeAndFlush(msg).addListener(f -> requestFuture.complete(request));
}
/**
* Saves any inbound error as the cause of the promise failure.
*/
/** Saves any inbound error as the cause of the promise failure. */
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ChannelFuture unusedFuture =
@ -209,9 +199,7 @@ public final class NettyRule extends ExternalResource {
}
}
/**
* A handler that dumps its inbound message to a promise that can be inspected later.
*/
/** A handler that dumps its inbound message to a promise that can be inspected later. */
private static class DumpHandler extends ChannelInboundHandlerAdapter {
private final CompletableFuture<String> responseFuture = new CompletableFuture<>();
@ -232,13 +220,10 @@ public final class NettyRule extends ExternalResource {
responseFuture.complete(response);
}
/**
* Saves any inbound error into the failure cause of the promise.
*/
/** Saves any inbound error into the failure cause of the promise. */
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.channel().closeFuture().addListener(f -> responseFuture.completeExceptionally(cause));
}
}
}

View file

@ -15,14 +15,14 @@
package google.registry.monitoring.blackbox.handlers;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.monitoring.blackbox.ProbingAction.REMOTE_ADDRESS_KEY;
import static google.registry.monitoring.blackbox.Protocol.PROTOCOL_KEY;
import static google.registry.monitoring.blackbox.connection.ProbingAction.REMOTE_ADDRESS_KEY;
import static google.registry.monitoring.blackbox.connection.Protocol.PROTOCOL_KEY;
import static google.registry.monitoring.blackbox.handlers.SslInitializerTestUtils.getKeyPair;
import static google.registry.monitoring.blackbox.handlers.SslInitializerTestUtils.setUpSslChannel;
import static google.registry.monitoring.blackbox.handlers.SslInitializerTestUtils.signKeyPair;
import com.google.common.collect.ImmutableList;
import google.registry.monitoring.blackbox.Protocol;
import google.registry.monitoring.blackbox.connection.Protocol;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.embedded.EmbeddedChannel;
@ -62,39 +62,33 @@ import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class SslClientInitializerTest {
/**
* Fake host to test if the SSL engine gets the correct peer host.
*/
/** Fake host to test if the SSL engine gets the correct peer host. */
private static final String SSL_HOST = "www.example.tld";
/**
* Fake port to test if the SSL engine gets the correct peer port.
*/
/** Fake port to test if the SSL engine gets the correct peer port. */
private static final int SSL_PORT = 12345;
/**
* Fake protocol saved in channel attribute.
*/
private static final Protocol PROTOCOL = Protocol.builder()
.setName("ssl")
.setPort(SSL_PORT)
.setHandlerProviders(ImmutableList.of())
.setPersistentConnection(false)
.build();
@Rule
public NettyRule nettyRule = new NettyRule();
/** Fake protocol saved in channel attribute. */
private static final Protocol PROTOCOL =
Protocol.builder()
.setName("ssl")
.setPort(SSL_PORT)
.setHandlerProviders(ImmutableList.of())
.setPersistentConnection(false)
.build();
@Rule public NettyRule nettyRule = new NettyRule();
@Parameter(0)
public SslProvider sslProvider;
/**
* Saves the SNI hostname received by the server, if sent by the client.
*/
/** Saves the SNI hostname received by the server, if sent by the client. */
private String sniHostReceived;
// We do our best effort to test all available SSL providers.
@Parameters(name = "{0}")
public static SslProvider[] data() {
return OpenSsl.isAvailable()
? new SslProvider[]{SslProvider.JDK, SslProvider.OPENSSL}
: new SslProvider[]{SslProvider.JDK};
? new SslProvider[] {SslProvider.JDK, SslProvider.OPENSSL}
: new SslProvider[] {SslProvider.JDK};
}
private ChannelHandler getServerHandler(PrivateKey privateKey, X509Certificate certificate)
@ -170,7 +164,7 @@ public class SslClientInitializerTest {
// Set up the client to trust the self signed cert used to sign the cert that server provides.
SslClientInitializer<LocalChannel> sslClientInitializer =
new SslClientInitializer<>(sslProvider, new X509Certificate[]{ssc.cert()});
new SslClientInitializer<>(sslProvider, new X509Certificate[] {ssc.cert()});
nettyRule.setUpClient(localAddress, PROTOCOL, SSL_HOST, sslClientInitializer);
@ -199,7 +193,7 @@ public class SslClientInitializerTest {
// Set up the client to trust the self signed cert used to sign the cert that server provides.
SslClientInitializer<LocalChannel> sslClientInitializer =
new SslClientInitializer<>(sslProvider, new X509Certificate[]{ssc.cert()});
new SslClientInitializer<>(sslProvider, new X509Certificate[] {ssc.cert()});
nettyRule.setUpClient(localAddress, PROTOCOL, SSL_HOST, sslClientInitializer);
@ -211,4 +205,3 @@ public class SslClientInitializerTest {
assertThat(nettyRule.getChannel().isActive()).isFalse();
}
}

View file

@ -33,9 +33,7 @@ import javax.security.auth.x500.X500Principal;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;
/**
* Utility class that provides methods used by {@link SslClientInitializerTest}
*/
/** Utility class that provides methods used by {@link SslClientInitializerTest} */
public class SslInitializerTestUtils {
static {
@ -74,10 +72,7 @@ public class SslInitializerTestUtils {
* @param certs The certificate that the server should provide.
* @return The SSL session in current channel, can be used for further validation.
*/
static SSLSession setUpSslChannel(
Channel channel,
X509Certificate... certs)
throws Exception {
static SSLSession setUpSslChannel(Channel channel, X509Certificate... certs) throws Exception {
SslHandler sslHandler = channel.pipeline().get(SslHandler.class);
// Wait till the handshake is complete.
sslHandler.handshakeFuture().get();
@ -92,4 +87,3 @@ public class SslInitializerTestUtils {
return sslHandler.engine().getSession();
}
}

View file

@ -37,6 +37,4 @@ public class TestActionHandler extends ActionHandler {
public InboundMessageType getResponse() {
return receivedMessage;
}
}

View file

@ -15,14 +15,14 @@
package google.registry.monitoring.blackbox.handlers;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.monitoring.blackbox.ProbingAction.CONNECTION_FUTURE_KEY;
import static google.registry.monitoring.blackbox.Protocol.PROTOCOL_KEY;
import static google.registry.monitoring.blackbox.TestUtils.makeHttpGetRequest;
import static google.registry.monitoring.blackbox.TestUtils.makeHttpResponse;
import static google.registry.monitoring.blackbox.TestUtils.makeRedirectResponse;
import static google.registry.monitoring.blackbox.connection.ProbingAction.CONNECTION_FUTURE_KEY;
import static google.registry.monitoring.blackbox.connection.Protocol.PROTOCOL_KEY;
import static google.registry.monitoring.blackbox.util.WebWhoisUtils.makeHttpGetRequest;
import static google.registry.monitoring.blackbox.util.WebWhoisUtils.makeHttpResponse;
import static google.registry.monitoring.blackbox.util.WebWhoisUtils.makeRedirectResponse;
import com.google.common.collect.ImmutableList;
import google.registry.monitoring.blackbox.Protocol;
import google.registry.monitoring.blackbox.connection.Protocol;
import google.registry.monitoring.blackbox.exceptions.FailureException;
import google.registry.monitoring.blackbox.messages.HttpRequestMessage;
import google.registry.monitoring.blackbox.messages.HttpResponseMessage;
@ -45,8 +45,8 @@ import org.junit.runners.JUnit4;
/**
* Unit tests for {@link WebWhoisActionHandler}.
*
* <p>Attempts to test how well {@link WebWhoisActionHandler} works
* when responding to all possible types of responses </p>
* <p>Attempts to test how well {@link WebWhoisActionHandler} works when responding to all possible
* types of responses
*/
@RunWith(JUnit4.class)
public class WebWhoisActionHandlerTest {
@ -55,14 +55,14 @@ public class WebWhoisActionHandlerTest {
private static final String HTTP_REDIRECT = "http://";
private static final String TARGET_HOST = "whois.nic.tld";
private static final String DUMMY_URL = "__WILL_NOT_WORK__";
private final Protocol standardProtocol = Protocol.builder()
.setHandlerProviders(ImmutableList.of(() -> new WebWhoisActionHandler(
null, null, null, null)))
.setName("http")
.setPersistentConnection(false)
.setPort(HTTP_PORT)
.build();
private final Protocol standardProtocol =
Protocol.builder()
.setHandlerProviders(
ImmutableList.of(() -> new WebWhoisActionHandler(null, null, null, null)))
.setName("http")
.setPersistentConnection(false)
.setPort(HTTP_PORT)
.build();
private EmbeddedChannel channel;
private ActionHandler actionHandler;
@ -70,10 +70,7 @@ public class WebWhoisActionHandlerTest {
private Protocol initialProtocol;
private HttpRequestMessage msg;
/**
* Creates default protocol with empty list of handlers and specified other inputs
*/
/** Creates default protocol with empty list of handlers and specified other inputs */
private Protocol createProtocol(String name, int port, boolean persistentConnection) {
return Protocol.builder()
.setName(name)
@ -83,22 +80,14 @@ public class WebWhoisActionHandlerTest {
.build();
}
/**
* Initializes new WebWhoisActionHandler
*/
/** Initializes new WebWhoisActionHandler */
private void setupActionHandler(Bootstrap bootstrap, HttpRequestMessage messageTemplate) {
actionHandler = new WebWhoisActionHandler(
bootstrap,
standardProtocol,
standardProtocol,
messageTemplate
);
actionHandler =
new WebWhoisActionHandler(bootstrap, standardProtocol, standardProtocol, messageTemplate);
actionHandlerProvider = () -> actionHandler;
}
/**
* Sets up testing channel with requisite attributes
*/
/** Sets up testing channel with requisite attributes */
private void setupChannel(Protocol protocol) {
channel = new EmbeddedChannel(actionHandler);
channel.attr(PROTOCOL_KEY).set(protocol);
@ -106,43 +95,39 @@ public class WebWhoisActionHandlerTest {
}
private Bootstrap makeBootstrap(EventLoopGroup group) {
return new Bootstrap()
.group(group)
.channel(LocalChannel.class);
return new Bootstrap().group(group).channel(LocalChannel.class);
}
private void setup(String hostName, Bootstrap bootstrap, boolean persistentConnection) {
msg = new HttpRequestMessage(makeHttpGetRequest(hostName, ""));
setupActionHandler(bootstrap, msg);
initialProtocol = createProtocol("testProtocol", 0, persistentConnection);
}
@Test
public void testBasic_responseOk() {
//setup
// setup
setup("", null, true);
setupChannel(initialProtocol);
//stores future
// stores future
ChannelFuture future = actionHandler.getFinishedFuture();
channel.writeOutbound(msg);
FullHttpResponse response = new HttpResponseMessage(makeHttpResponse(HttpResponseStatus.OK));
//assesses that future listener isn't triggered yet.
// assesses that future listener isn't triggered yet.
assertThat(future.isDone()).isFalse();
channel.writeInbound(response);
//assesses that we successfully received good response and protocol is unchanged
// assesses that we successfully received good response and protocol is unchanged
assertThat(future.isSuccess()).isTrue();
}
@Test
public void testBasic_responseFailure_badRequest() {
//setup
// setup
setup("", null, false);
setupChannel(initialProtocol);
@ -150,8 +135,8 @@ public class WebWhoisActionHandlerTest {
ChannelFuture future = actionHandler.getFinishedFuture();
channel.writeOutbound(msg);
FullHttpResponse response = new HttpResponseMessage(
makeHttpResponse(HttpResponseStatus.BAD_REQUEST));
FullHttpResponse response =
new HttpResponseMessage(makeHttpResponse(HttpResponseStatus.BAD_REQUEST));
// Assesses that future listener isn't triggered yet.
assertThat(future.isDone()).isFalse();
@ -168,23 +153,24 @@ public class WebWhoisActionHandlerTest {
@Test
public void testBasic_responseFailure_badURL() {
//setup
// setup
setup("", null, false);
setupChannel(initialProtocol);
//stores future
// stores future
ChannelFuture future = actionHandler.getFinishedFuture();
channel.writeOutbound(msg);
FullHttpResponse response = new HttpResponseMessage(
makeRedirectResponse(HttpResponseStatus.MOVED_PERMANENTLY, DUMMY_URL, true));
FullHttpResponse response =
new HttpResponseMessage(
makeRedirectResponse(HttpResponseStatus.MOVED_PERMANENTLY, DUMMY_URL, true));
//assesses that future listener isn't triggered yet.
// assesses that future listener isn't triggered yet.
assertThat(future.isDone()).isFalse();
channel.writeInbound(response);
//assesses that listener is triggered, and event is success
// assesses that listener is triggered, and event is success
assertThat(future.isDone()).isTrue();
assertThat(future.isSuccess()).isFalse();
@ -204,7 +190,7 @@ public class WebWhoisActionHandlerTest {
// Initializes LocalAddress with unique String.
LocalAddress address = new LocalAddress(TARGET_HOST);
//stores future
// stores future
ChannelFuture future = actionHandler.getFinishedFuture();
channel.writeOutbound(msg);
@ -215,18 +201,19 @@ public class WebWhoisActionHandlerTest {
TestServer.webWhoisServer(group, address, "", TARGET_HOST, path);
FullHttpResponse response =
new HttpResponseMessage(makeRedirectResponse(HttpResponseStatus.MOVED_PERMANENTLY,
HTTP_REDIRECT + TARGET_HOST + path, true));
new HttpResponseMessage(
makeRedirectResponse(
HttpResponseStatus.MOVED_PERMANENTLY, HTTP_REDIRECT + TARGET_HOST + path, true));
//checks that future has not been set to successful or a failure
// checks that future has not been set to successful or a failure
assertThat(future.isDone()).isFalse();
channel.writeInbound(response);
//makes sure old channel is shut down when attempting redirection
// makes sure old channel is shut down when attempting redirection
assertThat(channel.isActive()).isFalse();
//assesses that we successfully received good response and protocol is unchanged
// assesses that we successfully received good response and protocol is unchanged
assertThat(future.syncUninterruptibly().isSuccess()).isTrue();
}
}

View file

@ -0,0 +1,223 @@
// Copyright 2019 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.monitoring.blackbox.messages;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.JUnitBackports.assertThrows;
import static java.nio.charset.StandardCharsets.UTF_8;
import google.registry.monitoring.blackbox.exceptions.EppClientException;
import google.registry.monitoring.blackbox.exceptions.FailureException;
import google.registry.monitoring.blackbox.util.EppUtils;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
@RunWith(JUnit4.class)
public class EppMessageTest {
private Document xmlDoc = null;
private Document greeting = null;
private DocumentBuilder builder = null;
@Before
public void setUp() throws Exception {
String xmlString =
"<epp>"
+ "<textAndAttr myAttr1='1'>text1</textAndAttr>"
+ "<textNoAttr>text2</textNoAttr>"
+ "<attrNoText myAttr2='2'/>"
+ "<textAndAttrSplitRepeated>text3</textAndAttrSplitRepeated>"
+ "<textAndAttrSplitRepeated myAttr3='3'/>"
+ "</epp>";
ByteArrayInputStream byteStream = new ByteArrayInputStream(xmlString.getBytes(UTF_8));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
builder = factory.newDocumentBuilder();
xmlDoc = builder.parse(byteStream);
greeting = EppUtils.getGreeting();
}
@Test
public void xmlDocToStringSuccess() throws Exception {
Document xml = builder.newDocument();
Element doc = xml.createElement("doc");
Element title = xml.createElement("title");
title.setTextContent("test");
Element meta = xml.createElement("meta");
meta.setAttribute("version", "1.0");
doc.appendChild(title);
doc.appendChild(meta);
xml.appendChild(doc);
// note that setting the version just ensures this will either be the same in the result,
// or the result won't support the version and this will throw an exception.
xml.setXmlVersion("1.0");
// setting stand alone to true removes this from the processing instructions
xml.setXmlStandalone(true);
String expected =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<doc><title>test</title><meta version=\"1.0\"/></doc>";
String actual = EppMessage.xmlDocToString(xml);
assertThat(actual).isEqualTo(expected);
}
@Test
public void xmlDoctoByteArraySuccess() throws Exception {
Document xml = builder.newDocument();
Element doc = xml.createElement("doc");
Element title = xml.createElement("title");
title.setTextContent("test");
Element meta = xml.createElement("meta");
meta.setAttribute("version", "1.0");
doc.appendChild(title);
doc.appendChild(meta);
xml.appendChild(doc);
// note that setting the version just ensures this will either be the same in the result,
// or the result won't support the version and this will throw an exception.
xml.setXmlVersion("1.0");
// setting stand alone to true removes this from the processing instructions
xml.setXmlStandalone(true);
String expected =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<doc><title>test</title><meta version=\"1.0\"/></doc>";
byte[] actual = EppMessage.xmlDocToByteArray(xml);
assertThat(actual).isEqualTo(expected.getBytes(UTF_8));
}
@Test
public void eppValidateSuccess() throws Exception {
EppMessage.eppValidate(greeting);
}
@Test
public void eppValidateFail() {
assertThrows(SAXException.class, () -> EppMessage.eppValidate(xmlDoc));
}
/**
* These test a "success" without validating a document. This is to make it easier to test the
* XPath part of the verify in isolation. See EppClientConnectionTest for tests that verify an
* actual (greeting) respoonse.
*/
@Test
public void verifyResponseSuccess() throws Exception {
ArrayList<String> list = new ArrayList<>();
list.add("epp");
list.add("//textAndAttr[@myAttr1='1'] | //textAndAttr[child::text()='text1']");
list.add("//textAndAttr[child::text()='text1']");
list.add("//textAndAttr/@myAttr1");
list.add("//textAndAttrSplitRepeated[@myAttr3='3']");
EppMessage.verifyEppResponse(xmlDoc, list, false);
}
@Test
public void verifyEppResponseSuccess() throws Exception {
ArrayList<String> list = new ArrayList<>();
list.add("*");
list.add("/eppns:epp");
list.add("/eppns:epp/eppns:greeting");
list.add("//eppns:greeting");
list.add("//eppns:svID");
EppMessage.verifyEppResponse(greeting, list, false);
}
@Test
public void verifyResponseMissingTextFail() {
ArrayList<String> list = new ArrayList<>();
list.add("epp");
list.add("//textAndAttr[child::text()='text2']");
assertThrows(FailureException.class, () -> EppMessage.verifyEppResponse(xmlDoc, list, false));
}
@Test
public void verifyResponseMissingAttrFail() {
ArrayList<String> list = new ArrayList<>();
list.add("epp");
list.add("//textAndAttr/@myAttr2");
assertThrows(FailureException.class, () -> EppMessage.verifyEppResponse(xmlDoc, list, false));
}
@Test
public void verifyResponseSplitTextAttrFail() {
ArrayList<String> list = new ArrayList<>();
list.add("epp");
list.add("//textAndAttrSplitRepeated[@myAttr3='3'][child::text()='text3']");
assertThrows(FailureException.class, () -> EppMessage.verifyEppResponse(xmlDoc, list, false));
}
@Test
public void getEppDocFromTemplateTest() throws Exception {
Map<String, String> replaceMap = new HashMap<>();
replaceMap.put("//eppns:expectedClTRID", "ABC-1234-CBA");
replaceMap.put("//domainns:name", "foo");
replaceMap.put("//domainns:pw", "bar");
Document epp = EppMessage.getEppDocFromTemplate("create.xml", replaceMap);
List<String> noList = Collections.emptyList();
EppMessage.verifyEppResponse(epp, noList, true);
}
@Test
public void getEppDocFromTemplateTestFail() {
Map<String, String> replaceMap = new HashMap<>();
replaceMap.put("//eppns:create", "ABC-1234-CBA");
replaceMap.put("//domainns:name", "foo");
replaceMap.put("//domainns:pw", "bar");
assertThrows(
EppClientException.class, () -> EppMessage.getEppDocFromTemplate("create.xml", replaceMap));
}
@Test
public void checkValidDomainName() {
String domainName = "good.tld";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isTrue();
domainName = "good.tld.";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isTrue();
domainName = "g-o-o-d.tld.";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isTrue();
domainName = "good.cc.tld";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isTrue();
domainName = "good.cc.tld.";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isTrue();
domainName = "too-short";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isFalse();
domainName = "too-short.";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isFalse();
// TODO(rgr): sync up how many dots is actually too many
domainName = "too.many.dots.tld.";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isFalse();
domainName = "too.many.dots.tld";
assertThat(domainName.matches(EppMessage.VALID_SLD_LABEL_REGEX)).isFalse();
}
}

View file

@ -14,17 +14,22 @@
package google.registry.monitoring.blackbox.testservers;
import static google.registry.monitoring.blackbox.TestUtils.makeHttpResponse;
import static google.registry.monitoring.blackbox.TestUtils.makeRedirectResponse;
import static google.registry.monitoring.blackbox.util.WebWhoisUtils.makeHttpResponse;
import static google.registry.monitoring.blackbox.util.WebWhoisUtils.makeRedirectResponse;
import com.google.common.collect.ImmutableList;
import google.registry.monitoring.blackbox.exceptions.FailureException;
import google.registry.monitoring.blackbox.messages.EppMessage;
import google.registry.monitoring.blackbox.messages.HttpResponseMessage;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.local.LocalAddress;
@ -34,6 +39,7 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.w3c.dom.Document;
/**
* Mock Server Superclass whose subclasses implement specific behaviors we expect blackbox server to
@ -45,18 +51,21 @@ public class TestServer {
this(new NioEventLoopGroup(1), localAddress, handlers);
}
public TestServer(EventLoopGroup eventLoopGroup, LocalAddress localAddress,
public TestServer(
EventLoopGroup eventLoopGroup,
LocalAddress localAddress,
ImmutableList<? extends ChannelHandler> handlers) {
//Creates ChannelInitializer with handlers specified
ChannelInitializer<LocalChannel> serverInitializer = new ChannelInitializer<LocalChannel>() {
@Override
protected void initChannel(LocalChannel ch) {
for (ChannelHandler handler : handlers) {
ch.pipeline().addLast(handler);
}
}
};
//Sets up serverBootstrap with specified initializer, eventLoopGroup, and using
// Creates ChannelInitializer with handlers specified
ChannelInitializer<LocalChannel> serverInitializer =
new ChannelInitializer<LocalChannel>() {
@Override
protected void initChannel(LocalChannel ch) {
for (ChannelHandler handler : handlers) {
ch.pipeline().addLast(handler);
}
}
};
// Sets up serverBootstrap with specified initializer, eventLoopGroup, and using
// LocalServerChannel class
ServerBootstrap serverBootstrap =
new ServerBootstrap()
@ -65,22 +74,27 @@ public class TestServer {
.childHandler(serverInitializer);
ChannelFuture unusedFuture = serverBootstrap.bind(localAddress).syncUninterruptibly();
}
public static TestServer webWhoisServer(EventLoopGroup eventLoopGroup,
LocalAddress localAddress, String redirectInput, String destinationInput,
public static TestServer webWhoisServer(
EventLoopGroup eventLoopGroup,
LocalAddress localAddress,
String redirectInput,
String destinationInput,
String destinationPath) {
return new TestServer(
eventLoopGroup,
localAddress,
ImmutableList.of(new RedirectHandler(redirectInput, destinationInput, destinationPath))
);
ImmutableList.of(new RedirectHandler(redirectInput, destinationInput, destinationPath)));
}
/**
* Handler that will wither redirect client, give successful response, or give error messge
*/
public static TestServer eppServer(EventLoopGroup eventLoopGroup, LocalAddress localAddress) {
// TODO - add LengthFieldBasedFrameDecoder to handlers in pipeline if necessary for future
// tests.
return new TestServer(eventLoopGroup, localAddress, ImmutableList.of(new EppHandler()));
}
/** Handler that will wither redirect client, give successful response, or give error messge */
@Sharable
static class RedirectHandler extends SimpleChannelInboundHandler<HttpRequest> {
@ -90,9 +104,9 @@ public class TestServer {
/**
* @param redirectInput - Server will send back redirect to {@code destinationInput} when
* receiving a request with this host location
* receiving a request with this host location
* @param destinationInput - Server will send back an {@link HttpResponseStatus} OK response
* when receiving a request with this host location
* when receiving a request with this host location
*/
public RedirectHandler(String redirectInput, String destinationInput, String destinationPath) {
this.redirectInput = redirectInput;
@ -108,8 +122,9 @@ public class TestServer {
public void channelRead0(ChannelHandlerContext ctx, HttpRequest request) {
HttpResponse response;
if (request.headers().get("host").equals(redirectInput)) {
response = new HttpResponseMessage(
makeRedirectResponse(HttpResponseStatus.MOVED_PERMANENTLY, destinationInput, true));
response =
new HttpResponseMessage(
makeRedirectResponse(HttpResponseStatus.MOVED_PERMANENTLY, destinationInput, true));
} else if (request.headers().get("host").equals(destinationInput)
&& request.uri().equals(destinationPath)) {
response = new HttpResponseMessage(makeHttpResponse(HttpResponseStatus.OK));
@ -117,7 +132,36 @@ public class TestServer {
response = new HttpResponseMessage(makeHttpResponse(HttpResponseStatus.BAD_REQUEST));
}
ChannelFuture unusedFuture = ctx.channel().writeAndFlush(response);
}
}
private static class EppHandler extends ChannelDuplexHandler {
Document doc;
private ChannelPromise future;
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
// TODO - pass EppMessage into future to easily read attributes of message.
future = ctx.newPromise();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buf = (ByteBuf) msg;
byte[] messageBytes = new byte[buf.readableBytes()];
buf.readBytes(messageBytes);
// TODO - Break ByteBuf into multiple pieces to test how well it works with
// LengthFieldBasedFrameDecoder.
try {
doc = EppMessage.byteArrayToXmlDoc(messageBytes);
ChannelFuture unusedFuture = future.setSuccess();
} catch (FailureException e) {
ChannelFuture unusedFuture = future.setFailure(e);
}
}
}
}

View file

@ -0,0 +1,91 @@
// Copyright 2019 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.monitoring.blackbox.tokens;
import static com.google.common.truth.Truth.assertThat;
import google.registry.monitoring.blackbox.exceptions.UndeterminedStateException;
import google.registry.monitoring.blackbox.messages.EppRequestMessage;
import google.registry.monitoring.blackbox.util.EppUtils;
import io.netty.channel.Channel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;
/** Unit Tests for each {@link Token} subtype (just {@link WebWhoisToken} for now) */
@RunWith(JUnit4.class)
public class EppTokenTest {
private static String TEST_HOST = "host";
private static String TEST_TLD = "tld";
private EppToken persistentEppToken = new EppToken.Persistent(TEST_TLD, TEST_HOST);
private EppToken transientEppToken = new EppToken.Transient(TEST_TLD, TEST_HOST);
@Test
public void testMessageModificationSuccess_PersistentToken() throws UndeterminedStateException {
EppRequestMessage originalMessage = EppUtils.getCreateMessage(EppUtils.getSuccessResponse());
String domainName = persistentEppToken.getCurrentDomainName();
String clTrid = domainName.substring(0, domainName.indexOf('.'));
EppRequestMessage modifiedMessage =
(EppRequestMessage) persistentEppToken.modifyMessage(originalMessage);
// ensure element values are what they should be
assertThat(modifiedMessage.getElementValue("//domainns:name")).isEqualTo(domainName);
assertThat(modifiedMessage.getElementValue("//eppns:clTRID")).isNotEqualTo(clTrid);
}
@Test
public void testMessageModificationSuccess_TransientToken() throws UndeterminedStateException {
EppRequestMessage originalMessage = EppUtils.getCreateMessage(EppUtils.getSuccessResponse());
String domainName = transientEppToken.getCurrentDomainName();
String clTrid = domainName.substring(0, domainName.indexOf('.'));
EppRequestMessage modifiedMessage =
(EppRequestMessage) transientEppToken.modifyMessage(originalMessage);
// ensure element values are what they should be
assertThat(modifiedMessage.getElementValue("//domainns:name")).isEqualTo(domainName);
assertThat(modifiedMessage.getElementValue("//eppns:clTRID")).isNotEqualTo(clTrid);
}
@Test
public void testNext_persistentToken() {
String domainName = persistentEppToken.getCurrentDomainName();
Channel mockChannel = Mockito.mock(Channel.class);
persistentEppToken.setChannel(mockChannel);
EppToken nextToken = (EppToken) persistentEppToken.next();
assertThat(nextToken.getCurrentDomainName()).isNotEqualTo(domainName);
assertThat(nextToken.channel()).isEqualTo(mockChannel);
}
@Test
public void testNext_transientToken() {
String domainName = transientEppToken.getCurrentDomainName();
Channel mockChannel = Mockito.mock(Channel.class);
transientEppToken.setChannel(mockChannel);
EppToken nextToken = (EppToken) transientEppToken.next();
assertThat(nextToken.getCurrentDomainName()).isNotEqualTo(domainName);
assertThat(nextToken.channel()).isNull();
}
}

View file

@ -23,9 +23,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Unit Tests for {@link WebWhoisToken}
*/
/** Unit Tests for {@link WebWhoisToken} */
@RunWith(JUnit4.class)
public class WebWhoisTokenTest {
@ -35,19 +33,17 @@ public class WebWhoisTokenTest {
private static final String SECOND_TLD = "second_test";
private static final String THIRD_TLD = "third_test";
private final CircularList<String> testDomains =
new CircularList.Builder<String>()
.add(FIRST_TLD, SECOND_TLD, THIRD_TLD)
.build();
new CircularList.Builder<String>().add(FIRST_TLD, SECOND_TLD, THIRD_TLD).build();
public Token webToken = new WebWhoisToken(testDomains);
@Test
public void testMessageModification() throws UndeterminedStateException {
//creates Request message with header
// creates Request message with header
HttpRequestMessage message = new HttpRequestMessage();
message.headers().set("host", HOST);
//attempts to use Token's method for modifying the method based on its stored host
// attempts to use Token's method for modifying the method based on its stored host
HttpRequestMessage secondMessage = (HttpRequestMessage) webToken.modifyMessage(message);
assertThat(secondMessage.headers().get("host")).isEqualTo(PREFIX + FIRST_TLD);
}
@ -69,5 +65,4 @@ public class WebWhoisTokenTest {
assertThat(webToken.host()).isEqualTo(PREFIX + FIRST_TLD);
}
}

View file

@ -0,0 +1,197 @@
// Copyright 2019 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.monitoring.blackbox.util;
import static google.registry.monitoring.blackbox.messages.EppMessage.CLIENT_ID_KEY;
import static google.registry.monitoring.blackbox.messages.EppMessage.CLIENT_PASSWORD_KEY;
import static google.registry.monitoring.blackbox.messages.EppMessage.CLIENT_TRID_KEY;
import static google.registry.monitoring.blackbox.messages.EppMessage.DOMAIN_KEY;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import google.registry.monitoring.blackbox.exceptions.EppClientException;
import google.registry.monitoring.blackbox.messages.EppMessage;
import google.registry.monitoring.blackbox.messages.EppRequestMessage;
import google.registry.monitoring.blackbox.messages.EppResponseMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.io.IOException;
import org.w3c.dom.Document;
/** Houses static utility functions for testing EPP components of Prober. */
public class EppUtils {
/** Return a simple default greeting as a {@link Document}. */
public static Document getGreeting() throws IOException, EppClientException {
return EppMessage.getEppDocFromTemplate("greeting.xml", ImmutableMap.of());
}
/**
* Return a basic response as a {@link Document}.
*
* @param success specifies if response shows a success or failure
* @param clTrid the client transaction ID
* @param svTrid the server transaction ID
* @return the EPP basic response as a {@link Document}.
*/
public static Document getBasicResponse(boolean success, String clTrid, String svTrid)
throws IOException, EppClientException {
String template = success ? "success_response.xml" : "failed_response.xml";
return EppMessage.getEppDocFromTemplate(
template,
ImmutableMap.of(
EppRequestMessage.CLIENT_TRID_KEY, clTrid, EppMessage.SERVER_TRID_KEY, svTrid));
}
/**
* Return a domain check response as a {@link Document}.
*
* @param exists specifies if response shows that domain name exists on server or doesn't
* @param clTrid the client transaction ID
* @param svTrid the server transaction ID
* @param domain the domain the check success is for
* @return the EPP check response as a {@link Document}.
*/
public static Document getDomainCheck(boolean exists, String clTrid, String svTrid, String domain)
throws IOException, EppClientException {
String template = exists ? "domain_exists.xml" : "domain_not_exists.xml";
return EppMessage.getEppDocFromTemplate(
template,
ImmutableMap.of(
EppRequestMessage.CLIENT_TRID_KEY, clTrid,
EppMessage.SERVER_TRID_KEY, svTrid,
EppMessage.DOMAIN_KEY, domain));
}
/** Converts {@link Document} to {@link ByteBuf}. */
public static ByteBuf docToByteBuf(Document message) throws EppClientException {
byte[] bytestream = EppMessage.xmlDocToByteArray(message);
ByteBuf buf = Unpooled.buffer(bytestream.length);
buf.writeBytes(bytestream);
return buf;
}
/** Returns standard hello request with supplied response. */
public static EppRequestMessage getHelloMessage(EppResponseMessage greetingResponse) {
return new EppRequestMessage(greetingResponse, null, (a, b) -> ImmutableMap.of());
}
/** Returns standard login request with supplied userId, userPassword, and response. */
public static EppRequestMessage getLoginMessage(
EppResponseMessage response, String userId, String userPassword) {
return new EppRequestMessage(
response,
"login.xml",
(clTrid, domain) ->
ImmutableMap.of(
CLIENT_TRID_KEY, clTrid,
CLIENT_ID_KEY, userId,
CLIENT_PASSWORD_KEY, userPassword));
}
/** Returns standard create request with supplied response. */
public static EppRequestMessage getCreateMessage(EppResponseMessage response) {
return new EppRequestMessage(
response,
"create.xml",
(clTrid, domain) ->
ImmutableMap.of(
CLIENT_TRID_KEY, clTrid,
DOMAIN_KEY, domain));
}
/** Returns standard delete request with supplied response. */
public static EppRequestMessage getDeleteMessage(EppResponseMessage response) {
return new EppRequestMessage(
response,
"delete.xml",
(clTrid, domain) ->
ImmutableMap.of(
CLIENT_TRID_KEY, clTrid,
DOMAIN_KEY, domain));
}
/** Returns standard logout request with supplied response. */
public static EppRequestMessage getLogoutMessage(EppResponseMessage successResponse) {
return new EppRequestMessage(
successResponse,
"logout.xml",
(clTrid, domain) -> ImmutableMap.of(CLIENT_TRID_KEY, clTrid));
}
/** Returns standard check request with supplied response. */
public static EppRequestMessage getCheckMessage(EppResponseMessage response) {
return new EppRequestMessage(
response,
"check.xml",
(clTrid, domain) ->
ImmutableMap.of(
CLIENT_TRID_KEY, clTrid,
DOMAIN_KEY, domain));
}
/** Returns standard success response. */
public static EppResponseMessage getSuccessResponse() {
return new EppResponseMessage(
"success",
(clTrid, domain) ->
ImmutableList.of(
String.format("//eppns:clTRID[.='%s']", clTrid), EppMessage.XPASS_EXPRESSION));
}
/** Returns standard failure response. */
public static EppResponseMessage getFailureResponse() {
return new EppResponseMessage(
"failure",
(clTrid, domain) ->
ImmutableList.of(
String.format("//eppns:clTRID[.='%s']", clTrid), EppMessage.XFAIL_EXPRESSION));
}
/** Returns standard domainExists response. */
public static EppResponseMessage getDomainExistsResponse() {
return new EppResponseMessage(
"domainExists",
(clTrid, domain) ->
ImmutableList.of(
String.format("//eppns:clTRID[.='%s']", clTrid),
String.format("//domainns:name[@avail='false'][.='%s']", domain),
EppMessage.XPASS_EXPRESSION));
}
/** Returns standard domainNotExists response. */
public static EppResponseMessage getDomainNotExistsResponse() {
return new EppResponseMessage(
"domainNotExists",
(clTrid, domain) ->
ImmutableList.of(
String.format("//eppns:clTRID[.='%s']", clTrid),
String.format("//domainns:name[@avail='true'][.='%s']", domain),
EppMessage.XPASS_EXPRESSION));
}
/** Returns standard greeting response. */
public static EppResponseMessage getGreetingResponse() {
return new EppResponseMessage(
"greeting", (clTrid, domain) -> ImmutableList.of("//eppns:greeting"));
}
}

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.monitoring.blackbox;
package google.registry.monitoring.blackbox.util;
import static java.nio.charset.StandardCharsets.US_ASCII;
@ -26,10 +26,8 @@ import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
/**
* Utility class for various helper methods used in testing.
*/
public class TestUtils {
/** Houses static utility functions for testing WebWHOIS components of Prober. */
public class WebWhoisUtils {
public static FullHttpRequest makeHttpGetRequest(String host, String path) {
FullHttpRequest request =
@ -51,9 +49,7 @@ public class TestUtils {
return response;
}
/**
* Creates HttpResponse given status, redirection location, and other necessary inputs
*/
/** Creates HttpResponse given status, redirection location, and other necessary inputs */
public static FullHttpResponse makeRedirectResponse(
HttpResponseStatus status, String location, boolean keepAlive) {
FullHttpResponse response = makeHttpResponse("", status);
@ -67,4 +63,3 @@ public class TestUtils {
return response;
}
}