diff --git a/src/db/app.rs b/src/db/app.rs index 2245313..3abe616 100644 --- a/src/db/app.rs +++ b/src/db/app.rs @@ -404,6 +404,12 @@ impl ActiveAppWithNode { None => Ok(vec![]), } } + + pub async fn list_all(db: &Surreal) -> Result, Error> { + let mut query_response = db.query(format!("SELECT * FROM {ACTIVE_APP} FETCH out;")).await?; + let active_apps: Vec = query_response.take(0)?; + Ok(active_apps) + } } #[derive(Debug, Serialize)] diff --git a/src/grpc/general.rs b/src/grpc/general.rs index 3dcb31c..667908b 100644 --- a/src/grpc/general.rs +++ b/src/grpc/general.rs @@ -212,19 +212,18 @@ impl BrainGeneralCli for GeneralCliServer { async fn list_all_app_contracts( &self, - _req: tonic::Request, + req: tonic::Request, ) -> Result, Status> { - todo!(); - // check_admin_key(&req)?; - // let _ = check_sig_from_req(req)?; - // let contracts = self.data.list_all_app_contracts(); - // let (tx, rx) = mpsc::channel(6); - // tokio::spawn(async move { - // for contract in contracts { - // let _ = tx.send(Ok(contract.into())).await; - // } - // }); - // let output_stream = ReceiverStream::new(rx); - // Ok(Response::new(Box::pin(output_stream))) + check_admin_key(&req)?; + check_sig_from_req(req)?; + let contracts = db::ActiveAppWithNode::list_all(&self.db).await?; + let (tx, rx) = mpsc::channel(6); + tokio::spawn(async move { + for contract in contracts { + let _ = tx.send(Ok(contract.into())).await; + } + }); + let output_stream = ReceiverStream::new(rx); + Ok(Response::new(Box::pin(output_stream))) } } diff --git a/tests/common/vm_cli_utils.rs b/tests/common/vm_cli_utils.rs index 6a6937f..4e4b31a 100644 --- a/tests/common/vm_cli_utils.rs +++ b/tests/common/vm_cli_utils.rs @@ -1,5 +1,6 @@ use super::test_utils::{admin_keys, Key}; use anyhow::{anyhow, Result}; +use detee_shared::app_proto; use detee_shared::common_proto::Empty; use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient; use detee_shared::general_proto::{Account, AirdropReq, RegOperatorReq, ReportNodeReq}; @@ -134,3 +135,29 @@ pub async fn list_all_vm_contracts( Ok(vm_contracts) } + +pub async fn list_all_app_contracts( + brain_channel: &Channel, + admin_key: &Key, +) -> Result> { + let mut cli_client = BrainGeneralCliClient::new(brain_channel.clone()); + let mut stream = cli_client + .list_all_app_contracts(admin_key.sign_request(Empty {}).unwrap()) + .await? + .into_inner(); + + let mut app_contracts = Vec::new(); + + while let Some(stream_data) = stream.next().await { + match stream_data { + Ok(app_contract) => { + app_contracts.push(app_contract); + } + Err(e) => { + panic!("Error while listing app_contracts: {e:?}"); + } + } + } + + Ok(app_contracts) +} diff --git a/tests/grpc_general_test.rs b/tests/grpc_general_test.rs index e9b0332..0eb9ef1 100644 --- a/tests/grpc_general_test.rs +++ b/tests/grpc_general_test.rs @@ -3,7 +3,8 @@ use common::prepare_test_env::{ }; use common::test_utils::{admin_keys, Key}; use common::vm_cli_utils::{ - airdrop, create_new_vm, list_accounts, list_all_vm_contracts, register_operator, report_node, + airdrop, create_new_vm, list_accounts, list_all_app_contracts, list_all_vm_contracts, + register_operator, report_node, }; use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node}; use detee_shared::common_proto::{Empty, Pubkey}; @@ -11,7 +12,7 @@ use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient use detee_shared::general_proto::{AirdropReq, BanUserReq, SlashReq}; use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient; use futures::StreamExt; -use surreal_brain::constants::{ACCOUNT, ACTIVE_VM, BAN, TOKEN_DECIMAL, VM_NODE}; +use surreal_brain::constants::{ACCOUNT, ACTIVE_APP, ACTIVE_VM, BAN, TOKEN_DECIMAL, VM_NODE}; use surreal_brain::db::prelude as db; use surreal_brain::db::vm::VmNodeWithReports; @@ -264,7 +265,7 @@ async fn test_kick_contract() { */ let db_conn = prepare_test_db().await.unwrap(); - let contract_uuid = "e3d01f252b2a410b80e312f44e474334"; + let contract_uuid = "5af49a714c64a82ef50e574b023b2a0ef0405ed"; let operator_wallet = "7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB"; let reason = "'; THROW 'Injected error'; --"; // sql injection query @@ -341,6 +342,7 @@ async fn test_ban_user() { assert!(operator_banned_you.to_string().contains("This operator banned you")); } + #[tokio::test] async fn test_slash_operator() { let db_conn = prepare_test_db().await.unwrap(); @@ -389,8 +391,11 @@ async fn test_admin_list_account() { let unauthenticated = list_accounts(&brain_channel, &Key::new()).await.err().unwrap(); assert!(unauthenticated.to_string().contains("reserved to admin accounts")); + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; // sync time for other db opeartion + + let acc_in_db = db_conn.select::>(ACCOUNT).await.unwrap(); let accounts = list_accounts(&brain_channel, &admin_key).await.unwrap(); - assert_eq!(accounts.len(), 19); + assert_eq!(accounts.len(), acc_in_db.len()); airdrop(&brain_channel, &Key::new().pubkey, 10).await.unwrap(); @@ -417,3 +422,24 @@ async fn test_admin_list_all_vm_contracts() { // TODO: mock vm daemon and deploy a new vm, then list again } + +#[tokio::test] +async fn test_admin_list_all_app_contracts() { + let db_conn = prepare_test_db().await.unwrap(); + let brain_channel = run_service_for_stream().await.unwrap(); + + let admin_key = admin_keys()[0].clone(); + + let unauthenticated = list_all_app_contracts(&brain_channel, &Key::new()).await.err().unwrap(); + assert!(unauthenticated.to_string().contains("reserved to admin accounts")); + + let app_contracts = list_all_app_contracts(&brain_channel, &admin_key).await.unwrap(); + assert_eq!(app_contracts.len(), 1); + + let app_in_db = db_conn.select::>(ACTIVE_APP).await.unwrap(); + + let app_contracts = list_all_app_contracts(&brain_channel, &admin_key).await.unwrap(); + assert_eq!(app_contracts.len(), app_in_db.len()); + + // TODO: mock app daemon and deploy a new app, then list again +} diff --git a/tests/mock_data.yaml b/tests/mock_data.yaml index f651f11..1bae3f9 100644 --- a/tests/mock_data.yaml +++ b/tests/mock_data.yaml @@ -405,6 +405,25 @@ vm_contracts: price_per_unit: 20000 locked_nano: 12730960000 collected_at: 2025-04-20T00:34:15.461240342Z + + - uuid: 5af49a71-4c64-a82e-f50e574-b023-b2a0ef0405ed + hostname: hallow-hobo + admin_pubkey: 4qFJJJdRrSB9hCn8rrvYTXHLJg371ab36PJmZ4uxHjGQ + node_pubkey: 7fujZQeTme52RdXTLmQST5jBgAbvzic5iERtH5EWoYjk + exposed_ports: + - 46393 + public_ipv4: "" + public_ipv6: "" + disk_size_gb: 10 + vcpus: 1 + memory_mb: 1000 + kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919 + dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990 + created_at: 2025-04-16T20:37:57.176592933Z + updated_at: 2025-04-16T20:37:57.176594069Z + price_per_unit: 20000 + locked_nano: 12730960000 + collected_at: 2025-04-20T00:34:15.461240342Z app_nodes: - node_pubkey: BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg operator_wallet: 7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB