Skip to content

Commit

Permalink
feature/AddonCancel (#45)
Browse files Browse the repository at this point in the history
* cancel event

* Event handler and parser for the event are hooked up

* Added unit test for the parser

* Sonar warnings

* unit test for the event dispatcher
  • Loading branch information
EmilDafinov authored and jpboudreault committed Jan 5, 2017
1 parent fca1758 commit cdb9c9f
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.appdirect.sdk.appmarket.events;

import java.util.Map;

import lombok.EqualsAndHashCode;
import lombok.Value;

/**
* A developer-facing event representing cancellation of an addon account requested by the AppMarket
*/
@Value
@EqualsAndHashCode(callSuper = true)
public class AddonSubscriptionCancel extends EventWithConsumerKeyQueryParametersAndEventFlag {
private final String accountIdentifier;
private final String parentAccountIdentifier;

public AddonSubscriptionCancel(String accountIdentifier,
String parentAccountIdentifier,
String consumerKeyUsedByTheRequest,
Map<String, String[]> queryParameters,
EventFlag flag) {

super(consumerKeyUsedByTheRequest, queryParameters, flag);
this.accountIdentifier = accountIdentifier;
this.parentAccountIdentifier = parentAccountIdentifier;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.appdirect.sdk.appmarket.events;

class AddonSubscriptionCancelEventParser implements EventParser<AddonSubscriptionCancel> {
@Override
public AddonSubscriptionCancel parse(EventInfo eventInfo, EventHandlingContext eventContext) {
return new AddonSubscriptionCancel(
eventInfo.getPayload().getAccount().getAccountIdentifier(),
eventInfo.getPayload().getAccount().getParentAccountIdentifier(),
eventContext.getConsumerKeyUsedByTheRequest(),
eventContext.getQueryParameters(),
eventInfo.getFlag()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,35 @@ class AppmarketEventDispatcher {
private final SDKEventHandler subscriptionCancelHandler;
private final SDKEventHandler subscriptionChangeHandler;
private final SDKEventHandler addonSubscriptionOrderHandler;
private final SDKEventHandler addonSubscriptionCancelHandler;
private final SDKEventHandler userAssignmentHandler;
private final SDKEventHandler userUnassignmentHandler;
private final SDKEventHandler unknownEventHandler;
private final AddonEventDetector addonDetector;

AppmarketEventDispatcher(Events events, AsyncEventHandler asyncHandler, SDKEventHandler subscriptionOrderHandler, SDKEventHandler subscriptionCancelHandler, SDKEventHandler subscriptionChangeHandler, SDKEventHandler subscriptionDeactivatedHandler, SDKEventHandler subscriptionReactivatedHandler, SDKEventHandler subscriptionClosedHandler, SDKEventHandler subscriptionUpcomingInvoiceHandler, SDKEventHandler addonSubscriptionOrderHandler, SDKEventHandler userAssignmentHandler, SDKEventHandler userUnassignmentHandler, SDKEventHandler unknownEventHandler, AddonEventDetector addonDetector) { // NOSONAR: ctor has too many params - This is for SDK use only.
AppmarketEventDispatcher(Events events, // NOSONAR: ctor has too many params - This is for SDK use only.
AsyncEventHandler asyncHandler,
SDKEventHandler subscriptionOrderHandler,
SDKEventHandler subscriptionCancelHandler,
SDKEventHandler subscriptionChangeHandler,
SDKEventHandler subscriptionDeactivatedHandler,
SDKEventHandler subscriptionReactivatedHandler,
SDKEventHandler subscriptionClosedHandler,
SDKEventHandler subscriptionUpcomingInvoiceHandler,
SDKEventHandler addonSubscriptionOrderHandler,
SDKEventHandler addonSubscriptionCancelHandler,
SDKEventHandler userAssignmentHandler,
SDKEventHandler userUnassignmentHandler,
SDKEventHandler unknownEventHandler,
AddonEventDetector addonDetector) {
this.events = events;
this.asyncHandler = asyncHandler;
this.subscriptionOrderHandler = subscriptionOrderHandler;
this.subscriptionCancelHandler = subscriptionCancelHandler;
this.subscriptionChangeHandler = subscriptionChangeHandler;
this.noticeEventsToHandlers = buildNoticeHandlersMap(subscriptionDeactivatedHandler, subscriptionReactivatedHandler, subscriptionClosedHandler, subscriptionUpcomingInvoiceHandler);
this.addonSubscriptionOrderHandler = addonSubscriptionOrderHandler;
this.addonSubscriptionCancelHandler = addonSubscriptionCancelHandler;
this.noticeEventsToHandlers = buildNoticeHandlersMap(subscriptionDeactivatedHandler, subscriptionReactivatedHandler, subscriptionClosedHandler, subscriptionUpcomingInvoiceHandler);
this.userAssignmentHandler = userAssignmentHandler;
this.userUnassignmentHandler = userUnassignmentHandler;
this.unknownEventHandler = unknownEventHandler;
Expand All @@ -57,7 +73,7 @@ private SDKEventHandler getHandlerFor(final EventInfo rawEvent) {

Map<EventType, Supplier<SDKEventHandler>> eventsToHandlers = new EnumMap<>(EventType.class);
eventsToHandlers.put(SUBSCRIPTION_ORDER, () -> eventIsForAddon ? addonSubscriptionOrderHandler : subscriptionOrderHandler);
eventsToHandlers.put(SUBSCRIPTION_CANCEL, () -> subscriptionCancelHandler);
eventsToHandlers.put(SUBSCRIPTION_CANCEL, () -> eventIsForAddon ? addonSubscriptionCancelHandler : subscriptionCancelHandler);
eventsToHandlers.put(SUBSCRIPTION_CHANGE, () -> subscriptionChangeHandler);
eventsToHandlers.put(SUBSCRIPTION_NOTICE, () -> subscriptionNoticeHandlerFor(rawEvent.getPayload().getNotice().getType()));
eventsToHandlers.put(USER_ASSIGNMENT, () -> userAssignmentHandler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class EventHandlingConfiguration {
private final AppmarketEventHandler<SubscriptionReactivated> subscriptionReactivatedHandler;
private final AppmarketEventHandler<SubscriptionUpcomingInvoice> subscriptionUpcomingInvoiceHandler;
private final AppmarketEventHandler<AddonSubscriptionOrder> addonSubscriptionOrderHandler;
private final AppmarketEventHandler<AddonSubscriptionCancel> addonSubscriptionCancelHandler;
private final AppmarketEventHandler<UserAssignment> userAssignmentHandler;
private final AppmarketEventHandler<UserUnassignment> userUnassignmentHandler;

Expand All @@ -40,20 +41,21 @@ public ExecutorService defaultExecutorService() {
@Bean
public AppmarketEventDispatcher appmarketEventDispatcher(AppmarketEventClient appmarketEventClient) {
return new AppmarketEventDispatcher(
new Events(),
new AsyncEventHandler(defaultExecutorService(), appmarketEventClient),
new ParseAndHandleWrapper<>(new SubscriptionOrderEventParser(), subscriptionOrderHandler),
new ParseAndHandleWrapper<>(new SubscriptionCancelEventParser(), subscriptionCancelHandler),
new ParseAndHandleWrapper<>(new SubscriptionChangeEventParser(), subscriptionChangeHandler),
new ParseAndHandleWrapper<>(new SubscriptionDeactivatedParser(), subscriptionDeactivatedHandler),
new ParseAndHandleWrapper<>(new SubscriptionReactivatedParser(), subscriptionReactivatedHandler),
new ParseAndHandleWrapper<>(new SubscriptionClosedParser(), subscriptionClosedHandler),
new ParseAndHandleWrapper<>(new SubscriptionUpcomingInvoiceParser(), subscriptionUpcomingInvoiceHandler),
new ParseAndHandleWrapper<>(new AddonSubscriptionOrderEventParser(), addonSubscriptionOrderHandler),
new ParseAndHandleWrapper<>(new UserAssignmentParser(), userAssignmentHandler),
new ParseAndHandleWrapper<>(new UserUnassignmentParser(), userUnassignmentHandler),
unknownEventHandler(),
new AddonEventDetector()
new Events(),
new AsyncEventHandler(defaultExecutorService(), appmarketEventClient),
new ParseAndHandleWrapper<>(new SubscriptionOrderEventParser(), subscriptionOrderHandler),
new ParseAndHandleWrapper<>(new SubscriptionCancelEventParser(), subscriptionCancelHandler),
new ParseAndHandleWrapper<>(new SubscriptionChangeEventParser(), subscriptionChangeHandler),
new ParseAndHandleWrapper<>(new SubscriptionDeactivatedParser(), subscriptionDeactivatedHandler),
new ParseAndHandleWrapper<>(new SubscriptionReactivatedParser(), subscriptionReactivatedHandler),
new ParseAndHandleWrapper<>(new SubscriptionClosedParser(), subscriptionClosedHandler),
new ParseAndHandleWrapper<>(new SubscriptionUpcomingInvoiceParser(), subscriptionUpcomingInvoiceHandler),
new ParseAndHandleWrapper<>(new AddonSubscriptionOrderEventParser(), addonSubscriptionOrderHandler),
new ParseAndHandleWrapper<>(new AddonSubscriptionCancelEventParser(), addonSubscriptionCancelHandler),
new ParseAndHandleWrapper<>(new UserAssignmentParser(), userAssignmentHandler),
new ParseAndHandleWrapper<>(new UserUnassignmentParser(), userUnassignmentHandler),
unknownEventHandler(),
new AddonEventDetector()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.appdirect.sdk.appmarket.events;

import static com.appdirect.sdk.appmarket.events.EventFlag.STATELESS;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class AddonSubscriptionCancelEventParserTest {

AddonSubscriptionCancelEventParser testedParser = new AddonSubscriptionCancelEventParser();

@Test
public void parse_whenAnAddonSubscriptionCancelEventWithNoFlagIsParsed_aCorrespondingRichEventIsCreated() throws Exception {
//Given
String expectedConsumerKey = "expectedConsumerKey";
String expectedAddonAccountIdentifier = "expectedAddonAccountIdentifier";
String expectedParentAccountIdentifier = "expectedParentAccountIdentifier";
Map<String, String[]> expectedParameters = new HashMap<>();
EventFlag expectedFlag = null;
EventInfo testEvent = addonCancelEvent(expectedAddonAccountIdentifier, expectedParentAccountIdentifier, expectedFlag);
EventHandlingContext testEventContext = EventHandlingContexts.eventContext(expectedConsumerKey, expectedParameters);
AddonSubscriptionCancel expectedEvent = new AddonSubscriptionCancel(
expectedAddonAccountIdentifier,
expectedParentAccountIdentifier,
expectedConsumerKey,
expectedParameters,
expectedFlag
);

//When
AddonSubscriptionCancel parsedEvent = testedParser.parse(testEvent, testEventContext);

//Then
assertThat(parsedEvent).isEqualTo(expectedEvent);
}

@Test
public void parse_whenAnAddonSubscriptionCancelEventWithFlagIsParsed_aCorrespondingRichEventIsCreated() throws Exception {
//Given
String expectedConsumerKey = "expectedConsumerKey";
String expectedAddonAccountIdentifier = "expectedAddonAccountIdentifier";
String expectedParentAccountIdentifier = "expectedParentAccountIdentifier";
Map<String, String[]> expectedParameters = new HashMap<>();
EventFlag expectedFlag = STATELESS;
EventInfo testEvent = addonCancelEvent(expectedAddonAccountIdentifier, expectedParentAccountIdentifier, expectedFlag);
EventHandlingContext testEventContext = EventHandlingContexts.eventContext(expectedConsumerKey, expectedParameters);
AddonSubscriptionCancel expectedEvent = new AddonSubscriptionCancel(
expectedAddonAccountIdentifier,
expectedParentAccountIdentifier,
expectedConsumerKey,
expectedParameters,
expectedFlag
);

//When
AddonSubscriptionCancel parsedEvent = testedParser.parse(testEvent, testEventContext);

//Then
assertThat(parsedEvent).isEqualTo(expectedEvent);
}

private EventInfo addonCancelEvent(String accountIdentifier, String parentAccountIdentidier, EventFlag eventFlag) {
return EventInfo.builder()
.flag(eventFlag)
.payload(
EventPayload.builder()
.account(
AccountInfo.builder()
.accountIdentifier(accountIdentifier)
.parentAccountIdentifier(parentAccountIdentidier)
.build()
).build()
).build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class AppmarketEventDispatcherTest {
@Mock
private SDKEventHandler mockAddonSubscriptionOrderHandler;
@Mock
private SDKEventHandler mockAddonSubscriptionCancelHandler;
@Mock
private SDKEventHandler mockUnknownEventHandler;

@Mock
Expand Down Expand Up @@ -76,27 +78,30 @@ public class AppmarketEventDispatcherTest {
private APIResult mockUserAssignmentResponse;
@Mock
private APIResult mockUserUnassignmentResponse;
@Mock
private APIResult mockAddonSubscriptionCancelResponse;

@Mock
private AddonEventDetector mockAddonDetector;

@Before
public void setUp() throws Exception {
eventDispatcher = new AppmarketEventDispatcher(
mockEvents,
mockAsyncEventHandler,
mockSubscriptionOrderHandler,
mockSubscriptionCancelHandler,
mockSubscriptionChangeHandler,
mockSubscriptionDeactivatedHandler,
mockSubscriptionReactivatedhandler,
mockSubscriptionClosedHandler,
mockSubscriptionIncomingNoticeHandler,
mockAddonSubscriptionOrderHandler,
mockUserAssignmentHandler,
mockUserUnassignmentHandler,
mockUnknownEventHandler,
mockAddonDetector
mockEvents,
mockAsyncEventHandler,
mockSubscriptionOrderHandler,
mockSubscriptionCancelHandler,
mockSubscriptionChangeHandler,
mockSubscriptionDeactivatedHandler,
mockSubscriptionReactivatedhandler,
mockSubscriptionClosedHandler,
mockSubscriptionIncomingNoticeHandler,
mockAddonSubscriptionOrderHandler,
mockAddonSubscriptionCancelHandler,
mockUserAssignmentHandler,
mockUserUnassignmentHandler,
mockUnknownEventHandler,
mockAddonDetector
);

when(mockEvents.eventShouldBeHandledAsync(any()))
Expand All @@ -118,6 +123,8 @@ public void setUp() throws Exception {
.thenReturn(mockSubscriptionUpcomingInvoiceResponse);
when(mockAddonSubscriptionOrderHandler.handle(any(), any()))
.thenReturn(mockAddonSubscriptionOrderResponse);
when(mockAddonSubscriptionCancelHandler.handle(any(), any()))
.thenReturn(mockAddonSubscriptionCancelResponse);
when(mockUnknownEventHandler.handle(any(), any()))
.thenReturn(mockUnknownEventResponse);
when(mockUserAssignmentHandler.handle(any(), any()))
Expand Down Expand Up @@ -235,6 +242,20 @@ public void testDispatchAndHandle_whenTheEventIsSubscriptionOrder_forAddon_thenI
assertThat(result).isEqualTo(mockAddonSubscriptionOrderResponse);
}

@Test
public void testDispatchAndHandle_whenTheEventIsSubscriptionCancel_forAddon_thenInvokeAppropriateHandler() throws Exception {
//Given
EventInfo addonTestEvent = someSubCancelEvent();
when(mockAddonDetector.eventIsRelatedToAddon(addonTestEvent))
.thenReturn(true);

//When
APIResult result = eventDispatcher.dispatchAndHandle(addonTestEvent, defaultEventContext());

//Then
assertThat(result).isEqualTo(mockAddonSubscriptionCancelResponse);
}

@Test
public void testDispatchAndHandle_whenTheEventIsUserAssign_thenTheUserAssignHandlerIsInvoked() throws Exception {
//Given
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.appdirect.sdk.feature;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.appdirect.sdk.support.FakeAppmarket;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MinimalConnector.class, webEnvironment = RANDOM_PORT)
public class CanDispatchAddonSubscriptionCancelIntegrationTest {
@LocalServerPort
private int localConnectorPort;
private FakeAppmarket fakeAppmarket;

@Before
public void setUp() throws Exception {
fakeAppmarket = FakeAppmarket.create(localConnectorPort + 1, "isv-key", "isv-secret").start();
}

@After
public void stop() throws Exception {
fakeAppmarket.stop();
}

@Test
public void addonSubscriptionOrderIsProcessedSuccessfully() throws Exception {
HttpResponse response = fakeAppmarket.sendEventTo(connectorEventEndpoint(), "/v1/events/subscription-cancel-addon");

assertThat(fakeAppmarket.allRequestPaths()).first().isEqualTo("/v1/events/subscription-cancel-addon");
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(202);
assertThat(EntityUtils.toString(response.getEntity())).isEqualTo("{\"success\":true,\"message\":\"Event with eventId=subscription-cancel-addon has been accepted by the connector. It will be processed soon.\"}");

fakeAppmarket.waitForResolvedEvents(1);
assertThat(fakeAppmarket.resolvedEvents()).contains("subscription-cancel-addon");
assertThat(fakeAppmarket.allRequestPaths()).last().isEqualTo("/api/integration/v1/events/subscription-cancel-addon/result");
assertThat(fakeAppmarket.lastRequestBody()).isEqualTo("{\"success\":true,\"message\":\"ADDON_CANCEL has been processed just now.\"}");
}

private String connectorEventEndpoint() {
return baseConnectorUrl() + "/api/v1/integration/processEvent";
}

private String baseConnectorUrl() {
return "http://localhost:" + localConnectorPort;
}
}
6 changes: 6 additions & 0 deletions src/test/java/com/appdirect/sdk/feature/MinimalConnector.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.appdirect.sdk.appmarket.AppmarketEventHandler;
import com.appdirect.sdk.appmarket.Credentials;
import com.appdirect.sdk.appmarket.DeveloperSpecificAppmarketCredentialsSupplier;
import com.appdirect.sdk.appmarket.events.AddonSubscriptionCancel;
import com.appdirect.sdk.appmarket.events.AddonSubscriptionOrder;
import com.appdirect.sdk.appmarket.events.SubscriptionCancel;
import com.appdirect.sdk.appmarket.events.SubscriptionChange;
Expand Down Expand Up @@ -92,6 +93,11 @@ public AppmarketEventHandler<AddonSubscriptionOrder> addonSubscriptionOrderHandl
return event -> success("ADDON_ORDER has been processed just now.");
}

@Bean
public AppmarketEventHandler<AddonSubscriptionCancel> addonSubscriptionCancelAppmarketEventHandler() {
return event -> success("ADDON_CANCEL has been processed just now.");
}

@Bean
public AppmarketEventHandler<UserAssignment> userAssignmentDevHandler() {
return event -> success(
Expand Down
Loading

0 comments on commit cdb9c9f

Please sign in to comment.