OcrPurchaseTracker implements PurchaseEventsListener { @SuppressLint("CheckResult") public void initialize() { Logger.debug(this, "Initializing..."); this.purchaseManager.addEventListener(this); this.identityManager.isLoggedInStream() .subscribeOn(subscribeOnScheduler) .filter(isLoggedIn -> isLoggedIn) .flatMap(aBoolean -> { return fetchAndPersistAvailableRecognitions(); }) .flatMap(integer -> purchaseManager.getAllOwnedPurchases()) .flatMap(managedProducts -> { for (final ManagedProduct managedProduct : managedProducts) { if (managedProduct.getInAppPurchase().getPurchaseFamilies().contains(PurchaseFamily.Ocr)) { Logger.debug(OcrPurchaseTracker.this, "Found available OCR purchase: {}", managedProduct.getInAppPurchase()); if (!defaultInAppPurchaseConsumer.isConsumed(managedProduct, PurchaseFamily.Ocr)) { return uploadOcrPurchase(managedProduct); } else { Logger.debug(OcrPurchaseTracker.this, "But {} was already consumed...", managedProduct.getInAppPurchase()); } } } return Observable.empty(); }) .subscribe(o -> Logger.info(OcrPurchaseTracker.this, "Successfully initialized"), throwable -> Logger.error(OcrPurchaseTracker.this, "Failed to initialize.", throwable)); } @Inject  OcrPurchaseTracker(@NonNull IdentityManager identityManager,
                              @NonNull WebServiceManager webServiceManager,
                              @NonNull PurchaseManager purchaseManager,
                              @NonNull PurchaseWallet purchaseWallet,
                              @NonNull DefaultInAppPurchaseConsumer defaultInAppPurchaseConsumer,
                              @NonNull LocalOcrScansTracker localOcrScansTracker); @VisibleForTesting  OcrPurchaseTracker(@NonNull IdentityManager identityManager,
                       @NonNull WebServiceManager webServiceManager,
                       @NonNull PurchaseManager purchaseManager,
                       @NonNull PurchaseWallet purchaseWallet,
                       @NonNull DefaultInAppPurchaseConsumer defaultInAppPurchaseConsumer,
                       @NonNull LocalOcrScansTracker localOcrScansTracker,
                       @NonNull Scheduler subscribeOnScheduler); @SuppressLint("CheckResult") void initialize(); @Override void onPurchaseSuccess(@NonNull InAppPurchase inAppPurchase, @NonNull PurchaseSource purchaseSource); @Override void onPurchaseFailed(@NonNull PurchaseSource purchaseSource); int getRemainingScans(); Observable<Integer> getRemainingScansStream(); boolean hasAvailableScans(); void decrementRemainingScans();  }
@SuppressWarnings("ThrowableInstanceNeverThrown") @Test public void initializeUploadFailsWith422CodeAndSmartReceiptsApiExceptionWithListOfUnknownErrors() { final SmartReceiptsApiErrorResponse errorResponse = new SmartReceiptsApiErrorResponse(Arrays.asList("error1", "error2", "error3")); final SmartReceiptsApiException smartReceiptsApiException = new SmartReceiptsApiException(Response.error(422, retrofitResponseBody), new Exception("test"), errorResponse); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(smartReceiptsApiException)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); }
@SuppressWarnings("ThrowableInstanceNeverThrown") @Test public void initializeUploadFailsWith400CodeAndSmartReceiptsApiExceptionWithDuplicatePurchaseError() { final SmartReceiptsApiErrorResponse errorResponse = new SmartReceiptsApiErrorResponse(Arrays.asList("error1", "Purchase has already been taken", "error3")); final SmartReceiptsApiException smartReceiptsApiException = new SmartReceiptsApiException(Response.error(400, retrofitResponseBody), new Exception("test"), errorResponse); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(smartReceiptsApiException)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); }
@SuppressWarnings("ThrowableInstanceNeverThrown") @Test public void initializeUploadFailsWith422CodeAndSmartReceiptsApiExceptionWithDuplicatePurchaseErrorButThenConsumesThisPurchaseLocally() { final SmartReceiptsApiErrorResponse errorResponse = new SmartReceiptsApiErrorResponse(Arrays.asList("error1", "Purchase has already been taken", "error3")); final SmartReceiptsApiException smartReceiptsApiException = new SmartReceiptsApiException(Response.error(422, retrofitResponseBody), new Exception("test"), errorResponse); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(smartReceiptsApiException)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer).consumePurchase(managedProduct, PurchaseFamily.Ocr); }
@Test public void initializeSucceeds() { when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer).consumePurchase(managedProduct, PurchaseFamily.Ocr); }
@Test public void initializeFailsToFetchMe() { when(identityManager.getMe()).thenReturn(Observable.error(new Exception("test"))); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker, never()).setRemainingScans(anyInt()); verify(defaultInAppPurchaseConsumer).consumePurchase(managedProduct, PurchaseFamily.Ocr); }
@Test public void initializeReturnsInvalidMeResponse() { when(meResponse.getUser()).thenReturn(null); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker, never()).setRemainingScans(anyInt()); verify(defaultInAppPurchaseConsumer).consumePurchase(managedProduct, PurchaseFamily.Ocr); }
@Test public void initializeSucceedsForLateLogin() { final PublishSubject<Boolean> loggedInStream = PublishSubject.create(); loggedInStream.onNext(false); when(identityManager.isLoggedInStream()).thenReturn(loggedInStream); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse)); ocrPurchaseTracker.initialize(); loggedInStream.onNext(true); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer).consumePurchase(managedProduct, PurchaseFamily.Ocr); }
@Test public void initializeWhenNotLoggedInDoesNothing() { when(identityManager.isLoggedInStream()).thenReturn(Observable.just(false)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker, never()).setRemainingScans(REMAINING_SCANS); verifyNoMoreInteractions(purchaseManager); verifyZeroInteractions(webServiceManager); }
@Test public void initializeThrowsException() { when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.<Set<ManagedProduct>>error(new Exception("test"))); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); verifyZeroInteractions(webServiceManager); }
@Test public void initializeWithoutPurchases() { when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.emptySet())); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(new Exception("test"))); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); verifyZeroInteractions(webServiceManager); }
@Test public void initializeWithAnAlreadyConsumedPurchase() { when(defaultInAppPurchaseConsumer.isConsumed(managedProduct, PurchaseFamily.Ocr)).thenReturn(true); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(new Exception("test"))); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); verifyZeroInteractions(webServiceManager); }
@Test public void initializeUploadFails() { when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(new Exception("test"))); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); }
@SuppressWarnings("ThrowableInstanceNeverThrown") @Test public void initializeUploadFailsWith422CodeAndNullSmartReceiptsApiException() { final SmartReceiptsApiErrorResponse errorResponse = null; final SmartReceiptsApiException smartReceiptsApiException = new SmartReceiptsApiException(Response.error(422, retrofitResponseBody), new Exception("test"), errorResponse); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(smartReceiptsApiException)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); }
@SuppressWarnings("ThrowableInstanceNeverThrown") @Test public void initializeUploadFailsWith422CodeAndSmartReceiptsApiExceptionWithNullList() { final SmartReceiptsApiErrorResponse errorResponse = new SmartReceiptsApiErrorResponse(null); final SmartReceiptsApiException smartReceiptsApiException = new SmartReceiptsApiException(Response.error(422, retrofitResponseBody), new Exception("test"), errorResponse); when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton(managedProduct))); when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.error(smartReceiptsApiException)); ocrPurchaseTracker.initialize(); verify(purchaseManager).addEventListener(ocrPurchaseTracker); verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS); verify(defaultInAppPurchaseConsumer, never()).consumePurchase(any(ManagedProduct.class), any(PurchaseFamily.class)); }