-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test(wallet-integration): unit tests for pop up contract #374
Changes from 22 commits
9f7f430
1485dfa
55addf5
e6a5d6a
3bd4c7b
c03f658
3e8266d
a391771
193582a
0075e94
50bd1c8
b3d6aa3
ebaf925
4f7798e
3460818
6f2dd8c
0784af7
9cb21a0
4c4d3b2
13cc493
1edf8dc
76b8aec
50818a4
59509cb
f9851d1
80f4f7b
86ab4b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,7 @@ mod tests { | |
// This is a helper test for an actual running pop CLI. | ||
// It can serve as the "frontend" to query the payload, sign it | ||
// and submit back to the CLI. | ||
#[ignore] | ||
#[tokio::test] | ||
async fn sign_call_data() -> anyhow::Result<()> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be removed if its purpose is properly represented elsewhere in the tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. Even more now that we have the front end part too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed in f9851d1 |
||
use subxt::{config::DefaultExtrinsicParamsBuilder as Params, tx::Payload}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,45 @@ use pop_contracts::{ | |
contracts_node_generator, dry_run_gas_estimate_instantiate, instantiate_smart_contract, | ||
run_contracts_node, set_up_deployment, Contract, UpOpts, | ||
}; | ||
use std::{path::Path, process::Command as Cmd}; | ||
use serde::{Deserialize, Serialize}; | ||
use std::{path::Path, process::Command as Cmd, time::Duration}; | ||
use strum::VariantArray; | ||
use subxt::{config::DefaultExtrinsicParamsBuilder as Params, tx::Payload, utils::to_hex}; | ||
use subxt_signer::sr25519::dev; | ||
use tokio::time::sleep; | ||
use url::Url; | ||
|
||
// This struct implements the [`Payload`] trait and is used to submit | ||
// pre-encoded SCALE call data directly, without the dynamic construction of transactions. | ||
struct CallData(Vec<u8>); | ||
impl Payload for CallData { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. leaving a note: I copied this from the pop call parachain PR (IIRC). Once everything gets merged in we should hopefully be able to just import this. |
||
fn encode_call_data_to( | ||
&self, | ||
_: &subxt::Metadata, | ||
out: &mut Vec<u8>, | ||
) -> Result<(), subxt::ext::subxt_core::Error> { | ||
out.extend_from_slice(&self.0); | ||
Ok(()) | ||
} | ||
} | ||
|
||
// TransactionData has been copied from wallet_integration.rs | ||
/// Transaction payload to be sent to frontend for signing. | ||
#[derive(Serialize, Debug)] | ||
#[cfg_attr(test, derive(Deserialize, Clone))] | ||
pub struct TransactionData { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason this wasn't just imported? |
||
chain_rpc: String, | ||
call_data: Vec<u8>, | ||
} | ||
impl TransactionData { | ||
pub fn new(chain_rpc: String, call_data: Vec<u8>) -> Self { | ||
Self { chain_rpc, call_data } | ||
} | ||
pub fn call_data(&self) -> Vec<u8> { | ||
self.call_data.clone() | ||
} | ||
} | ||
|
||
/// Test the contract lifecycle: new, build, up, call | ||
#[tokio::test] | ||
async fn contract_lifecycle() -> Result<()> { | ||
|
@@ -135,6 +170,96 @@ async fn contract_lifecycle() -> Result<()> { | |
Ok(()) | ||
} | ||
|
||
#[tokio::test] | ||
async fn wait_for_wallet_signature() -> Result<()> { | ||
const DEFAULT_ENDPOINT: &str = "ws://127.0.0.1:9966"; | ||
const DEFAULT_PORT: u16 = 9966; | ||
const WALLET_INT_URI: &str = "http://127.0.0.1:9090"; | ||
const WAIT_SECS: u64 = 320; | ||
let temp = tempfile::tempdir()?; | ||
let temp_dir = temp.path(); | ||
//let temp_dir = Path::new("./"); //For testing locally | ||
// pop new contract test_contract (default) | ||
Command::cargo_bin("pop") | ||
.unwrap() | ||
.current_dir(&temp_dir) | ||
.args(&["new", "contract", "test_contract"]) | ||
.assert() | ||
.success(); | ||
assert!(temp_dir.join("test_contract").exists()); | ||
|
||
let binary = contracts_node_generator(temp_dir.to_path_buf().clone(), None).await?; | ||
binary.source(false, &(), true).await?; | ||
set_executable_permission(binary.path())?; | ||
let process = run_contracts_node(binary.path(), None, DEFAULT_PORT).await?; | ||
sleep(Duration::from_secs(10)).await; | ||
|
||
// pop up contract --upload-only --use-wallet | ||
// Using `cargo run --` as means for the CI to pass. | ||
// Possibly there's room for improvement here. | ||
let _handler = tokio::process::Command::new("cargo") | ||
.args(&[ | ||
"run", | ||
"--", | ||
"up", | ||
"contract", | ||
"--upload-only", | ||
"--use-wallet", | ||
"--skip-confirm", | ||
"--dry-run", | ||
"--url", | ||
DEFAULT_ENDPOINT, | ||
"-p", | ||
temp_dir.join("test_contract").to_str().expect("to_str"), | ||
]) | ||
.spawn()?; | ||
// Wait a moment for node and server to be up. | ||
sleep(Duration::from_secs(WAIT_SECS)).await; | ||
|
||
// Request payload from server. | ||
let response = reqwest::get(&format!("{}/payload", WALLET_INT_URI)) | ||
.await | ||
.expect("Failed to get payload") | ||
.json::<TransactionData>() | ||
.await | ||
.expect("Failed to parse payload"); | ||
// We have received some payload. | ||
assert!(!response.call_data().is_empty()); | ||
|
||
let rpc_client = subxt::backend::rpc::RpcClient::from_url(DEFAULT_ENDPOINT).await?; | ||
let client = subxt::OnlineClient::<subxt::SubstrateConfig>::from_rpc_client(rpc_client).await?; | ||
|
||
// Sign payload. | ||
let signer = dev::alice(); | ||
let payload = CallData(response.call_data()); | ||
let ext_params = Params::new().build(); | ||
let signed = client.tx().create_signed(&payload, &signer, ext_params).await?; | ||
|
||
// Submit signed payload. This kills the wallet integration server. | ||
let _ = reqwest::Client::new() | ||
.post(&format!("{}/submit", WALLET_INT_URI)) | ||
.json(&to_hex(signed.encoded())) | ||
.send() | ||
.await | ||
.expect("Failed to submit payload") | ||
.text() | ||
.await | ||
.expect("Failed to parse JSON response"); | ||
|
||
// Request payload from server after signed payload has been sent. | ||
// Server should not be running! | ||
let response = reqwest::get(&format!("{}/payload", WALLET_INT_URI)).await; | ||
assert!(response.is_err()); | ||
|
||
// Stop the process contracts-node | ||
Cmd::new("kill") | ||
.args(["-s", "TERM", &process.id().to_string()]) | ||
.spawn()? | ||
.wait()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
fn generate_all_the_templates(temp_dir: &Path) -> Result<()> { | ||
for template in Contract::VARIANTS { | ||
let contract_name = format!("test_contract_{}", template).replace("-", "_"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice if these were some value to ensure pop-cli isn't just taking the default None.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 86ab4b8