From 8d31680ff1932af31ca5acc90c57bcbe09eae379 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 6 Jul 2023 01:18:39 -0400 Subject: [PATCH] David/referral test new (#162) * working on test for referral * refactored logic in tests to helper functions * added getbalance helper * added more helper functions to test for referral * gotta be able to submit to rpc now * adding provider instead * referral tests are not passing, may be because we need for stats to be updated * balance doesnt decrease * will look into deposits in the meantime * finding some first bugs * seems to have fixed a bunch of stuff * feedback, lint, and make it compile --------- Co-authored-by: Bryan Stitt --- web3_proxy/src/stats/mod.rs | 10 +- .../tests/common/admin_increases_balance.rs | 46 ++++ web3_proxy/tests/common/create_admin.rs | 101 ++++++++ web3_proxy/tests/common/create_user.rs | 47 ++++ web3_proxy/tests/common/get_rpc_key.rs | 55 ++++ web3_proxy/tests/common/get_user_balance.rs | 26 ++ web3_proxy/tests/common/mod.rs | 6 + web3_proxy/tests/common/referral.rs | 124 +++++++++ web3_proxy/tests/test_admins.rs | 168 ++---------- web3_proxy/tests/test_users.rs | 240 +++++++++++++++++- 10 files changed, 667 insertions(+), 156 deletions(-) create mode 100644 web3_proxy/tests/common/admin_increases_balance.rs create mode 100644 web3_proxy/tests/common/create_admin.rs create mode 100644 web3_proxy/tests/common/create_user.rs create mode 100644 web3_proxy/tests/common/get_rpc_key.rs create mode 100644 web3_proxy/tests/common/get_user_balance.rs create mode 100644 web3_proxy/tests/common/referral.rs diff --git a/web3_proxy/src/stats/mod.rs b/web3_proxy/src/stats/mod.rs index c39287cb..b8c6a6bc 100644 --- a/web3_proxy/src/stats/mod.rs +++ b/web3_proxy/src/stats/mod.rs @@ -413,8 +413,8 @@ impl BufferedRpcQueryStats { deltas.balance_spent_including_free_credits = self.sum_credits_used; deltas.balance_spent_excluding_free_credits = self.sum_credits_used; } else { - deltas.balance_spent_including_free_credits = user_balance; - deltas.balance_spent_excluding_free_credits = self.sum_credits_used; + deltas.balance_spent_including_free_credits = self.sum_credits_used; + deltas.balance_spent_excluding_free_credits = user_balance; } Ok((deltas, Some((referral_entity, referrer_code_entity)))) @@ -428,8 +428,8 @@ impl BufferedRpcQueryStats { deltas.balance_spent_including_free_credits = self.sum_credits_used; deltas.balance_spent_excluding_free_credits = self.sum_credits_used; } else { - deltas.balance_spent_including_free_credits = user_balance; - deltas.balance_spent_excluding_free_credits = self.sum_credits_used; + deltas.balance_spent_including_free_credits = self.sum_credits_used; + deltas.balance_spent_excluding_free_credits = user_balance; } Ok((deltas, None)) @@ -575,7 +575,6 @@ impl BufferedRpcQueryStats { deltas: &Deltas, db_conn: &DatabaseConnection, sender_rpc_entity: &rpc_key::Model, - referral_objects: &Option<(referee::Model, referrer::Model)>, rpc_secret_key_cache: &RpcSecretKeyCache, user_balance_cache: &UserBalanceCache, ) -> Web3ProxyResult<()> { @@ -710,7 +709,6 @@ impl BufferedRpcQueryStats { &deltas, db_conn, &sender_rpc_entity, - &referral_objects, rpc_secret_key_cache, user_balance_cache, ) diff --git a/web3_proxy/tests/common/admin_increases_balance.rs b/web3_proxy/tests/common/admin_increases_balance.rs new file mode 100644 index 00000000..ff05c1cf --- /dev/null +++ b/web3_proxy/tests/common/admin_increases_balance.rs @@ -0,0 +1,46 @@ +use crate::TestApp; +use ethers::prelude::{LocalWallet, Signer}; +use rust_decimal::Decimal; +use tracing::info; +use web3_proxy::frontend::admin::AdminIncreaseBalancePost; +use web3_proxy::frontend::users::authentication::LoginPostResponse; + +/// Helper function to increase the balance of a user, from an admin +#[allow(unused)] +pub async fn admin_increase_balance( + x: &TestApp, + r: &reqwest::Client, + admin_login_response: &LoginPostResponse, + target_wallet: &LocalWallet, + amount: Decimal, +) -> serde_json::Value { + let increase_balance_post_url = format!("{}admin/increase_balance", x.proxy_provider.url()); + info!("Increasing balance"); + // Login the user + // Use the bearer token of admin to increase user balance + let increase_balance_data = AdminIncreaseBalancePost { + user_address: target_wallet.address(), // set user address to increase balance + amount, // set amount to increase + note: Some("Test increasing balance".to_string()), + }; + info!(?increase_balance_post_url); + info!(?increase_balance_data); + info!(?admin_login_response.bearer_token); + + let increase_balance_response = r + .post(increase_balance_post_url) + .json(&increase_balance_data) + .bearer_auth(admin_login_response.bearer_token) + .send() + .await + .unwrap(); + info!(?increase_balance_response, "http response"); + + let increase_balance_response = increase_balance_response + .json::() + .await + .unwrap(); + info!(?increase_balance_response, "json response"); + + increase_balance_response +} diff --git a/web3_proxy/tests/common/create_admin.rs b/web3_proxy/tests/common/create_admin.rs new file mode 100644 index 00000000..e40771cf --- /dev/null +++ b/web3_proxy/tests/common/create_admin.rs @@ -0,0 +1,101 @@ +use crate::TestApp; +use ethers::prelude::{LocalWallet, Signer}; +use ethers::types::Signature; +use tracing::info; +use web3_proxy::frontend::users::authentication::{LoginPostResponse, PostLogin}; +use web3_proxy::sub_commands::ChangeAdminStatusSubCommand; + +/// Helper function to create admin + +/// Create user as admin +#[allow(unused)] +pub async fn create_user_as_admin( + x: &TestApp, + r: &reqwest::Client, + admin_wallet: &LocalWallet, +) -> LoginPostResponse { + // Create the account + let login_post_url = format!("{}user/login", x.proxy_provider.url()); + let admin_login_get_url = format!( + "{}user/login/{:?}", + x.proxy_provider.url(), + admin_wallet.address() + ); + let admin_login_message = r.get(admin_login_get_url).send().await.unwrap(); + let admin_login_message = admin_login_message.text().await.unwrap(); + + // Sign the message and POST it to login as admin + let admin_signed: Signature = admin_wallet + .sign_message(&admin_login_message) + .await + .unwrap(); + info!(?admin_signed); + + let admin_post_login_data = PostLogin { + msg: admin_login_message, + sig: admin_signed.to_string(), + referral_code: None, + }; + info!(?admin_post_login_data); + + let admin_login_response = r + .post(&login_post_url) + .json(&admin_post_login_data) + .send() + .await + .unwrap() + .json::() + .await + .unwrap(); + info!(?admin_login_response); + + // Upgrade the account to admin + info!("Make the user an admin ..."); + // Change Admin SubCommand struct + let admin_status_changer = ChangeAdminStatusSubCommand { + address: format!("{:?}", admin_wallet.address()), + should_be_admin: true, + }; + info!(?admin_status_changer); + + info!("Changing the status of the admin_wallet to be an admin"); + // Pass on the database into it ... + admin_status_changer.main(x.db_conn()).await.unwrap(); + + // Now log him in again, because he was just signed out + // Login the admin again, because he was just signed out + let admin_login_get_url = format!( + "{}user/login/{:?}", + x.proxy_provider.url(), + admin_wallet.address() + ); + let admin_login_message = r.get(admin_login_get_url).send().await.unwrap(); + let admin_login_message = admin_login_message.text().await.unwrap(); + + // Sign the message and POST it to login as admin + let admin_signed: Signature = admin_wallet + .sign_message(&admin_login_message) + .await + .unwrap(); + info!(?admin_signed); + + let admin_post_login_data = PostLogin { + msg: admin_login_message, + sig: admin_signed.to_string(), + referral_code: None, + }; + info!(?admin_post_login_data); + + let admin_login_response = r + .post(&login_post_url) + .json(&admin_post_login_data) + .send() + .await + .unwrap() + .json::() + .await + .unwrap(); + info!(?admin_login_response); + + admin_login_response +} diff --git a/web3_proxy/tests/common/create_user.rs b/web3_proxy/tests/common/create_user.rs new file mode 100644 index 00000000..e9a183ff --- /dev/null +++ b/web3_proxy/tests/common/create_user.rs @@ -0,0 +1,47 @@ +use crate::TestApp; +use ethers::prelude::{LocalWallet, Signer}; +use ethers::types::Signature; +use tracing::info; +use web3_proxy::frontend::users::authentication::{LoginPostResponse, PostLogin}; + +/// Helper function to create an "ordinary" user +#[allow(unused)] +pub async fn create_user( + x: &TestApp, + r: &reqwest::Client, + user_wallet: &LocalWallet, + referral_code: Option, +) -> (LoginPostResponse) { + let login_post_url = format!("{}user/login", x.proxy_provider.url()); + let user_login_get_url = format!( + "{}user/login/{:?}", + x.proxy_provider.url(), + user_wallet.address() + ); + let user_login_message = r.get(user_login_get_url).send().await.unwrap(); + let user_login_message = user_login_message.text().await.unwrap(); + + // Sign the message and POST it to login as the user + let user_signed: Signature = user_wallet.sign_message(&user_login_message).await.unwrap(); + info!(?user_signed); + + let user_post_login_data = PostLogin { + msg: user_login_message, + sig: user_signed.to_string(), + referral_code, + }; + info!(?user_post_login_data); + + let user_login_response = r + .post(&login_post_url) + .json(&user_post_login_data) + .send() + .await + .unwrap() + .json::() + .await + .unwrap(); + info!(?user_login_response); + + user_login_response +} diff --git a/web3_proxy/tests/common/get_rpc_key.rs b/web3_proxy/tests/common/get_rpc_key.rs new file mode 100644 index 00000000..6bfbf702 --- /dev/null +++ b/web3_proxy/tests/common/get_rpc_key.rs @@ -0,0 +1,55 @@ +use crate::TestApp; +use serde::Deserialize; +use tracing::info; +use ulid::Ulid; +use web3_proxy::frontend::users::authentication::LoginPostResponse; + +#[derive(Debug, Deserialize)] +pub struct RpcKeyResponse { + pub user_id: u64, + pub user_rpc_keys: std::collections::HashMap, +} + +#[derive(Debug, Deserialize)] +pub struct RpcKey { + pub active: bool, + pub allowed_ips: Option, + pub allowed_origins: Option, + pub allowed_referers: Option, + pub allowed_user_agents: Option, + pub description: Option, + pub id: u64, + pub log_revert_chance: f64, + pub private_txs: bool, + pub role: String, + pub secret_key: Ulid, + pub user_id: u64, +} + +/// Helper function to get the user's balance +#[allow(unused)] +pub async fn user_get_first_rpc_key( + x: &TestApp, + r: &reqwest::Client, + login_response: &LoginPostResponse, +) -> RpcKey { + let get_keys = format!("{}user/keys", x.proxy_provider.url()); + + info!("Get balance"); + let rpc_key_response = r + .get(get_keys) + .bearer_auth(login_response.bearer_token) + .send() + .await + .unwrap(); + info!(?rpc_key_response); + + let rpc_key_response = rpc_key_response.json::().await.unwrap(); + info!(?rpc_key_response); + + info!("Rpc Key"); + let rpc_key: RpcKeyResponse = serde_json::from_value(rpc_key_response).unwrap(); + info!(?rpc_key); + + rpc_key.user_rpc_keys.into_iter().next().unwrap().1 +} diff --git a/web3_proxy/tests/common/get_user_balance.rs b/web3_proxy/tests/common/get_user_balance.rs new file mode 100644 index 00000000..88d5d97e --- /dev/null +++ b/web3_proxy/tests/common/get_user_balance.rs @@ -0,0 +1,26 @@ +use crate::TestApp; +use tracing::info; +use web3_proxy::frontend::users::authentication::LoginPostResponse; + +/// Helper function to get the user's balance +#[allow(unused)] +pub async fn user_get_balance( + x: &TestApp, + r: &reqwest::Client, + login_response: &LoginPostResponse, +) -> (serde_json::Value) { + let get_user_balance = format!("{}user/balance", x.proxy_provider.url()); + info!("Get balance"); + let balance_response = r + .get(get_user_balance) + .bearer_auth(login_response.bearer_token) + .send() + .await + .unwrap(); + info!(?balance_response); + + let balance_response = balance_response.json::().await.unwrap(); + info!(?balance_response); + + balance_response +} diff --git a/web3_proxy/tests/common/mod.rs b/web3_proxy/tests/common/mod.rs index 8c9bc1e4..6333cff2 100644 --- a/web3_proxy/tests/common/mod.rs +++ b/web3_proxy/tests/common/mod.rs @@ -1,3 +1,9 @@ +pub mod admin_increases_balance; pub mod app; +pub mod create_admin; +pub mod create_user; +pub mod get_rpc_key; +pub mod get_user_balance; +pub mod referral; pub use self::app::TestApp; diff --git a/web3_proxy/tests/common/referral.rs b/web3_proxy/tests/common/referral.rs new file mode 100644 index 00000000..639d3a8d --- /dev/null +++ b/web3_proxy/tests/common/referral.rs @@ -0,0 +1,124 @@ +/// Helper for referral functions +/// Includes +/// - get referral link +/// - getting code for referral (shared and used) +use crate::TestApp; +use tracing::info; +use ulid::Ulid; +use web3_proxy::frontend::users::authentication::LoginPostResponse; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct UserSharedReferralInfo { + pub user: User, + pub referrals: Vec, + pub used_referral_code: Ulid, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct UserUsedReferralInfo { + pub user: User, + pub referrals: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct User { + pub address: String, + pub description: Option, + pub email: Option, + pub id: u64, + pub user_tier_id: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Referral { + pub credits_applied_for_referee: bool, + pub credits_applied_for_referrer: String, + pub referral_start_date: String, + pub referred_address: Option, + pub used_referral_code: Option, +} + +/// Helper function to create an "ordinary" user +#[allow(unused)] +pub async fn get_referral_code( + x: &TestApp, + r: &reqwest::Client, + login_response: &LoginPostResponse, +) -> String { + let get_referral_link = format!("{}user/referral", x.proxy_provider.url()); + + // The referrer makes sure that the user is registered as a referred used + let referral_link = r + .get(&get_referral_link) + .bearer_auth(login_response.bearer_token) + .send() + .await + .unwrap(); + info!(?referral_link); + let referral_link = referral_link.json::().await.unwrap(); + info!("Referrer get link"); + info!(?referral_link); + let referral_link = referral_link["referral_code"].as_str().unwrap().to_string(); + info!(?referral_link); + + referral_link +} + +#[allow(unused)] +pub async fn get_shared_referral_codes( + x: &TestApp, + r: &reqwest::Client, + login_response: &LoginPostResponse, +) -> UserSharedReferralInfo { + let check_shared_referral_link = + format!("{}user/referral/stats/shared-codes", x.proxy_provider.url()); + info!("Get balance"); + let shared_referral_codes = r + .get(check_shared_referral_link) + .bearer_auth(login_response.bearer_token) + .send() + .await + .unwrap(); + info!(?shared_referral_codes); + + let shared_referral_codes = shared_referral_codes + .json::() + .await + .unwrap(); + info!(?shared_referral_codes); + + let user_referral_info: UserSharedReferralInfo = + serde_json::from_value(shared_referral_codes).unwrap(); + + user_referral_info +} + +#[allow(unused)] +pub async fn get_used_referral_codes( + x: &TestApp, + r: &reqwest::Client, + login_response: &LoginPostResponse, +) -> UserUsedReferralInfo { + let check_used_referral_link = + format!("{}user/referral/stats/used-codes", x.proxy_provider.url()); + info!("Get balance"); + let used_referral_codes = r + .get(check_used_referral_link) + .bearer_auth(login_response.bearer_token) + .send() + .await + .unwrap(); + info!(?used_referral_codes); + + let used_referral_codes = used_referral_codes + .json::() + .await + .unwrap(); + info!(?used_referral_codes); + + let user_referral_info: UserUsedReferralInfo = + serde_json::from_value(used_referral_codes).unwrap(); + user_referral_info +} diff --git a/web3_proxy/tests/test_admins.rs b/web3_proxy/tests/test_admins.rs index 08736805..67efc558 100644 --- a/web3_proxy/tests/test_admins.rs +++ b/web3_proxy/tests/test_admins.rs @@ -3,14 +3,13 @@ mod common; use std::str::FromStr; use std::time::Duration; +use crate::common::admin_increases_balance::admin_increase_balance; +use crate::common::create_admin::create_user_as_admin; +use crate::common::create_user::create_user; +use crate::common::get_user_balance::user_get_balance; use crate::common::TestApp; -use ethers::prelude::Signer; -use ethers::types::Signature; use rust_decimal::Decimal; use tracing::info; -use web3_proxy::frontend::admin::AdminIncreaseBalancePost; -use web3_proxy::frontend::users::authentication::{LoginPostResponse, PostLogin}; -use web3_proxy::sub_commands::ChangeAdminStatusSubCommand; // #[cfg_attr(not(feature = "tests-needing-docker"), ignore)] #[ignore = "under construction"] @@ -32,157 +31,34 @@ async fn test_admin_grant_credits() { .unwrap(); // Setup variables that will be used - let login_post_url = format!("{}user/login", x.proxy_provider.url()); - let increase_balance_post_url = format!("{}admin/increase_balance", x.proxy_provider.url()); - + let user_wallet = x.wallet(0); let admin_wallet = x.wallet(1); - let user_wallet = x.wallet(2); + info!(?admin_wallet); - // Login the admin to create their account. they aren't an admin yet - let admin_login_get_url = format!( - "{}user/login/{:?}", - x.proxy_provider.url(), - admin_wallet.address() - ); - let admin_login_message = r.get(admin_login_get_url).send().await.unwrap(); - let admin_login_message = admin_login_message.text().await.unwrap(); - - // Sign the message and POST it to login as admin - let admin_signed: Signature = admin_wallet - .sign_message(&admin_login_message) - .await - .unwrap(); - info!(?admin_signed); - - let admin_post_login_data = PostLogin { - msg: admin_login_message, - sig: admin_signed.to_string(), - referral_code: None, - }; - info!(?admin_post_login_data); - - let admin_login_response = r - .post(&login_post_url) - .json(&admin_post_login_data) - .send() - .await - .unwrap() - .json::() - .await - .unwrap(); + let user_login_response = create_user(&x, &r, &user_wallet, None).await; + let admin_login_response = create_user_as_admin(&x, &r, &admin_wallet).await; info!(?admin_login_response); - // Also login the user (to create the user) - let user_login_get_url = format!( - "{}user/login/{:?}", - x.proxy_provider.url(), - user_wallet.address() - ); - let user_login_message = r.get(user_login_get_url).send().await.unwrap(); - let user_login_message = user_login_message.text().await.unwrap(); + let increase_balance_response = admin_increase_balance( + &x, + &r, + &admin_login_response, + &user_wallet, + Decimal::from(100), + ) + .await; - // Sign the message and POST it to login as the user - let user_signed: Signature = user_wallet.sign_message(&user_login_message).await.unwrap(); - info!(?user_signed); - - let user_post_login_data = PostLogin { - msg: user_login_message, - sig: user_signed.to_string(), - referral_code: None, - }; - info!(?user_post_login_data); - - let user_login_response = r - .post(&login_post_url) - .json(&user_post_login_data) - .send() - .await - .unwrap() - .json::() - .await - .unwrap(); - info!(?user_login_response); - - info!("Make the user an admin ..."); - // Change Admin SubCommand struct - let admin_status_changer = ChangeAdminStatusSubCommand { - address: format!("{:?}", admin_wallet.address()), - should_be_admin: true, - }; - info!(?admin_status_changer); - - info!("Changing the status of the admin_wallet to be an admin"); - // Pass on the database into it ... - admin_status_changer.main(x.db_conn()).await.unwrap(); - - // Login the admin again, because he was just signed out - let admin_login_get_url = format!( - "{}user/login/{:?}", - x.proxy_provider.url(), - admin_wallet.address() - ); - let admin_login_message = r.get(admin_login_get_url).send().await.unwrap(); - let admin_login_message = admin_login_message.text().await.unwrap(); - - // Sign the message and POST it to login as admin - let admin_signed: Signature = admin_wallet - .sign_message(&admin_login_message) - .await - .unwrap(); - info!(?admin_signed); - - let admin_post_login_data = PostLogin { - msg: admin_login_message, - sig: admin_signed.to_string(), - referral_code: None, - }; - info!(?admin_post_login_data); - - let admin_login_response = r - .post(&login_post_url) - .json(&admin_post_login_data) - .send() - .await - .unwrap() - .json::() - .await - .unwrap(); - info!(?admin_login_response); - - info!("Increasing balance"); - // Login the user - // Use the bearer token of admin to increase user balance - let increase_balance_data = AdminIncreaseBalancePost { - user_address: user_wallet.address(), // set user address to increase balance - amount: Decimal::from(100), // set amount to increase - note: Some("Test increasing balance".to_string()), - }; - info!(?increase_balance_post_url); - info!(?increase_balance_data); - info!(?admin_login_response.bearer_token); - - let increase_balance_response = r - .post(increase_balance_post_url) - .json(&increase_balance_data) - .bearer_auth(admin_login_response.bearer_token) - .send() - .await - .unwrap(); - info!(?increase_balance_response, "http response"); - - let increase_balance_response = increase_balance_response - .json::() - .await - .unwrap(); - info!(?increase_balance_response, "json response"); - - // Check if the response is as expected - // TODO: assert_eq!(increase_balance_response["user"], user_wallet.address()); assert_eq!( Decimal::from_str(increase_balance_response["amount"].as_str().unwrap()).unwrap(), Decimal::from(100) ); + let user_balance_response = user_get_balance(&x, &r, &user_login_response).await; + assert_eq!( + Decimal::from_str(user_balance_response["balance"].as_str().unwrap()).unwrap(), + Decimal::from(100) + ); + x.wait().await; } diff --git a/web3_proxy/tests/test_users.rs b/web3_proxy/tests/test_users.rs index 5603c8b8..5867ae38 100644 --- a/web3_proxy/tests/test_users.rs +++ b/web3_proxy/tests/test_users.rs @@ -1,11 +1,25 @@ mod common; +use crate::common::admin_increases_balance::admin_increase_balance; +use crate::common::create_admin::create_user_as_admin; +use crate::common::create_user::create_user; +use crate::common::get_rpc_key::{user_get_first_rpc_key, RpcKey}; +use crate::common::get_user_balance::user_get_balance; +use crate::common::referral::{ + get_referral_code, get_shared_referral_codes, get_used_referral_codes, UserSharedReferralInfo, + UserUsedReferralInfo, +}; use crate::common::TestApp; +use ethers::prelude::{Http, Provider}; use ethers::{signers::Signer, types::Signature}; +use rust_decimal::Decimal; use serde::Deserialize; +use std::str::FromStr; +use std::time::Duration; use tracing::{debug, info, trace}; use ulid::Ulid; use web3_proxy::frontend::users::authentication::PostLogin; +use web3_proxy::rpcs::blockchain::ArcBlock; /// TODO: use this type in the frontend #[derive(Debug, Deserialize)] @@ -73,11 +87,229 @@ async fn test_log_in_and_out() { assert_eq!(logout_response, "goodbye"); } -// #[cfg_attr(not(feature = "tests-needing-docker"), ignore)] -#[ignore = "under construction"] +#[cfg_attr(not(feature = "tests-needing-docker"), ignore)] #[test_log::test(tokio::test)] -async fn test_referral_bonus() { +async fn test_user_balance_decreases() { + info!("Starting balance decreases with usage test"); let x = TestApp::spawn(true).await; + let r = reqwest::Client::builder() + .timeout(Duration::from_secs(20)) + .build() + .unwrap(); - todo!(); + let user_wallet = x.wallet(0); + let admin_wallet = x.wallet(1); + + // Create three users, one referrer, one admin who bumps both their balances + let admin_login_response = create_user_as_admin(&x, &r, &admin_wallet).await; + let user_login_response = create_user(&x, &r, &user_wallet, None).await; + + // Get the rpc keys for this user + let rpc_keys: RpcKey = user_get_first_rpc_key(&x, &r, &user_login_response).await; + let proxy_endpoint = format!("{}rpc/{}", x.proxy_provider.url(), rpc_keys.secret_key); + let proxy_provider = Provider::::try_from(proxy_endpoint).unwrap(); + + // Make somre requests while in the free tier, so we can test bookkeeping here + for _ in 1..10_000 { + let _ = proxy_provider + .request::<_, Option>("eth_getBlockByNumber", ("latest", false)) + .await + .unwrap() + .unwrap(); + } + + // Flush all stats here + let (influx_count, mysql_count) = x.flush_stats().await.unwrap(); + assert_eq!(influx_count, 0); + assert!(mysql_count > 0); + + // Bump both user's wallet to $20 + admin_increase_balance( + &x, + &r, + &admin_login_response, + &user_wallet, + Decimal::from(20), + ) + .await; + let user_balance_response = user_get_balance(&x, &r, &user_login_response).await; + let user_balance_pre = + Decimal::from_str(user_balance_response["balance"].as_str().unwrap()).unwrap(); + assert_eq!(user_balance_pre, Decimal::from(20)); + + for _ in 1..10_000 { + let _ = proxy_provider + .request::<_, Option>("eth_getBlockByNumber", ("latest", false)) + .await + .unwrap() + .unwrap(); + } + + // Flush all stats here + let (influx_count, mysql_count) = x.flush_stats().await.unwrap(); + assert_eq!(influx_count, 0); + assert!(mysql_count > 0); + + // Deposits should not be affected, and should be equal to what was initially provided + let total_deposits = + Decimal::from_str(user_balance_response["total_deposits"].as_str().unwrap()).unwrap(); + assert_eq!(total_deposits, Decimal::from(20)); + + // Get the full balance endpoint + let user_balance_response = user_get_balance(&x, &r, &user_login_response).await; + let user_balance_post = + Decimal::from_str(user_balance_response["balance"].as_str().unwrap()).unwrap(); + assert!(user_balance_post < user_balance_pre); + + // Balance should be total deposits - usage while in the paid tier + let total_spent_outside_free_tier = Decimal::from_str( + user_balance_response["total_spent_outside_free_tier"] + .as_str() + .unwrap(), + ) + .unwrap(); + assert_eq!( + total_deposits - total_spent_outside_free_tier, + user_balance_post + ); + + // This should never be negative + let user_balance_total_spent = + Decimal::from_str(user_balance_response["total_spent"].as_str().unwrap()).unwrap(); + assert!(user_balance_total_spent > Decimal::from(0)); +} + +#[cfg_attr(not(feature = "tests-needing-docker"), ignore)] +#[test_log::test(tokio::test)] +async fn test_referral_bonus_non_concurrent() { + info!("Starting referral bonus test"); + let x = TestApp::spawn(true).await; + let r = reqwest::Client::builder() + .timeout(Duration::from_secs(20)) + .build() + .unwrap(); + + let user_wallet = x.wallet(0); + let referrer_wallet = x.wallet(1); + let admin_wallet = x.wallet(2); + + // Create three users, one referrer, one admin who bumps both their balances + let referrer_login_response = create_user(&x, &r, &referrer_wallet, None).await; + let admin_login_response = create_user_as_admin(&x, &r, &admin_wallet).await; + // Get the first user's referral link + let referral_link = get_referral_code(&x, &r, &referrer_login_response).await; + + let user_login_response = create_user(&x, &r, &user_wallet, Some(referral_link.clone())).await; + + // Bump both user's wallet to $20 + admin_increase_balance( + &x, + &r, + &admin_login_response, + &user_wallet, + Decimal::from(20), + ) + .await; + admin_increase_balance( + &x, + &r, + &admin_login_response, + &referrer_wallet, + Decimal::from(20), + ) + .await; + + // Get balance before for both users + let user_balance_response = user_get_balance(&x, &r, &user_login_response).await; + let user_balance_pre = + Decimal::from_str(user_balance_response["balance"].as_str().unwrap()).unwrap(); + let referrer_balance_response = user_get_balance(&x, &r, &referrer_login_response).await; + let referrer_balance_pre = + Decimal::from_str(referrer_balance_response["balance"].as_str().unwrap()).unwrap(); + + // Make sure they both have balance now + assert_eq!(user_balance_pre, Decimal::from(20)); + assert_eq!(referrer_balance_pre, Decimal::from(20)); + + // Setup variables that will be used + let shared_referral_code: UserSharedReferralInfo = + get_shared_referral_codes(&x, &r, &referrer_login_response).await; + let used_referral_code: UserUsedReferralInfo = + get_used_referral_codes(&x, &r, &user_login_response).await; + + // assert that the used referral code is used + assert_eq!( + format!("{:?}", user_wallet.address()), + shared_referral_code + .clone() + .referrals + .get(0) + .unwrap() + .referred_address + .clone() + .unwrap() + ); + assert_eq!( + referral_link.clone(), + used_referral_code + .clone() + .referrals + .get(0) + .unwrap() + .used_referral_code + .clone() + .unwrap() + ); + + // Make a for-loop just spam it a bit + // Make a JSON request + let rpc_keys: RpcKey = user_get_first_rpc_key(&x, &r, &user_login_response).await; + info!("Rpc key is: {:?}", rpc_keys); + + let proxy_endpoint = format!("{}rpc/{}", x.proxy_provider.url(), rpc_keys.secret_key); + let proxy_provider = Provider::::try_from(proxy_endpoint).unwrap(); + + for _ in 1..20_000 { + let _proxy_result = proxy_provider + .request::<_, Option>("eth_getBlockByNumber", ("latest", false)) + .await + .unwrap() + .unwrap(); + } + + // Flush all stats here + let (influx_count, mysql_count) = x.flush_stats().await.unwrap(); + assert_eq!(influx_count, 0); + assert!(mysql_count > 0); + + // Check that at least something was earned: + let shared_referral_code: UserSharedReferralInfo = + get_shared_referral_codes(&x, &r, &referrer_login_response).await; + info!("Referral code"); + info!("{:?}", shared_referral_code.referrals.get(0).unwrap()); + + // We make sure that the referrer has $10 + 10% of the used balance + // The admin provides credits for both + let user_balance_response = user_get_balance(&x, &r, &user_login_response).await; + let user_balance_post = + Decimal::from_str(user_balance_response["balance"].as_str().unwrap()).unwrap(); + let referrer_balance_response = user_get_balance(&x, &r, &referrer_login_response).await; + let referrer_balance_post = + Decimal::from_str(referrer_balance_response["balance"].as_str().unwrap()).unwrap(); + + let difference = user_balance_pre - user_balance_post; + + // Make sure that the pre and post balance is not the same (i.e. some change has occurred) + assert_ne!( + user_balance_pre, user_balance_post, + "Pre and post balnace is equivalent" + ); + assert!(user_balance_pre > user_balance_post); + assert!(referrer_balance_pre < referrer_balance_post); + + // Finally, make sure that referrer has received 10$ of balances + assert_eq!( + referrer_balance_pre + difference / Decimal::from(10), + referrer_balance_post + ); }