def test_ingest_update_customer(dbsession, stripe_customer): """A Stripe Customer can be updated.""" data = stripe_customer_data() # Change payment method new_source_id = fake_stripe_id("card", "new credit card") data["default_source"] = new_source_id data["invoice_settings"]["default_payment_method"] = None with StatementWatcher(dbsession.connection()) as watcher: customer, actions = ingest_stripe_customer(dbsession, data) dbsession.commit() assert watcher.count == 2 stmt1 = watcher.statements[0][0] assert stmt1.startswith("SELECT stripe_customer."), stmt1 assert stmt1.endswith(" FOR UPDATE"), stmt1 stmt2 = watcher.statements[1][0] assert stmt2.startswith("UPDATE stripe_customer SET "), stmt2 assert customer.default_source_id == new_source_id assert customer.invoice_settings_default_payment_method_id is None assert actions == { "updated": { f"customer:{data['id']}", } }
def test_ingest_existing_contact(dbsession, example_contact): """A Stripe Customer is associated with the existing contact.""" data = stripe_customer_data() data["description"] = example_contact.fxa.fxa_id data["email"] = example_contact.fxa.primary_email with StatementWatcher(dbsession.connection()) as watcher: customer, actions = ingest_stripe_customer(dbsession, data) dbsession.commit() assert watcher.count == 3 stmt1 = watcher.statements[0][0] assert stmt1.startswith("SELECT stripe_customer."), stmt1 assert stmt1.endswith(" FOR UPDATE"), stmt1 stmt2 = watcher.statements[1][0] assert stmt2.startswith("SELECT stripe_customer."), stmt2 assert stmt2.endswith(" FOR UPDATE"), stmt2 stmt3 = watcher.statements[2][0] assert stmt3.startswith("INSERT INTO stripe_customer "), stmt3 assert customer.stripe_id == FAKE_STRIPE_ID["Customer"] assert not customer.deleted assert customer.default_source_id is None assert ( customer.invoice_settings_default_payment_method_id == FAKE_STRIPE_ID["Payment Method"] ) assert customer.fxa_id == example_contact.fxa.fxa_id assert customer.get_email_id() == example_contact.email.email_id assert actions == { "created": { f"customer:{customer.stripe_id}", } }
def test_sync_acoustic_record_delete_path( dbsession, sync_obj, maximal_contact, settings, ): no_metrics = sync_obj.metric_service is None sync_obj.ctms_to_acoustic = MagicMock( **{"attempt_to_upload_ctms_contact.return_value": True} ) _setup_pending_record(dbsession, email_id=maximal_contact.email.email_id) end_time = datetime.now(timezone.utc) + timedelta(hours=12) with StatementWatcher(dbsession.connection()) as watcher: context = sync_obj.sync_records(dbsession, end_time=end_time) dbsession.flush() sync_obj.ctms_to_acoustic.attempt_to_upload_ctms_contact.assert_called_with( maximal_contact ) expected_context = { "batch_limit": 20, "retry_limit": 5, "count_total": 1, "count_synced": 1, "end_time": end_time.isoformat(), } if no_metrics: assert watcher.count == 4 # Get All Records, Get Contact(x2), Increment Retry assert context == expected_context return # Metrics adds two DB queries (total records and retries) assert watcher.count == 6 expected_context["retry_backlog"] = 0 expected_context["sync_backlog"] = 1 assert context == expected_context registry = sync_obj.metric_service.registry labels = { "app_kubernetes_io_component": "background", "app_kubernetes_io_instance": "ctms", "app_kubernetes_io_name": "ctms", } prefix = "ctms_background_acoustic_sync" assert registry.get_sample_value(f"{prefix}_total", labels) == 1 assert registry.get_sample_value(f"{prefix}_retries", labels) == 0 assert registry.get_sample_value(f"{prefix}_backlog", labels) == 1 assert 0.0 <= registry.get_sample_value(f"{prefix}_age_s", labels) <= 0.2
def test_ingest_updated_invoice(dbsession, stripe_invoice): """An existing Stripe Invoice is updated.""" assert stripe_invoice.status == "open" data = stripe_invoice_data() data["status"] = "void" with StatementWatcher(dbsession.connection()) as watcher: invoice, actions = ingest_stripe_invoice(dbsession, data) dbsession.commit() assert watcher.count == 5 stmt1, stmt2, stmt3, stmt4, stmt5 = [pair[0] for pair in watcher.statements] assert stmt1.startswith("SELECT stripe_invoice."), stmt1 assert stmt1.endswith(" FOR UPDATE"), stmt1 # Get all IDs assert stmt2.startswith("SELECT stripe_invoice_line_item.stripe_id "), stmt2 assert stmt2.endswith(" FOR UPDATE"), stmt2 # Load line item 1 # Can't eager load items with FOR UPDATE, need to query twice assert stmt3.startswith("SELECT stripe_price."), stmt3 assert stmt3.endswith(" FOR UPDATE"), stmt3 assert stmt4.startswith("SELECT stripe_invoice_line_item."), stmt4 assert stmt4.endswith(" FOR UPDATE"), stmt4 # Updates invoice assert stmt5.startswith("UPDATE stripe_invoice "), stmt5 assert invoice.status == "void" assert len(invoice.line_items) == 1 assert actions == { "updated": { f"invoice:{data['id']}", }, "no_change": { f"line_item:{data['lines']['data'][0]['id']}", f"price:{data['lines']['data'][0]['price']['id']}", }, }
def test_ingest_new_invoice(dbsession): """A new Stripe Invoice is ingested.""" data = stripe_invoice_data() with StatementWatcher(dbsession.connection()) as watcher: invoice, actions = ingest_stripe_invoice(dbsession, data) dbsession.commit() assert watcher.count == 6 stmt1, stmt2, stmt3, stmt4, stmt5, stmt6 = [pair[0] for pair in watcher.statements] assert stmt1.startswith("SELECT stripe_invoice."), stmt1 assert stmt1.endswith(" FOR UPDATE"), stmt1 assert stmt2.startswith("SELECT stripe_price."), stmt2 assert stmt2.endswith(" FOR UPDATE"), stmt2 assert stmt3.startswith("SELECT stripe_invoice_line_item."), stmt3 assert stmt3.endswith(" FOR UPDATE"), stmt3 # Insert order could be swapped assert stmt4.startswith("INSERT INTO stripe_"), stmt4 assert stmt5.startswith("INSERT INTO stripe_"), stmt5 assert stmt6.startswith("INSERT INTO stripe_"), stmt6 assert invoice.stripe_id == FAKE_STRIPE_ID["Invoice"] assert invoice.stripe_created == datetime(2021, 10, 28, tzinfo=timezone.utc) assert invoice.stripe_customer_id == FAKE_STRIPE_ID["Customer"] assert invoice.currency == "usd" assert invoice.total == 1000 assert invoice.status == "open" assert invoice.default_payment_method_id is None assert invoice.default_source_id is None assert invoice.get_email_id() is None # Can be created without the Customer object assert invoice.customer is None assert len(invoice.line_items) == 1 item = invoice.line_items[0] assert item.stripe_id == FAKE_STRIPE_ID["(Invoice) Line Item"] assert item.invoice == invoice assert item.stripe_subscription_id == FAKE_STRIPE_ID["Subscription"] assert item.stripe_subscription_item_id == FAKE_STRIPE_ID["Subscription Item"] assert item.stripe_invoice_item_id is None assert item.amount == 1000 assert item.currency == "usd" assert item.get_email_id() is None price = item.price assert price.stripe_id == FAKE_STRIPE_ID["Price"] assert price.stripe_created == datetime(2020, 10, 27, 10, 45, tzinfo=timezone.utc) assert price.stripe_product_id == FAKE_STRIPE_ID["Product"] assert price.active assert price.currency == "usd" assert price.recurring_interval == "month" assert price.recurring_interval_count == 1 assert price.unit_amount == 999 assert price.get_email_id() is None assert actions == { "created": { f"invoice:{data['id']}", f"line_item:{item.stripe_id}", f"price:{price.stripe_id}", }, }
def test_ingest_update_subscription(dbsession, stripe_subscription): """An existing subscription is updated.""" data = stripe_subscription_data() # Change to yearly current_period_end = stripe_subscription.current_period_end + timedelta(days=365) si_created = stripe_subscription.current_period_start + timedelta(days=15) data["current_period_end"] = unix_timestamp(current_period_end) old_sub_item_id = data["items"]["data"][0]["id"] new_sub_item_id = fake_stripe_id("si", "new subscription item id") new_price_id = fake_stripe_id("price", "yearly price") data["items"]["data"][0] = { "id": new_sub_item_id, "object": "subscription_item", "created": unix_timestamp(current_period_end), "subscription": data["id"], "price": { "id": new_price_id, "object": "price", "created": unix_timestamp(si_created), "product": FAKE_STRIPE_ID["Product"], "active": True, "currency": "usd", "recurring": { "interval": "year", "interval_count": 1, }, "unit_amount": 4999, }, } data["default_payment_method"] = fake_stripe_id("pm", "my new credit card") with StatementWatcher(dbsession.connection()) as watcher: subscription, actions = ingest_stripe_subscription(dbsession, data) dbsession.commit() assert watcher.count == 8 stmt1, stmt2, stmt3, stmt4, stmt5, stmt6, stmt7, stmt8 = [ pair[0] for pair in watcher.statements ] assert stmt1.startswith("SELECT stripe_subscription."), stmt1 assert stmt1.endswith(" FOR UPDATE"), stmt1 # Get all IDs assert stmt2.startswith("SELECT stripe_subscription_item.stripe_id "), stmt2 assert stmt2.endswith(" FOR UPDATE"), stmt2 # Load item 1 # Can't eager load items with FOR UPDATE, need to query twice assert stmt3.startswith("SELECT stripe_price."), stmt3 assert stmt3.endswith(" FOR UPDATE"), stmt3 assert stmt4.startswith("SELECT stripe_subscription_item."), stmt4 assert stmt4.endswith(" FOR UPDATE"), stmt4 # Delete old item assert stmt5.startswith("DELETE FROM stripe_subscription_item "), stmt5 # Insert order could be swapped insert = "INSERT INTO stripe_" update = "UPDATE stripe_subscription SET " assert stmt6.startswith(insert) or stmt6.startswith(update), stmt6 assert stmt7.startswith(insert) or stmt7.startswith(update), stmt7 assert stmt8.startswith(insert) or stmt8.startswith(update), stmt8 assert subscription.current_period_end == current_period_end assert subscription.default_payment_method_id == data["default_payment_method"] assert len(subscription.subscription_items) == 1 s_item = subscription.subscription_items[0] assert s_item.stripe_id == new_sub_item_id assert s_item.price.stripe_id == new_price_id assert actions == { "created": { f"subscription_item:{new_sub_item_id}", f"price:{new_price_id}", }, "updated": { f"subscription:{data['id']}", }, "deleted": { f"subscription_item:{old_sub_item_id}", }, }
def test_ingest_new_subscription(dbsession): """A new Stripe Subscription is ingested.""" data = stripe_subscription_data() with StatementWatcher(dbsession.connection()) as watcher: subscription, actions = ingest_stripe_subscription(dbsession, data) dbsession.commit() assert watcher.count == 6 stmt1, stmt2, stmt3, stmt4, stmt5, stmt6 = [pair[0] for pair in watcher.statements] assert stmt1.startswith("SELECT stripe_subscription."), stmt1 assert stmt1.endswith(" FOR UPDATE"), stmt1 assert stmt2.startswith("SELECT stripe_price."), stmt2 assert stmt2.endswith(" FOR UPDATE"), stmt2 assert stmt3.startswith("SELECT stripe_subscription_item."), stmt3 assert stmt3.endswith(" FOR UPDATE"), stmt3 # Insert order could be swapped assert stmt4.startswith("INSERT INTO stripe_"), stmt4 assert stmt5.startswith("INSERT INTO stripe_"), stmt5 assert stmt6.startswith("INSERT INTO stripe_"), stmt6 assert subscription.stripe_id == FAKE_STRIPE_ID["Subscription"] assert subscription.stripe_created == datetime(2021, 9, 27, tzinfo=timezone.utc) assert subscription.stripe_customer_id == FAKE_STRIPE_ID["Customer"] assert not subscription.cancel_at_period_end assert subscription.canceled_at is None assert subscription.current_period_end == datetime( 2021, 11, 27, tzinfo=timezone.utc ) assert subscription.current_period_start == datetime( 2021, 10, 27, tzinfo=timezone.utc ) assert subscription.ended_at is None assert subscription.start_date == datetime(2021, 9, 27, tzinfo=timezone.utc) assert subscription.status == "active" assert subscription.default_payment_method_id is None assert subscription.get_email_id() is None # Can be created without the Customer object assert subscription.customer is None assert len(subscription.subscription_items) == 1 item = subscription.subscription_items[0] assert item.stripe_id == FAKE_STRIPE_ID["Subscription Item"] assert item.subscription == subscription assert item.get_email_id() is None price = item.price assert price.stripe_id == FAKE_STRIPE_ID["Price"] assert price.stripe_created == datetime(2020, 10, 27, 10, 45, tzinfo=timezone.utc) assert price.stripe_product_id == FAKE_STRIPE_ID["Product"] assert price.active assert price.currency == "usd" assert price.recurring_interval == "month" assert price.recurring_interval_count == 1 assert price.unit_amount == 999 assert price.get_email_id() is None assert actions == { "created": { f"subscription:{FAKE_STRIPE_ID['Subscription']}", f"subscription_item:{FAKE_STRIPE_ID['Subscription Item']}", f"price:{FAKE_STRIPE_ID['Price']}", } }