Skip to content

Commit

Permalink
Fix/rpc header (#1799)
Browse files Browse the repository at this point in the history
* Use network.rpc_client() to get a contract's spec

this will make sure that we're adding the necessary rpc provider
headers, if they are required for the given provider

* Use self.rpc_client() in network for creating a new rpc client

* Refactor TestEnv to have a network field

* Test that rpc_headers are being passed on rpc provider requests

* Fix operations int test

* Clippy

* Add CC-1.0 to allowed licenses in deny.toml

https://stellarfoundation.slack.com/archives/C92PPVBPT/p1734657921992129

* fix

* Use workspace httpmock dep

also
- move soroban-test httpmock dep to dev-dependencies
- use workspace dep for stellar-ledger test

---------

Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com>
  • Loading branch information
elizabethengelman and leighmcculloch authored Dec 20, 2024
1 parent a5f0259 commit 1c0d4e6
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 31 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ toml_edit = "0.22.20"
toml = "0.8.19"
reqwest = "0.12.7"
predicates = "3.1.2"
httpmock = "0.7.0"

[profile.test-wasms]
inherits = "release"
Expand Down
2 changes: 1 addition & 1 deletion cmd/crates/soroban-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ predicates = { workspace = true }
fs_extra = "1.3.0"
toml = { workspace = true }


[dev-dependencies]
serde_json = "1.0.93"
which = { workspace = true }
Expand All @@ -42,6 +41,7 @@ walkdir = "2.4.0"
ulid.workspace = true
ed25519-dalek = { workspace = true }
hex = { workspace = true }
httpmock = { workspace = true }

[features]
it = []
45 changes: 34 additions & 11 deletions cmd/crates/soroban-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,19 @@ pub enum Error {
/// its own `TempDir` where it will save test-specific configuration.
pub struct TestEnv {
pub temp_dir: TempDir,
pub rpc_url: String,
pub network_passphrase: String,
pub network: network::Network,
}

impl Default for TestEnv {
fn default() -> Self {
let temp_dir = TempDir::new().unwrap();
Self {
temp_dir,
rpc_url: "http://localhost:8889/soroban/rpc".to_string(),
network_passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(),
network: network::Network {
rpc_url: "http://localhost:8889/soroban/rpc".to_string(),
network_passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(),
rpc_headers: [].to_vec(),
},
}
}
}
Expand Down Expand Up @@ -102,12 +104,21 @@ impl TestEnv {
}

pub fn with_rpc_url(rpc_url: &str) -> TestEnv {
let mut env = TestEnv {
rpc_url: rpc_url.to_string(),
..Default::default()
let mut env = TestEnv::default();
env.network.rpc_url = rpc_url.to_string();
if let Ok(network_passphrase) = std::env::var("STELLAR_NETWORK_PASSPHRASE") {
env.network.network_passphrase = network_passphrase;
};
env.generate_account("test", None).assert().success();
env
}

pub fn with_rpc_provider(rpc_url: &str, rpc_headers: Vec<(String, String)>) -> TestEnv {
let mut env = TestEnv::default();
env.network.rpc_url = rpc_url.to_string();
env.network.rpc_headers = rpc_headers;
if let Ok(network_passphrase) = std::env::var("STELLAR_NETWORK_PASSPHRASE") {
env.network_passphrase = network_passphrase;
env.network.network_passphrase = network_passphrase;
};
env.generate_account("test", None).assert().success();
env
Expand All @@ -131,13 +142,25 @@ impl TestEnv {
/// to be the internal `temp_dir`.
pub fn new_assert_cmd(&self, subcommand: &str) -> Command {
let mut cmd: Command = self.bin();

cmd.arg(subcommand)
.env("SOROBAN_ACCOUNT", TEST_ACCOUNT)
.env("SOROBAN_RPC_URL", &self.rpc_url)
.env("SOROBAN_RPC_URL", &self.network.rpc_url)
.env("SOROBAN_NETWORK_PASSPHRASE", LOCAL_NETWORK_PASSPHRASE)
.env("XDG_CONFIG_HOME", self.temp_dir.join("config").as_os_str())
.env("XDG_DATA_HOME", self.temp_dir.join("data").as_os_str())
.current_dir(&self.temp_dir);

if !self.network.rpc_headers.is_empty() {
cmd.env(
"STELLAR_RPC_HEADERS",
format!(
"{}:{}",
&self.network.rpc_headers[0].0, &self.network.rpc_headers[0].1
),
);
}

cmd
}

Expand Down Expand Up @@ -234,7 +257,7 @@ impl TestEnv {
let config_dir = Some(self.dir().to_path_buf());
config::Args {
network: network::Args {
rpc_url: Some(self.rpc_url.clone()),
rpc_url: Some(self.network.rpc_url.clone()),
rpc_headers: [].to_vec(),
network_passphrase: Some(LOCAL_NETWORK_PASSPHRASE.to_string()),
network: None,
Expand Down Expand Up @@ -305,7 +328,7 @@ impl TestEnv {
}

pub fn client(&self) -> soroban_rpc::Client {
soroban_rpc::Client::new(&self.rpc_url).unwrap()
self.network.rpc_client().unwrap()
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/crates/soroban-test/tests/it/integration/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async fn invoke_test_generate_typescript_bindings() {
"--network-passphrase",
LOCAL_NETWORK_PASSPHRASE,
"--rpc-url",
&sandbox.rpc_url,
&sandbox.network.rpc_url,
"--output-dir",
&outdir.display().to_string(),
"--overwrite",
Expand Down Expand Up @@ -43,7 +43,7 @@ async fn invoke_test_bindings_context_failure() {
"--network-passphrase",
LOCAL_NETWORK_PASSPHRASE,
"--rpc-url",
&sandbox.rpc_url,
&sandbox.network.rpc_url,
"--output-dir",
&outdir.display().to_string(),
"--overwrite",
Expand Down
4 changes: 2 additions & 2 deletions cmd/crates/soroban-test/tests/it/integration/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async fn invoke_view_with_non_existent_source_account() {
#[allow(clippy::too_many_lines)]
async fn invoke() {
let sandbox = &TestEnv::new();
let c = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let c = sandbox.network.rpc_client().unwrap();
let GetLatestLedgerResponse { sequence, .. } = c.get_latest_ledger().await.unwrap();
sandbox
.new_assert_cmd("keys")
Expand Down Expand Up @@ -365,7 +365,7 @@ async fn fetch(sandbox: &TestEnv, id: &str) {
let f = sandbox.dir().join("contract.wasm");
let cmd = sandbox.cmd_arr::<fetch::Cmd>(&[
"--rpc-url",
&sandbox.rpc_url,
&sandbox.network.rpc_url,
"--network-passphrase",
LOCAL_NETWORK_PASSPHRASE,
"--id",
Expand Down
24 changes: 12 additions & 12 deletions cmd/crates/soroban-test/tests/it/integration/tx/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async fn create_account() {
.success()
.stdout_as_str();
let test = test_address(sandbox);
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let test_account = client.get_account(&test).await.unwrap();
println!("test account has a balance of {}", test_account.balance);
let starting_balance = ONE_XLM * 100;
Expand All @@ -92,7 +92,7 @@ async fn create_account() {
#[tokio::test]
async fn payment() {
let sandbox = &TestEnv::new();
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let (test, test1) = setup_accounts(sandbox);
let test_account = client.get_account(&test).await.unwrap();
println!("test account has a balance of {}", test_account.balance);
Expand Down Expand Up @@ -125,7 +125,7 @@ async fn payment() {
#[tokio::test]
async fn bump_sequence() {
let sandbox = &TestEnv::new();
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let test = test_address(sandbox);
let before = client.get_account(&test).await.unwrap();
let amount = 50;
Expand All @@ -148,7 +148,7 @@ async fn bump_sequence() {
#[tokio::test]
async fn account_merge() {
let sandbox = &TestEnv::new();
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let (test, test1) = setup_accounts(sandbox);
let before = client.get_account(&test).await.unwrap();
let before1 = client.get_account(&test1).await.unwrap();
Expand Down Expand Up @@ -188,7 +188,7 @@ async fn set_trustline_flags() {
.success();
let id = contract_id_hash_from_asset(
asset.parse::<builder::Asset>().unwrap(),
&sandbox.network_passphrase,
&sandbox.network.network_passphrase,
);
// sandbox
// .new_assert_cmd("contract")
Expand Down Expand Up @@ -224,7 +224,7 @@ async fn set_trustline_flags() {
#[tokio::test]
async fn set_options_add_signer() {
let sandbox = &TestEnv::new();
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let (test, test1) = setup_accounts(sandbox);
let before = client.get_account(&test).await.unwrap();
sandbox
Expand Down Expand Up @@ -286,7 +286,7 @@ fn build_and_run(sandbox: &TestEnv, cmd: &str, args: &[&str]) -> String {
#[tokio::test]
async fn set_options() {
let sandbox = &TestEnv::new();
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let (test, alice) = setup_accounts(sandbox);
let before = client.get_account(&test).await.unwrap();
assert!(before.inflation_dest.is_none());
Expand Down Expand Up @@ -356,7 +356,7 @@ async fn set_options() {
#[tokio::test]
async fn set_some_options() {
let sandbox = &TestEnv::new();
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let test = test_address(sandbox);
let before = client.get_account(&test).await.unwrap();
assert!(before.inflation_dest.is_none());
Expand Down Expand Up @@ -451,7 +451,7 @@ async fn change_trust() {
// wrap_cmd(&asset).run().await.unwrap();
let id = contract_id_hash_from_asset(
asset.parse::<builder::Asset>().unwrap(),
&sandbox.network_passphrase,
&sandbox.network.network_passphrase,
);
sandbox
.new_assert_cmd("contract")
Expand Down Expand Up @@ -529,7 +529,7 @@ async fn change_trust() {
async fn manage_data() {
let sandbox = &TestEnv::new();
let (test, _) = setup_accounts(sandbox);
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let key = "test";
let value = "beefface";
sandbox
Expand Down Expand Up @@ -573,7 +573,7 @@ async fn manage_data() {
}

async fn issue_asset(sandbox: &TestEnv, test: &str, asset: &str, limit: u64, initial_balance: u64) {
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let test_before = client.get_account(test).await.unwrap();
sandbox
.new_assert_cmd("tx")
Expand Down Expand Up @@ -633,7 +633,7 @@ async fn issue_asset(sandbox: &TestEnv, test: &str, asset: &str, limit: u64, ini
#[tokio::test]
async fn multi_create_accounts() {
let sandbox = &TestEnv::new();
let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap();
let client = sandbox.network.rpc_client().unwrap();
let nums: Vec<u8> = (1..=3).collect();
let mut accounts: Vec<(String, String)> = nums
.iter()
Expand Down
1 change: 1 addition & 0 deletions cmd/crates/soroban-test/tests/it/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ mod init;
// #[cfg(feature = "it")]
mod integration;
mod plugin;
mod rpc_provider;
mod util;
mod version;
97 changes: 97 additions & 0 deletions cmd/crates/soroban-test/tests/it/rpc_provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use httpmock::{prelude::*, Mock};
use serde_json::json;
use soroban_rpc::{GetEventsResponse, GetNetworkResponse};
use soroban_test::{TestEnv, LOCAL_NETWORK_PASSPHRASE};

#[tokio::test]
async fn test_use_rpc_provider_with_auth_header() {
// mock out http request to rpc provider
let server = MockServer::start();
let generate_account_mock = mock_generate_account(&server);
let get_network_mock = mock_get_network(&server);
let get_events_mock = mock_get_events(&server);

// create a new test environment with the mock server
let rpc_url = server.url("");
let rpc_headers = vec![("Authorization".to_string(), "Bearer test-token".to_string())];
let sandbox = &TestEnv::with_rpc_provider(&rpc_url, rpc_headers);

sandbox
.new_assert_cmd("events")
.arg("--start-ledger")
.arg("1000")
.assert()
.success();

// generate account is being called in `with_rpc_provider`
generate_account_mock.assert();
// get_network and get_events are being called in the `stellar events` command
get_network_mock.assert();
get_events_mock.assert();
}

fn mock_generate_account(server: &MockServer) -> Mock {
server.mock(|when, then| {
when.method(GET)
.path("/friendbot")
.header("accept", "*/*")
.header("user-agent", "soroban-cli/22.0.1"); //update this to be future proof
then.status(200);
})
}

fn mock_get_network(server: &MockServer) -> Mock {
server.mock(|when, then| {
when.method(POST)
.path("/")
.header("authorization", "Bearer test-token")
.json_body(json!({
"jsonrpc": "2.0",
"id": 0,
"method": "getNetwork"
}));

then.status(200).json_body(json!({
"jsonrpc": "2.0",
"id": 0,
"result": GetNetworkResponse {
friendbot_url: None,
passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(),
protocol_version: 22}
}));
})
}

fn mock_get_events(server: &MockServer) -> Mock {
server.mock(|when, then| {
when.method(POST)
.path("/")
.header("authorization", "Bearer test-token")
.json_body(json!({
"jsonrpc": "2.0",
"id": 1,
"method": "getEvents",
"params": {
"startLedger": 1000,
"filters": [
{
"contractIds": [],
"topics": []
}
],
"pagination": {
"limit": 10
}
}
}));

then.status(200).json_body(json!({
"jsonrpc": "2.0",
"id": 1,
"result": GetEventsResponse {
events: vec![],
latest_ledger: 1000
}
}));
})
}
2 changes: 1 addition & 1 deletion cmd/crates/stellar-ledger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ log = "0.4.21"
once_cell = "1.19.0"
pretty_assertions = "1.2.1"
serial_test = "3.0.0"
httpmock = "0.7.0-rc.1"
httpmock = { workspace = true }
test-case = "3.3.1"
testcontainers = "0.20.1"

Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/config/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl Network {
local_url.set_query(Some(&format!("addr={addr}")));
Ok(local_url)
} else {
let client = Client::new(&self.rpc_url)?;
let client = self.rpc_client()?;
let network = client.get_network().await?;
tracing::debug!("network {network:?}");
let url = client.friendbot_url().await?;
Expand Down
Loading

0 comments on commit 1c0d4e6

Please sign in to comment.