From b02c32fbb2c0881f8c81451a5d9c1d793c077fd5 Mon Sep 17 00:00:00 2001 From: Kyrylo Stepanov Date: Mon, 27 Jan 2025 16:30:04 +0200 Subject: [PATCH] Added a possibility to do integration tests using Eclipse && Added test for the case when fungible tokens are returned while only NFTs are requested --- .github/workflows/rust.yml | 2 + integration_tests/src/account_update_tests.rs | 4 +- integration_tests/src/common.rs | 10 +- ...QDwULQDdpisGssKZeRw2qcCTiZnsAmi6cnR89YYxSg | Bin 0 -> 304 bytes ...vjE7bDpwA2nFp5KbjWHjG2RHBWi5z1pP5ehY9t6p8V | Bin 0 -> 304 bytes ...RQs1xZdASeL65PHTa1C8GnYCWtX18Lx98ofJB3SZNC | Bin 0 -> 304 bytes ...k1Zv557DAnichMsWE4cfURYbr1D2yWfcaqehydHo9R | Bin 0 -> 304 bytes ...peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH | Bin 0 -> 872 bytes ...kXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB | Bin 0 -> 680 bytes ...KGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 | Bin 0 -> 616 bytes ...A21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom | Bin 0 -> 600 bytes ...pMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ | Bin 0 -> 616 bytes ...nRA9ALhDYC5SWhBrw19JVWnDxnrGMYTmkfLsLkbpzV | Bin 0 -> 304 bytes ...peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH | 1 + ...kXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB | 1 + ...KGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 | 1 + ...A21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom | 1 + ...pMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ | 1 + integration_tests/src/regular_nft_tests.rs | 48 ++ ...ested_non_fungibles_are_non_fungibles.snap | 458 ++++++++++++++++++ nft_ingester/tests/api_tests.rs | 174 +++++++ 21 files changed, 694 insertions(+), 7 deletions(-) create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/2TQDwULQDdpisGssKZeRw2qcCTiZnsAmi6cnR89YYxSg create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/44vjE7bDpwA2nFp5KbjWHjG2RHBWi5z1pP5ehY9t6p8V create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/4pRQs1xZdASeL65PHTa1C8GnYCWtX18Lx98ofJB3SZNC create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/5ok1Zv557DAnichMsWE4cfURYbr1D2yWfcaqehydHo9R create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ create mode 100644 integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/JCnRA9ALhDYC5SWhBrw19JVWnDxnrGMYTmkfLsLkbpzV create mode 100644 integration_tests/src/data/largest_token_account_ids/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH create mode 100644 integration_tests/src/data/largest_token_account_ids/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB create mode 100644 integration_tests/src/data/largest_token_account_ids/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 create mode 100644 integration_tests/src/data/largest_token_account_ids/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom create mode 100644 integration_tests/src/data/largest_token_account_ids/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ create mode 100644 integration_tests/src/snapshots/integration_tests__regular_nft_tests__requested_non_fungibles_are_non_fungibles.snap diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5e6bebb7..2e436593 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -136,4 +136,6 @@ jobs: DATABASE_TEST_URL: "postgres://postgres:postgres@127.0.0.1:5432/postgres" DEVNET_RPC_URL: ${{ secrets.SOLANA_DEVNET_RPC_URL }} MAINNET_RPC_URL: ${{ secrets.SOLANA_MAINNET_RPC_URL }} + ECLIPSE_DEVNET_RPC_URL: ${{ secrets.SOLANA_ECLIPSE_DEVNET_RPC_URL }} + ECLIPSE_MAINNET_RPC_URL: ${{ secrets.SOLANA_ECLIPSE_MAINNET_RPC_URL }} run: cargo test --features integration_tests -- --nocapture \ No newline at end of file diff --git a/integration_tests/src/account_update_tests.rs b/integration_tests/src/account_update_tests.rs index 904efb6b..1d03b1a3 100644 --- a/integration_tests/src/account_update_tests.rs +++ b/integration_tests/src/account_update_tests.rs @@ -172,7 +172,7 @@ async fn test_account_updates() { setup.clean_up_data_bases().await; - index_nft(&setup, mint).await; + index_nft_accounts(&setup, get_nft_accounts(&setup, mint).await).await; let response = setup.das_api.get_asset(request.clone(), mutexed_tasks.clone()).await.unwrap(); @@ -217,7 +217,7 @@ async fn test_account_updates() { for named_update in named_updates.clone() { setup.clean_up_data_bases().await; - index_nft(&setup, mint).await; + index_nft_accounts(&setup, get_nft_accounts(&setup, mint).await).await; let other_named_updates = named_updates .clone() diff --git a/integration_tests/src/common.rs b/integration_tests/src/common.rs index 2cc02e99..a0f4ac32 100644 --- a/integration_tests/src/common.rs +++ b/integration_tests/src/common.rs @@ -117,6 +117,8 @@ impl TestSetup { let rpc_url = match opts.network.unwrap_or_default() { Network::Mainnet => std::env::var("MAINNET_RPC_URL").unwrap(), Network::Devnet => std::env::var("DEVNET_RPC_URL").unwrap(), + Network::EclipseMainnet => std::env::var("ECLIPSE_MAINNET_RPC_URL").unwrap(), + Network::EclipseDevnet => std::env::var("ECLIPSE_DEVNET_RPC_URL").unwrap(), }; let client = Arc::new(RpcClient::new(rpc_url.to_string())); @@ -537,6 +539,8 @@ pub enum Network { #[default] Mainnet, Devnet, + EclipseMainnet, + EclipseDevnet, } #[derive(Clone, Copy, Debug)] @@ -553,7 +557,7 @@ pub async fn index_seed_events(setup: &TestSetup, events: Vec<&SeedEvent>) { index_and_sync_account_with_ordered_slot(setup, *account).await; }, SeedEvent::Nft(mint) => { - index_nft(setup, *mint).await; + index_nft_accounts(setup, get_nft_accounts(setup, *mint).await).await; }, SeedEvent::Signature(sig) => { index_transaction(setup, *sig).await; @@ -688,10 +692,6 @@ async fn index_token_mint(setup: &TestSetup, mint: Pubkey) { } } -pub async fn index_nft(setup: &TestSetup, mint: Pubkey) { - index_nft_accounts(setup, get_nft_accounts(setup, mint).await).await; -} - pub async fn index_nft_accounts(setup: &TestSetup, nft_accounts: NftAccounts) { for account in [nft_accounts.mint, nft_accounts.metadata, nft_accounts.token] { index_account(setup, account).await; diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/2TQDwULQDdpisGssKZeRw2qcCTiZnsAmi6cnR89YYxSg b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/2TQDwULQDdpisGssKZeRw2qcCTiZnsAmi6cnR89YYxSg new file mode 100644 index 0000000000000000000000000000000000000000..b9f542f02d8e60a86b2f36e8f1027329a548fc8a GIT binary patch literal 304 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1dtS+&;1~!E9vDocmL8A&i9sDztp<4Zff?W zjj7_FeU2XyWxMl v$2kQKyDg*tbFXTbS$g4}#zSB8N!|ibc!0by; literal 0 HcmV?d00001 diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/44vjE7bDpwA2nFp5KbjWHjG2RHBWi5z1pP5ehY9t6p8V b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/44vjE7bDpwA2nFp5KbjWHjG2RHBWi5z1pP5ehY9t6p8V new file mode 100644 index 0000000000000000000000000000000000000000..6f27a1b39270443dbd92817374b95b28d04909de GIT binary patch literal 304 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1d!C7(z|a3-|3Wm-fPD;c}mvbYu@-*T-;%< z$(~hJs`D$@*zSIN_^!17o`h5Eo+mkHZ*7zM-G3T*6$**&^wy3RcbkvTE_+rC+W-xwGt4oa?>l v$2kQKyDg*tbFXTbS$g4}#zSB8N!|ibcxYJ2$ literal 0 HcmV?d00001 diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/4pRQs1xZdASeL65PHTa1C8GnYCWtX18Lx98ofJB3SZNC b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/4pRQs1xZdASeL65PHTa1C8GnYCWtX18Lx98ofJB3SZNC new file mode 100644 index 0000000000000000000000000000000000000000..2f9bffb2ceaa87d3e339374bdec90b2be2c51176 GIT binary patch literal 304 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1dz1Y@%7JwJE~=d{Q{9*Qk+^V^fTU`o&9Eo z;;}FHZTR0^WxMl&%LT$X6c1@8V`NVCv^)*|DDC!4>J>LG+v4nwI~KLv4gn)wZBV$ literal 0 HcmV?d00001 diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/5ok1Zv557DAnichMsWE4cfURYbr1D2yWfcaqehydHo9R b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/5ok1Zv557DAnichMsWE4cfURYbr1D2yWfcaqehydHo9R new file mode 100644 index 0000000000000000000000000000000000000000..1d18365ce2d11796748b18cd9227b7e174e75889 GIT binary patch literal 304 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1dw#kkXY=zrq`AEWM z2%#9JKIUIB1;}~A1QE!|<9FHfNV?c&eWy_DA^(WEn2v3(KcJr+ZLKkFntV+ zAQmCjP)n#uF$ys_5VV(2NQn_)#;M6Q%$xr#dG_I4N8Ee!d)7+PMJr_UZcXYrDR4?+ zeNrP2g91T!2s89C5(*FXC8 z>!oGpq$VX6r|Ko==juZhrsU@)X66;cxVo7oskwSt#rb(0K)oVBT$Ep#m{U?257d}h z9AA*1nO9QG3=}stFwg-~ZceEM0jZ(Mxo)KeS>EPF;rV$^rs>`#Ss{jIj!CW+c^ScB z&W1@&0gi=fAZ>;Q2K+!OwW1)iD6u3nKQBHdu_ToXBx7!7YG7yqq}YHwh`X?PjT5ZB zBsH%XsGA+cfp{6DD5S0so3AK#mdz7htoa`53QeI|SS(#~`m{k_w6BQDcnP?VR6<(EY=;)a3U6NQ@ zSXc~-Nf96}%CAh!DXEN4N-WMSjxWg1%quBo0g9U%7#QdPX~*JV??P{L=j;l%&@^N3 o#Qeajsv?UhpMYG`G`IB9(2_7$)4+0fN1wpJJdm3V4Gb6<0H=ZBwg3PC literal 0 HcmV?d00001 diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 new file mode 100644 index 0000000000000000000000000000000000000000..868f86c5b4a1da07e8121d1c1052dc0e9a52cb06 GIT binary patch literal 616 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1dz;c31Bc*s}D<*J~VaLE2ALG-TVKiq#lsr zp7cfH>YRc;w!7aRzANp&C*c&k=Sj}lTic}m_%`q4RsXm5r^bzi-G5|&W_;KQB!GYs zLNS!y;$JZZ$aw-4klei4R_On?RG%~9>kq9EU^gz`Hs!;#Nz2|WW1Nv^>Sh7c$G`|; z5mF7cgqjqi5Q76jdkKY<7!}MAX4pirJ6M4sQ-vvh_0y(u(zy64SDaQZv&Fjf=`E&5X@*%Cd}%OEObTGxIA_O!CW0k~7QF dk}@)~ic3s0vdz;nsxnhkD$`TTjT1r9003SX%MSnm literal 0 HcmV?d00001 diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom new file mode 100644 index 0000000000000000000000000000000000000000..12b0481d4e5b760521649ec6c9969811da47f3df GIT binary patch literal 600 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1dwbtp7<;2j{S^YF_|aM8A~liw^x1J_qDWk z%A(c>S?AV-u-*Ok@Lg&DJqf4SJx_AZ-r6Sh$G3SWulm2eKQ(SF?EWJIG=t+ikN^Tk z2*q&!8vlwZK+YAYK-jkA`{`d3+2o5R9cN{GE|O{~nJzs)>FkPDcb?_5PbI$Yhaj?tZQOnX{?)Qlwz)HW|EX@ Pl45FZW@2IqG=c#DkSwwe literal 0 HcmV?d00001 diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ new file mode 100644 index 0000000000000000000000000000000000000000..cf8a5a53fc22c2ff1ccee4adda5fc1e6d41c222c GIT binary patch literal 616 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1du!+I#I(r<(67$oP0V1-Zf*5kQfQl9GaAD}DXEw36bI z{G!D4RK1+cylnlWjBN9?jH=Akl*;tfa^pl$Gynja_SFmk literal 0 HcmV?d00001 diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/JCnRA9ALhDYC5SWhBrw19JVWnDxnrGMYTmkfLsLkbpzV b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/JCnRA9ALhDYC5SWhBrw19JVWnDxnrGMYTmkfLsLkbpzV new file mode 100644 index 0000000000000000000000000000000000000000..84d96ed58e92bbf7e82a2780c5d00e375a1792ad GIT binary patch literal 304 zcmY#jfB*@G1O^rc4+a%5*9Axh0C5C^1d#kcJ3C}{aF|@@=H-T~LtaUQh22>5PVx9f zbu->~e(nZMY%Hj5 uIRy^8Eu;T)uWFZBdf}bMLtpbr-2&2oXR-Ff%!C?^mm)::new( + env.pg_env.client.clone(), + env.rocks_env.storage.clone(), + Arc::new(ApiMetricsConfig::new()), + None, + None, + 50, + None, + None, + JsonMiddlewareConfig::default(), + Arc::new(MockAccountBalanceGetter::new()), + None, + Arc::new(RaydiumTokenPriceFetcher::default()), + NATIVE_MINT_PUBKEY.to_string(), + ); + let tasks = JoinSet::new(); + let mutexed_tasks = Arc::new(Mutex::new(tasks)); + + let token_updates_processor = + TokenAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); + let mplx_updates_processor = + MplxAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); + + let token_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let owner_key = Pubkey::new_unique(); + + let mint_auth_key = Pubkey::new_unique(); + + let token_acc = TokenAccount { + pubkey: token_key, + mint: mint_key, + delegate: None, + owner: owner_key, + extensions: None, + frozen: false, + delegated_amount: 0, + slot_updated: 1, + amount: 1, + write_version: 1, + }; + + let mint_acc = Mint { + pubkey: mint_key, + slot_updated: 1, + supply: 10, + decimals: 0, + mint_authority: Some(mint_auth_key), + freeze_authority: None, + token_program: Default::default(), + extensions: None, + write_version: 1, + }; + + let metadata = MetadataInfo { + metadata: Metadata { + key: Key::MetadataV1, + update_authority: Pubkey::new_unique(), + mint: mint_key, + name: "".to_string(), + symbol: "".to_string(), + uri: "".to_string(), + seller_fee_basis_points: 0, + creators: None, + primary_sale_happened: false, + is_mutable: true, + edition_nonce: None, + token_standard: Some(mpl_token_metadata::types::TokenStandard::Fungible), + collection: None, + uses: None, + collection_details: None, + programmable_config: None, + }, + slot_updated: 1, + write_version: 1, + lamports: 1, + executable: false, + metadata_owner: None, + rent_epoch: 0, + }; + let offchain_data = OffChainData { + url: Some("https://ping-pong".to_string()), + metadata: Some("{\"msg\": \"hallo\"}".to_string()), + ..Default::default() + }; + + env.rocks_env + .storage + .asset_offchain_data + .put(offchain_data.url.clone().unwrap(), offchain_data.clone()) + .unwrap(); + + let mut batch_storage = BatchSaveStorage::new( + env.rocks_env.storage.clone(), + 10, + Arc::new(IngesterMetricsConfig::new()), + ); + token_updates_processor + .transform_and_save_mint_account(&mut batch_storage, &mint_acc) + .unwrap(); + token_updates_processor + .transform_and_save_token_account(&mut batch_storage, token_acc.pubkey, &token_acc) + .unwrap(); + + mplx_updates_processor + .transform_and_store_metadata_account(&mut batch_storage, mint_key, &metadata) + .unwrap(); + batch_storage.flush().unwrap(); + + let payload = GetAsset { + id: mint_key.to_string(), + options: Options { show_unverified_collections: true, ..Default::default() }, + }; + let response = api.get_asset(payload.clone(), mutexed_tasks.clone()).await.unwrap(); + + assert_eq!(response["interface"], "FungibleToken".to_string()); + + // Given record that respects fungible metadata + // When updated comes with NFT metadata + // Then it should transfer to NFT + + let metadata = MetadataInfo { + metadata: Metadata { + token_standard: Some(mpl_token_metadata::types::TokenStandard::NonFungible), + ..metadata.metadata + }, + ..metadata + }; + + mplx_updates_processor + .transform_and_store_metadata_account(&mut batch_storage, mint_key, &metadata) + .unwrap(); + batch_storage.flush().unwrap(); + let response = api.get_asset(payload.clone(), mutexed_tasks.clone()).await.unwrap(); + + assert_eq!(response["interface"], "V1_NFT".to_string()); + + // Given record that respects NFT metadata + // When updated comes with fungible metadata + // Then it should stay as NFT + let metadata = MetadataInfo { + metadata: Metadata { + token_standard: Some(mpl_token_metadata::types::TokenStandard::Fungible), + ..metadata.metadata + }, + ..metadata + }; + + mplx_updates_processor + .transform_and_store_metadata_account(&mut batch_storage, mint_key, &metadata) + .unwrap(); + batch_storage.flush().unwrap(); + let response = api.get_asset(payload.clone(), mutexed_tasks.clone()).await.unwrap(); + + assert_eq!(response["interface"], "V1_NFT".to_string()); + } }