### Question:
AwaitingCycle3DataStateController extends AbstractAwaitingCycle3DataStateController<AttributeQueryRequestDto, AwaitingCycle3DataState> implements StateController, ResponseProcessingStateController, ErrorResponsePreparedStateController { @Override public void handleCycle3DataSubmitted(final String principalIpAddressAsSeenByHub) { getHubEventLogger().logCycle3DataObtained( getState().getSessionId(), getState().getRequestIssuerEntityId(), getState().getSessionExpiryTimestamp(), getState().getRequestId(), principalIpAddressAsSeenByHub ); Cycle3MatchRequestSentState cycle3MatchRequestSentState = new Cycle3MatchRequestSentState( getState().getRequestId(), getState().getRequestIssuerEntityId(), getState().getSessionExpiryTimestamp(), getState().getAssertionConsumerServiceUri(), getState().getSessionId(), getState().getTransactionSupportsEidas(), getState().getIdentityProviderEntityId(), getState().getRelayState().orElse(null), getState().getLevelOfAssurance(), getState().isRegistering(), getState().getMatchingServiceEntityId(), getState().getEncryptedMatchingDatasetAssertion(), getState().getAuthnStatementAssertion(), getState().getPersistentId() ); getStateTransitionAction().transitionTo(cycle3MatchRequestSentState); } AwaitingCycle3DataStateController(
        final AwaitingCycle3DataState state,
        final HubEventLogger hubEventLogger,
        final StateTransitionAction stateTransitionAction,
        final TransactionsConfigProxy transactionsConfigProxy,
        final ResponseFromHubFactory responseFromHubFactory,
        final PolicyConfiguration policyConfiguration,
        final AssertionRestrictionsFactory assertionRestrictionsFactory,
        final MatchingServiceConfigProxy matchingServiceConfigProxy); @Override AttributeQueryRequestDto createAttributeQuery(final Cycle3Dataset cycle3Dataset); @Override void handleCycle3DataSubmitted(final String principalIpAddressAsSeenByHub);  }### Answer:
@Test public void handleCycle3DataSubmitted_shouldLogCycle3DataObtainedAndPrincipalIpAddressSeenByHubToEventSink() { final SessionId sessionId = aSessionId().build(); final String principalIpAddressAsSeenByHub = "principal-ip-address-as-seen-by-hub"; final String requestId = "requestId"; final AwaitingCycle3DataStateController awaitingCycle3DataStateController = setUpAwaitingCycle3DataStateController(requestId, sessionId); awaitingCycle3DataStateController.handleCycle3DataSubmitted(principalIpAddressAsSeenByHub); ArgumentCaptor<EventSinkHubEvent> argumentCaptor = ArgumentCaptor.forClass(EventSinkHubEvent.class); verify(eventSinkProxy, atLeastOnce()).logHubEvent(argumentCaptor.capture()); Condition<EventSinkHubEvent> combinedConditions = AllOf.allOf( hasSessionId(sessionId), hasDetail(EventDetailsKey.session_event_type, CYCLE3_DATA_OBTAINED), hasDetail(EventDetailsKey.request_id, requestId), hasDetail(EventDetailsKey.principal_ip_address_as_seen_by_hub, principalIpAddressAsSeenByHub)); assertThat(argumentCaptor.getAllValues()).haveAtLeast(1, combinedConditions); }
@Test public void shouldMoveFromAwaitingC3StateToCycle3DataSentStateWhenCycle3DataIsReceived() { final SessionId sessionId = SessionId.createNewSessionId(); AwaitingCycle3DataState state = anAwaitingCycle3DataState().withSessionId(sessionId).build(); AwaitingCycle3DataStateController controller = new AwaitingCycle3DataStateController(state, hubEventLogger, stateTransitionAction, transactionsConfigProxy, responseFromHubFactory, policyConfiguration, assertionRestrictionsFactory, matchingServiceConfigProxy); ArgumentCaptor<Cycle3MatchRequestSentState> argumentCaptor = ArgumentCaptor.forClass(Cycle3MatchRequestSentState.class); controller.handleCycle3DataSubmitted("principalIpAsSeenByHub"); verify(stateTransitionAction, times(1)).transitionTo(argumentCaptor.capture()); final Cycle3MatchRequestSentState cycle3MatchRequestSentState = argumentCaptor.getValue(); assertThat(cycle3MatchRequestSentState.getEncryptedMatchingDatasetAssertion()).isEqualTo(state.getEncryptedMatchingDatasetAssertion()); }