splitbit-llm / tests /test_subscription.py
hermescures1's picture
Upload folder using huggingface_hub
c9df2ea verified
Raw
History Blame Contribute Delete
24.7 kB
"""Test subscription manager β€” $1/month subscription with free trial.
Payment integration with Soulmate OS wallet API.
"""
import sys
import os
import tempfile
import time
import json
from unittest.mock import patch, MagicMock
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from splitbit_llm.subscription import (
SubscriptionManager, MONTHLY_PRICE, SOULMATE_API_URL,
FOUNDER_EMAIL, FOUNDER_PASSWORD, ACCEPTED_TOKENS, NETWORK,
BANK_ROUTING, BANK_ACCOUNT, AUTO_TRANSFER_ENABLED,
)
def test_no_subscription_blocks_access():
"""Test that no subscription blocks access."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
access = sub.check_access()
assert not access["has_access"]
assert access["status"] == "none"
print(f" No subscription: access blocked β€” '{access['message']}'")
def test_free_trial():
"""Test 7-day free trial."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Start trial
result = sub.start_trial()
assert result["success"]
assert result["status"] == "trial"
assert result["days_remaining"] == 7
print(f" Trial started: {result['days_remaining']} days")
# Access should be granted
access = sub.check_access()
assert access["has_access"]
assert access["status"] == "trial"
print(f" Trial access: granted β€” '{access['message']}'")
# Can't start trial again
result2 = sub.start_trial()
assert not result2["success"]
print(f" Second trial: blocked β€” '{result2['error']}'")
def test_subscribe():
"""Test $1/month subscription."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Subscribe
result = sub.subscribe(create_deposit=False)
assert result["success"]
assert result["status"] == "active"
assert result["price"] == MONTHLY_PRICE
assert result["days_remaining"] >= 29
print(f" Subscribed: ${result['price']:.2f}/month, {result['days_remaining']} days")
# Access granted
access = sub.check_access()
assert access["has_access"]
assert access["status"] == "active"
print(f" Access: granted β€” '{access['message']}'")
# Stats
stats = sub.get_stats()
assert stats["months_subscribed"] == 1
assert stats["total_paid"] == MONTHLY_PRICE
assert stats["auto_renew"] is True
assert len(stats["payment_history"]) == 1
print(f" Stats: {stats['months_subscribed']} month, ${stats['total_paid']:.2f} paid")
def test_subscribe_extends():
"""Test that subscribing while active extends the subscription."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# First subscription
result1 = sub.subscribe(create_deposit=False)
assert result1["success"]
assert result1["days_remaining"] >= 29
# Second subscription should extend
result2 = sub.subscribe(create_deposit=False)
assert result2["success"]
assert result2["days_remaining"] >= 59 # 30 + 30
print(f" Extended: {result2['days_remaining']} days (30 + 30)")
stats = sub.get_stats()
assert stats["months_subscribed"] == 2
assert stats["total_paid"] == MONTHLY_PRICE * 2
print(f" Total: {stats['months_subscribed']} months, ${stats['total_paid']:.2f}")
def test_unsubscribe():
"""Test cancelling subscription."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub.subscribe(create_deposit=False)
# Unsubscribe
result = sub.unsubscribe()
assert result["success"]
assert result["status"] == "cancelled"
print(f" Unsubscribed: {result['message']}")
# Access still works until expiration
access = sub.check_access()
assert access["has_access"] # still has access until expiration
print(f" Access after cancel: still granted until expiration")
def test_expired_blocks_access():
"""Test that expired subscription blocks access."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Subscribe
sub.subscribe(create_deposit=False)
# Manually expire the subscription
sub._state["expiration_date"] = time.time() - 1 # expired 1 second ago
sub._state["auto_renew"] = False
sub._save_state()
# Should enter grace period first
access = sub.check_access()
assert access["has_access"] # grace period
assert access["status"] == "grace"
print(f" Grace period: {access['days_remaining']} days β€” '{access['message']}'")
# Expire grace period
sub._state["expiration_date"] = time.time() - (4 * 86400) # 4 days ago (past 3-day grace)
sub._save_state()
access2 = sub.check_access()
assert not access2["has_access"]
assert access2["status"] == "expired"
print(f" Expired: access blocked β€” '{access2['message']}'")
def test_auto_renew():
"""Test auto-renewal when subscription expires."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub.subscribe(create_deposit=False)
months_before = sub._state["months_subscribed"]
# Simulate expiration with auto-renew on
sub._state["expiration_date"] = time.time() - 1
sub._state["auto_renew"] = True
sub._save_state()
access = sub.check_access()
assert access["has_access"]
assert access["status"] == "active" # auto-renewed
print(f" Auto-renewed: {access['days_remaining']} days β€” '{access['message']}'")
stats = sub.get_stats()
assert stats["months_subscribed"] == months_before + 1
print(f" Months subscribed: {stats['months_subscribed']} (auto-renewed)")
def test_trial_persistence():
"""Test that subscription state persists across restarts."""
with tempfile.TemporaryDirectory() as tmpdir:
sub1 = SubscriptionManager(data_dir=tmpdir)
sub1.subscribe(create_deposit=False)
# Create new instance β€” should load state
sub2 = SubscriptionManager(data_dir=tmpdir)
stats = sub2.get_stats()
assert stats["status"] == "active"
assert stats["months_subscribed"] == 1
print(f" Persisted: status={stats['status']}, months={stats['months_subscribed']}")
access = sub2.check_access()
assert access["has_access"]
print(f" Access after restart: granted")
def test_trial_then_subscribe():
"""Test using trial first, then subscribing."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Start trial
trial = sub.start_trial()
assert trial["success"]
print(f" Trial: {trial['days_remaining']} days")
# Subscribe while on trial
result = sub.subscribe(create_deposit=False)
assert result["success"]
assert result["status"] == "active"
print(f" Subscribed during trial: {result['days_remaining']} days")
# Can't start trial again
trial2 = sub.start_trial()
assert not trial2["success"]
print(f" Trial after subscribe: blocked")
def test_payment_history():
"""Test payment history tracking."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Multiple payments
sub.subscribe(payment_reference="stripe-001", create_deposit=False)
sub.subscribe(payment_reference="stripe-002", create_deposit=False)
sub.subscribe(payment_reference="stripe-003", create_deposit=False)
stats = sub.get_stats()
assert stats["months_subscribed"] == 3
assert stats["total_paid"] == MONTHLY_PRICE * 3
assert len(stats["payment_history"]) == 3
print(f" Payments: {stats['months_subscribed']} months, ${stats['total_paid']:.2f}")
print(f" History: {len(stats['payment_history'])} records")
def test_payment_instructions():
"""Test payment instructions are returned correctly."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Set a fake wallet in state so we don't hit the API
sub._state["founder_wallet"] = "0xABC123DEF456"
sub._founder_wallet = "0xABC123DEF456"
instructions = sub.get_payment_instructions()
assert instructions["amount"] == MONTHLY_PRICE
assert instructions["currency"] == "USD"
assert instructions["period"] == "monthly"
assert instructions["founder_wallet"] == "0xABC123DEF456"
assert instructions["network"] == NETWORK
assert "USDT" in instructions["accepted_tokens"]
assert "USDC" in instructions["accepted_tokens"]
assert "BNB" in instructions["accepted_tokens"]
assert "INC" in instructions["accepted_tokens"]
assert "soulmate_wallet_url" in instructions
assert SOULMATE_API_URL in instructions["soulmate_wallet_url"]
print(f" Amount: ${instructions['amount']:.2f}")
print(f" Wallet: {instructions['founder_wallet']}")
print(f" Network: {instructions['network']}")
print(f" Tokens: {instructions['accepted_tokens']}")
print(f" Google Pay URL: {instructions['soulmate_wallet_url']}")
def test_payment_instructions_with_wallet():
"""Test payment instructions include wallet from state."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub._state["founder_wallet"] = "0xDEADBEEF1234"
sub._founder_wallet = "0xDEADBEEF1234"
instructions = sub.get_payment_instructions()
assert instructions["founder_wallet"] == "0xDEADBEEF1234"
assert "0xDEADBEEF1234" in instructions["instructions"]
print(f" Wallet in instructions: {instructions['founder_wallet']}")
def test_create_deposit():
"""Test deposit creation (mocked API)."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub._state["founder_wallet"] = "0xTEST123"
sub._founder_wallet = "0xTEST123"
# Mock the API call β€” deposit creation will fall back to pending
result = sub.create_deposit("test-user", "USDT")
assert "deposit_id" in result
assert result["founder_wallet"] == "0xTEST123"
assert result["token"] == "USDT"
assert result["amount"] == MONTHLY_PRICE
print(f" Deposit ID: {result['deposit_id'][:16]}...")
print(f" Status: {result.get('status', 'pending')}")
print(f" Wallet: {result['founder_wallet']}")
def test_verify_payment():
"""Test payment verification (mocked API β€” will return error since no real API)."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Verify a non-existent deposit β€” should return some status
result = sub.verify_payment("fake-deposit-123")
assert isinstance(result, dict)
# Without a real API, it'll be "error", "not_found", or have some other status
print(f" Verify result: {result.get('status', 'unknown')} β€” '{result.get('message', '')}'")
def test_subscribe_with_deposit():
"""Test subscribing with deposit creation."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub._state["founder_wallet"] = "0xWALLET456"
sub._founder_wallet = "0xWALLET456"
result = sub.subscribe(user_id="test-user", token="USDT")
assert result["success"]
assert result["status"] == "active"
assert "deposit_id" in result
assert result["founder_wallet"] == "0xWALLET456"
assert "payment" in result
assert result["payment"]["founder_wallet"] == "0xWALLET456"
print(f" Subscribed with deposit: {result['deposit_id'][:16]}...")
print(f" Payment instructions included: {bool(result.get('payment'))}")
# Check payment history has deposit info
stats = sub.get_stats()
last_payment = stats["payment_history"][-1]
assert last_payment["token"] == "USDT"
assert last_payment["deposit_id"] == result["deposit_id"]
assert "0xWALLET456" in last_payment["founder_wallet"] or last_payment["founder_wallet"].startswith("0xWALLET")
print(f" Payment history: token={last_payment['token']}, deposit={last_payment['deposit_id'][:16]}...")
def test_soulmate_config():
"""Test Soulmate OS config constants are set correctly."""
assert SOULMATE_API_URL == "https://191.44.121.29.sslip.io"
assert FOUNDER_EMAIL == "hawpetossjustin25@gmail.com"
assert "USDT" in ACCEPTED_TOKENS
assert "USDC" in ACCEPTED_TOKENS
assert "BNB" in ACCEPTED_TOKENS
assert "INC" in ACCEPTED_TOKENS
assert NETWORK == "BSC (Binance Smart Chain)"
print(f" API URL: {SOULMATE_API_URL}")
print(f" Founder: {FOUNDER_EMAIL}")
print(f" Tokens: {ACCEPTED_TOKENS}")
print(f" Network: {NETWORK}")
def test_founder_unlock_correct_password():
"""Test founder unlock with correct password grants free forever access."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# No access before unlock
access = sub.check_access()
assert not access["has_access"]
# Unlock with correct password
result = sub.founder_unlock(FOUNDER_PASSWORD)
assert result["success"]
assert result["status"] == "founder"
print(f" Unlock: {result['message']}")
# Now has access β€” forever
access = sub.check_access()
assert access["has_access"]
assert access["status"] == "founder"
assert access["days_remaining"] == -1 # forever
print(f" Access: {access['status']} β€” {access['message']}")
def test_founder_unlock_wrong_password():
"""Test founder unlock with wrong password fails."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
result = sub.founder_unlock("wrongpassword123")
assert not result["success"]
assert "Invalid" in result["error"]
print(f" Wrong password: {result['error']}")
# Still no access
access = sub.check_access()
assert not access["has_access"]
print(f" Access after wrong password: blocked")
def test_founder_unlock_persists():
"""Test founder unlock persists across restarts."""
with tempfile.TemporaryDirectory() as tmpdir:
sub1 = SubscriptionManager(data_dir=tmpdir)
sub1.founder_unlock(FOUNDER_PASSWORD)
# New instance should load founder status
sub2 = SubscriptionManager(data_dir=tmpdir)
access = sub2.check_access()
assert access["has_access"]
assert access["status"] == "founder"
print(f" Persisted: status={access['status']}, forever={access['days_remaining'] == -1}")
def test_founder_unlock_bypasses_payment():
"""Test founder doesn't need to pay β€” access is free forever."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub.founder_unlock(FOUNDER_PASSWORD)
# Founder should have no payment history
stats = sub.get_stats()
assert stats["months_subscribed"] == 0
assert stats["total_paid"] == 0.0
print(f" Founder payments: ${stats['total_paid']:.2f} (free)")
# But has full access
access = sub.check_access()
assert access["has_access"]
print(f" Founder access: free forever")
def test_auto_transfer_init():
"""Test auto-transfer state initializes correctly."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub._init_auto_transfer()
assert "auto_transfer_history" in sub._state
assert "transferred_payments" in sub._state
assert "auto_transfer_enabled" in sub._state
print(f" Auto-transfer enabled: {sub._state['auto_transfer_enabled']}")
def test_auto_transfer_stats_empty():
"""Test auto-transfer stats with no transfers."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
stats = sub.get_auto_transfer_stats()
assert stats["transfer_count"] == 0
assert stats["total_transferred"] == 0.0
assert "auto_transfer_enabled" in stats
print(f" Stats: {stats['transfer_count']} transfers, ${stats['total_transferred']:.2f}")
def test_auto_transfer_process_no_payments():
"""Test auto-transfer when there are no payments to transfer."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
result = sub.process_auto_transfers()
assert result["status"] == "ok"
assert result["transfers_made"] == 0
print(f" No payments: {result['message']}")
def test_auto_transfer_process_with_payment():
"""Test auto-transfer processes a confirmed $1 payment."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Simulate a confirmed payment
sub.subscribe(payment_reference="test-pay-001", create_deposit=False)
# Process auto-transfers
result = sub.process_auto_transfers()
assert result["status"] == "ok"
assert result["transfers_made"] == 1
assert result["total_amount"] == MONTHLY_PRICE
print(f" Processed: {result['transfers_made']} transfer(s), ${result['total_amount']:.2f}")
# Verify transfer recorded
stats = sub.get_auto_transfer_stats()
assert stats["transfer_count"] == 1
assert stats["total_transferred"] == MONTHLY_PRICE
print(f" Recorded: {stats['transfer_count']} transfer(s), ${stats['total_transferred']:.2f}")
def test_auto_transfer_no_duplicates():
"""Test auto-transfer doesn't transfer the same payment twice."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
sub.subscribe(payment_reference="test-pay-002", create_deposit=False)
# First transfer
result1 = sub.process_auto_transfers()
assert result1["transfers_made"] == 1
# Second call should not re-transfer
result2 = sub.process_auto_transfers()
assert result2["transfers_made"] == 0
assert "No pending transfers" in result2["message"]
print(f" No duplicates: first={result1['transfers_made']}, second={result2['transfers_made']}")
def test_auto_transfer_toggle():
"""Test enabling/disabling auto-transfer."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Disable
result = sub.set_auto_transfer(False)
assert result["success"]
assert not result["auto_transfer_enabled"]
# Process should be skipped
sub.subscribe(payment_reference="test-pay-003", create_deposit=False)
process_result = sub.process_auto_transfers()
assert process_result["status"] == "disabled"
print(f" Disabled: {process_result['message']}")
# Re-enable
result = sub.set_auto_transfer(True)
assert result["success"]
assert result["auto_transfer_enabled"]
print(f" Re-enabled: {result['message']}")
def test_auto_transfer_multiple_payments():
"""Test auto-transfer processes multiple payments at once."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
# Three payments
sub.subscribe(payment_reference="pay-001", create_deposit=False)
sub.subscribe(payment_reference="pay-002", create_deposit=False)
sub.subscribe(payment_reference="pay-003", create_deposit=False)
# Process all
result = sub.process_auto_transfers()
assert result["transfers_made"] == 3
assert result["total_amount"] == MONTHLY_PRICE * 3
print(f" Batch: {result['transfers_made']} transfers, ${result['total_amount']:.2f}")
stats = sub.get_auto_transfer_stats()
assert stats["transfer_count"] == 3
assert stats["total_transferred"] == MONTHLY_PRICE * 3
print(f" Total: {stats['transfer_count']} transfers, ${stats['total_transferred']:.2f}")
def test_bank_info():
"""Test bank info returns masked account details."""
with tempfile.TemporaryDirectory() as tmpdir:
sub = SubscriptionManager(data_dir=tmpdir)
info = sub.get_bank_info()
assert "routing_number" in info
assert "account_number" in info
assert "auto_transfer_enabled" in info
assert "total_transferred" in info
# Should be masked or "Not set"
assert info["routing_number"] == "Not set" or "****" in info["routing_number"]
assert info["account_number"] == "Not set" or "****" in info["account_number"]
print(f" Routing: {info['routing_number']}")
print(f" Account: {info['account_number']}")
def test_auto_transfer_persists():
"""Test auto-transfer history persists across restarts."""
with tempfile.TemporaryDirectory() as tmpdir:
sub1 = SubscriptionManager(data_dir=tmpdir)
sub1.subscribe(payment_reference="persist-pay-001", create_deposit=False)
sub1.process_auto_transfers()
# New instance
sub2 = SubscriptionManager(data_dir=tmpdir)
stats = sub2.get_auto_transfer_stats()
assert stats["transfer_count"] == 1
assert stats["total_transferred"] == MONTHLY_PRICE
print(f" Persisted: {stats['transfer_count']} transfers, ${stats['total_transferred']:.2f}")
if __name__ == "__main__":
print("Running subscription manager tests...")
test_no_subscription_blocks_access()
print(" βœ“ test_no_subscription_blocks_access")
test_free_trial()
print(" βœ“ test_free_trial")
test_subscribe()
print(" βœ“ test_subscribe")
test_subscribe_extends()
print(" βœ“ test_subscribe_extends")
test_unsubscribe()
print(" βœ“ test_unsubscribe")
test_expired_blocks_access()
print(" βœ“ test_expired_blocks_access")
test_auto_renew()
print(" βœ“ test_auto_renew")
test_trial_persistence()
print(" βœ“ test_trial_persistence")
test_trial_then_subscribe()
print(" βœ“ test_trial_then_subscribe")
test_payment_history()
print(" βœ“ test_payment_history")
test_payment_instructions()
print(" βœ“ test_payment_instructions")
test_payment_instructions_with_wallet()
print(" βœ“ test_payment_instructions_with_wallet")
test_create_deposit()
print(" βœ“ test_create_deposit")
test_verify_payment()
print(" βœ“ test_verify_payment")
test_subscribe_with_deposit()
print(" βœ“ test_subscribe_with_deposit")
test_soulmate_config()
print(" βœ“ test_soulmate_config")
test_founder_unlock_correct_password()
print(" βœ“ test_founder_unlock_correct_password")
test_founder_unlock_wrong_password()
print(" βœ“ test_founder_unlock_wrong_password")
test_founder_unlock_persists()
print(" βœ“ test_founder_unlock_persists")
test_founder_unlock_bypasses_payment()
print(" βœ“ test_founder_unlock_bypasses_payment")
test_auto_transfer_init()
print(" βœ“ test_auto_transfer_init")
test_auto_transfer_stats_empty()
print(" βœ“ test_auto_transfer_stats_empty")
test_auto_transfer_process_no_payments()
print(" βœ“ test_auto_transfer_process_no_payments")
test_auto_transfer_process_with_payment()
print(" βœ“ test_auto_transfer_process_with_payment")
test_auto_transfer_no_duplicates()
print(" βœ“ test_auto_transfer_no_duplicates")
test_auto_transfer_toggle()
print(" βœ“ test_auto_transfer_toggle")
test_auto_transfer_multiple_payments()
print(" βœ“ test_auto_transfer_multiple_payments")
test_bank_info()
print(" βœ“ test_bank_info")
test_auto_transfer_persists()
print(" βœ“ test_auto_transfer_persists")
print("\nAll subscription tests passed!")