TransactionManager implements StatefulFunction { @Override public void invoke(Context context, Object input) { if (input instanceof Transaction) { Transaction transaction = (Transaction) input; transactionState.set(transaction); String account = transaction.getAccount(); context.send(FRAUD_FN, account, QueryFraud.getDefaultInstance()); String merchant = transaction.getMerchant(); context.send(MERCHANT_FN, merchant, QueryMerchantScore.getDefaultInstance()); } if (input instanceof ReportedFraud) { ReportedFraud reported = (ReportedFraud) input; recentFraudCount.set(reported.getCount()); MerchantScore merchant = merchantScore.get(); if (merchant != null) { score(context, merchant, reported.getCount()); } } if (input instanceof MerchantScore) { MerchantScore reportedScore = (MerchantScore) input; merchantScore.set(reportedScore); Integer count = recentFraudCount.get(); if (count != null) { score(context, reportedScore, count); } } if (input instanceof Any) { final FraudScore fraudScore; try { fraudScore = (((Any) input).unpack(FraudScore.class)); } catch (InvalidProtocolBufferException e) { throw new RuntimeException("Unexpected type", e); } if (fraudScore.getScore() > THRESHOLD) { context.send(ALERT, transactionState.get()); } transactionState.clear(); recentFraudCount.clear(); merchantScore.clear(); } }  @Override void invoke(Context context, Object input);  }
@Test public void initialTransactionTest() { FunctionTestHarness harness = FunctionTestHarness.test(ignore -> new TransactionManager(), MANAGER_FN, "id"); Assert.assertThat( harness.invoke(TRANSACTION), sent( messagesTo(new Address(FRAUD_FN, ACCOUNT), equalTo(QueryFraud.getDefaultInstance())), messagesTo(new Address(MERCHANT_FN, MERCHANT), equalTo(QueryMerchantScore.getDefaultInstance())))); }
@Test public void reportFraudThenMerchantTest() { FunctionTestHarness harness = FunctionTestHarness.test(ignore -> new TransactionManager(), MANAGER_FN, "id"); harness.invoke(TRANSACTION); FeatureVector expectedVector = FeatureVector.newBuilder().setAmount(AMOUNT).setFraudCount(1).setMerchantScore(1).build(); Assert.assertThat(harness.invoke(ReportedFraud.newBuilder().setCount(1).build()), sentNothing()); Assert.assertThat( harness.invoke(MerchantScore.newBuilder().setScore(1).build()), sent( messagesTo( new Address(MODEL_FN, ACCOUNT), equalTo(Any.pack(expectedVector))))); }
@Test public void reportMerchantThenFraudTest() { FunctionTestHarness harness = FunctionTestHarness.test(ignore -> new TransactionManager(), MANAGER_FN, "id"); harness.invoke(TRANSACTION); FeatureVector expectedVector = FeatureVector.newBuilder().setAmount(AMOUNT).setFraudCount(1).setMerchantScore(1).build(); Assert.assertThat(harness.invoke(MerchantScore.newBuilder().setScore(1).build()), sentNothing()); Assert.assertThat( harness.invoke(ReportedFraud.newBuilder().setCount(1).build()), sent( messagesTo( new Address(MODEL_FN, ACCOUNT), equalTo(Any.pack(expectedVector))))); }
@Test public void discoveredFraudTest() { FunctionTestHarness harness = FunctionTestHarness.test(ignore -> new TransactionManager(), MANAGER_FN, "id"); harness.invoke(TRANSACTION); Assert.assertThat(harness.invoke(Any.pack(FraudScore.newBuilder().setScore(81).build())), sentNothing()); Assert.assertThat(harness.getEgress(ALERT), contains(equalTo(TRANSACTION))); }
@Test public void falseFraudTest() { FunctionTestHarness harness = FunctionTestHarness.test(ignore -> new TransactionManager(), MANAGER_FN, "id"); harness.invoke(TRANSACTION); Assert.assertThat(harness.invoke(Any.pack(FraudScore.newBuilder().setScore(81).build())), sentNothing()); Assert.assertThat(harness.getEgress(ALERT), contains(equalTo(TRANSACTION))); }