// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Unlicense use common::app_daemon_utils::mock_app_daemon; use common::prepare_test_env::{prepare_test_db, run_service_for_stream}; use common::test_utils::{airdrop, Key}; use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient; use detee_shared::app_proto::brain_app_daemon_client::BrainAppDaemonClient; use detee_shared::app_proto::{self, AppNodeFilters, DelAppReq}; use std::vec; use surreal_brain::constants::{ ACCOUNT, ACTIVE_APP, APP_NODE, DELETED_APP, NEW_APP_REQ, TOKEN_DECIMAL, }; use surreal_brain::db::app::AppNode; use surreal_brain::db::prelude as db; use crate::common::app_cli_utils::create_new_app; use crate::common::app_daemon_utils::register_app_node; mod common; #[tokio::test] async fn test_app_creation() { /* env_logger::builder() .filter_level(log::LevelFilter::Trace) .filter_module("tungstenite", log::LevelFilter::Debug) .filter_module("tokio_tungstenite", log::LevelFilter::Debug) .init(); */ let db = prepare_test_db().await.unwrap(); let brain_channel = run_service_for_stream().await.unwrap(); let daemon_key = mock_app_daemon(&brain_channel, None).await.unwrap(); let key = Key::new(); let mut new_app_req = app_proto::NewAppReq { admin_pubkey: key.pubkey.clone(), node_pubkey: daemon_key.clone(), price_per_unit: 1200, resource: Some(app_proto::AppResource { ports: vec![8080, 8081], ..Default::default() }), locked_nano: 100, ..Default::default() }; let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone()); let new_app_resp = client_app_cli.new_app(key.sign_request(new_app_req.clone()).unwrap()).await; assert!(new_app_resp.is_err()); let new_app_err = new_app_resp.err().unwrap(); assert!(new_app_err.to_string().contains("Insufficient funds")); let airdrop_amount = 10; airdrop(&brain_channel, &key.pubkey, airdrop_amount).await.unwrap(); let new_app_resp = client_app_cli .new_app(key.sign_request(new_app_req.clone()).unwrap()) .await .unwrap() .into_inner(); let active_app = db.select::>((ACTIVE_APP, new_app_resp.app_id)).await.unwrap(); assert!(active_app.is_some()); let daemon_key_02 = mock_app_daemon(&brain_channel, Some("something went wrong 01".to_string())).await.unwrap(); new_app_req.node_pubkey = daemon_key_02.clone(); let new_app_resp = client_app_cli .new_app(key.sign_request(new_app_req.clone()).unwrap()) .await .unwrap() .into_inner(); assert!(!new_app_resp.error.is_empty()); let app_req_db = db.select::>((NEW_APP_REQ, new_app_resp.app_id)).await.unwrap(); assert!(!app_req_db.unwrap().error.is_empty()); let acc_db: db::Account = db.select((ACCOUNT, key.pubkey.clone())).await.unwrap().unwrap(); assert_eq!(acc_db.balance, (airdrop_amount * TOKEN_DECIMAL - 100)); assert_eq!(acc_db.tmp_locked, 0); let locking_nano = 1288; new_app_req.node_pubkey = daemon_key; new_app_req.locked_nano = locking_nano; let new_app_resp = client_app_cli.new_app(key.sign_request(new_app_req).unwrap()).await.unwrap().into_inner(); assert!(new_app_resp.error.is_empty()); let active_app = db.select::>((ACTIVE_APP, new_app_resp.app_id)).await.unwrap(); assert!(active_app.is_some()); tokio::time::sleep(std::time::Duration::from_millis(300)).await; let acc_db: db::Account = db.select((ACCOUNT, key.pubkey.clone())).await.unwrap().unwrap(); assert_eq!(acc_db.balance, airdrop_amount * TOKEN_DECIMAL - (locking_nano + 100)); assert_eq!(acc_db.tmp_locked, 0); } #[tokio::test] async fn test_timeout_app_creation() { let _ = prepare_test_db().await.unwrap(); let brain_channel = run_service_for_stream().await.unwrap(); let daemon_key = Key::new(); let key = Key::new(); let mut daemon_client = BrainAppDaemonClient::new(brain_channel.clone()); register_app_node(&mut daemon_client, &daemon_key, &Key::new().pubkey).await.unwrap(); let new_app_req = app_proto::NewAppReq { admin_pubkey: key.pubkey.clone(), node_pubkey: daemon_key.pubkey.clone(), price_per_unit: 1200, resource: Some(app_proto::AppResource { ports: vec![8080, 8081], ..Default::default() }), locked_nano: 100, ..Default::default() }; airdrop(&brain_channel, &key.pubkey, 10).await.unwrap(); let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone()); let timeout_resp = client_app_cli.new_app(key.sign_request(new_app_req.clone()).unwrap()).await; assert!(timeout_resp.is_err()); let timeout_err = timeout_resp.err().unwrap(); assert_eq!( timeout_err.message(), "Network timeout. Please try again later or contact the DeTEE devs team." ); } #[tokio::test] async fn test_app_deletion() { let db = prepare_test_db().await.unwrap(); let brain_channel = run_service_for_stream().await.unwrap(); let daemon_key = mock_app_daemon(&brain_channel, None).await.unwrap(); let key = Key::new(); airdrop(&brain_channel, &key.pubkey, 10).await.unwrap(); let new_app_res = create_new_app(&key, &daemon_key, &brain_channel).await.unwrap(); let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone()); let del_app_req = DelAppReq { admin_pubkey: key.pubkey.clone(), app_id: new_app_res.app_id }; let _ = client_app_cli.delete_app(key.sign_request(del_app_req).unwrap()).await.unwrap(); let key_02 = Key::new(); // delete random app let mut del_app_req = DelAppReq { admin_pubkey: key_02.pubkey.clone(), app_id: "9ae3VH8nJg2i8pqTQ6mJtvYuS2kd9n1XLLco8GUPfT95".to_string(), }; let del_err = client_app_cli .delete_app(key_02.sign_request(del_app_req.clone()).unwrap()) .await .err() .unwrap(); assert_eq!(del_err.message(), "Unauthorized"); let new_app_res_02 = create_new_app(&key, &daemon_key, &brain_channel).await.unwrap(); del_app_req.app_id = new_app_res_02.app_id; let del_err = client_app_cli .delete_app(key_02.sign_request(del_app_req.clone()).unwrap()) .await .err() .unwrap(); assert_eq!(del_err.message(), "Unauthorized"); // test refund let key_03 = Key::new(); airdrop(&brain_channel, &key_03.pubkey, 10).await.unwrap(); let new_app_res_03 = create_new_app(&key_03, &daemon_key, &brain_channel).await.unwrap(); let del_app_req = DelAppReq { admin_pubkey: key_03.pubkey.clone(), app_id: new_app_res_03.app_id.clone() }; let _ = client_app_cli.delete_app(key_03.sign_request(del_app_req).unwrap()).await.unwrap(); let acc: db::Account = db.select((ACCOUNT, key_03.pubkey.clone())).await.unwrap().unwrap(); assert_eq!(acc.balance, 10 * TOKEN_DECIMAL); let deleted_app = db.select::>((DELETED_APP, new_app_res_03.app_id)).await.unwrap(); assert!(deleted_app.is_some()); } #[tokio::test] async fn test_get_one_app_node() { let db = prepare_test_db().await.unwrap(); let brain_channel = run_service_for_stream().await.unwrap(); let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone()); let key = Key::new(); let mut req = AppNodeFilters { ..Default::default() }; let mock_app_node = client_app_cli .get_one_app_node(key.sign_request(req.clone()).unwrap()) .await .unwrap() .into_inner(); assert_eq!( mock_app_node.node_pubkey, "BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg".to_string() ); let node_pubkey = mock_app_daemon(&brain_channel, None).await.unwrap(); let new_node_ip = db.select::>((APP_NODE, node_pubkey.clone())).await.unwrap().unwrap().ip; req.ip = new_node_ip; let new_app_node = client_app_cli.get_one_app_node(key.sign_request(req).unwrap()).await.unwrap().into_inner(); assert_eq!(new_app_node.node_pubkey, node_pubkey); } // TODO: test register app node, delete app contract while node offline, kick, etc..