Skip to content

Commit

Permalink
✨ Added new function to read keypair file generated by Anchor
Browse files Browse the repository at this point in the history
Until now it was necessary to manually change the program ID to some of the keys predefined by Trdelnik. Now the test template automatically uses the the program keypair generated by Anchor and no manual modification of the program and Anchor.toml is necessary.
  • Loading branch information
Ikrk committed Sep 18, 2023
1 parent b33642a commit d8a6a71
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 16 deletions.
15 changes: 3 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ async fn init_fixture() -> Fixture {
// create a test fixture
let mut fixture = Fixture {
client: Client::new(system_keypair(0)),
// make sure your program is using a correct program ID
program: program_keypair(1),
// make sure to pass the correct name of your program
program: anchor_keypair("my_program_name").unwrap(),
state: keypair(42),
};
// deploy a tested program
// deploy the program to test
fixture.deploy().await?;
// call instruction init
my_instruction::initialize(
Expand Down Expand Up @@ -129,15 +129,6 @@ async fn test_happy_path(#[future] init_fixture: Result<Fixture>) {
}
```

Make sure your program is using a correct program ID in the `derive_id!(...)` macro and inside `Anchor.toml`.
If not, obtain the public key of a key pair you're using and replace it in these two places.
To get the program ID of a key pair (key pair's public key) the `trdelnik key-pair` command can be used.
For example
```
$ trdelnik key-pair program 7
```
will print information about the key pair received from `program_keypair(7)`.

#### Instructions with custom structures

- If you want to test an instruction which has custom structure as an argument
Expand Down
33 changes: 33 additions & 0 deletions crates/client/src/keys.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,37 @@
use std::error::Error;

use anchor_client::solana_sdk::signer::keypair::Keypair;
use heck::ToSnakeCase;
use solana_sdk::signer::EncodableKey;

use crate::config::Config;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum KeyPairError {
#[error("Cannot find the Anchor.toml file to locate the root folder")]
BadWorkspace,
#[error("Cannot the program keypair JSON file generated by Anchor")]
AnchorKeypairNotFound,
}

/// Reads program keypair JSON file generated by Anchor based on `program_name`. Returns error if not found.
pub fn anchor_keypair(program_name: &str) -> Result<Keypair, Box<dyn Error>> {
let root = match Config::discover_root() {
Ok(root) => root,
Err(_) => return Err(KeyPairError::BadWorkspace.into()),
};
let keypair_path = root
.join("target")
.join("deploy")
.join(format!("{}-keypair.json", program_name.to_snake_case()));

if !keypair_path.exists() {
return Err(KeyPairError::AnchorKeypairNotFound.into());
}

Keypair::read_from_file(keypair_path)
}

/// Generate a random keypair.
pub fn random_keypair() -> Keypair {
Expand Down
3 changes: 1 addition & 2 deletions crates/client/src/templates/trdelnik-tests/test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use fehler::throws;
use program_client::*;
use trdelnik_client::{anyhow::Result, *};

// @todo: create and deploy your fixture
Expand Down Expand Up @@ -30,7 +29,7 @@ impl Fixture {
fn new() -> Self {
Fixture {
client: Client::new(system_keypair(0)),
program: program_keypair(1),
program: anchor_keypair("###PROGRAM_NAME###").unwrap(),
state: keypair(42),
}
}
Expand Down
5 changes: 4 additions & 1 deletion crates/client/src/test_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ impl TestGenerator {
throw!(Error::NoProgramsFound)
};
let test_content = test_content.replace("###PROGRAM_NAME###", program_name);
self.create_file(&test_path, TESTS_FILE_NAME, &test_content)
let use_instructions = format!("use program_client::{}_instruction::*;\n", program_name);
let template = format!("{use_instructions}{test_content}");

self.create_file(&test_path, TESTS_FILE_NAME, &template)
.await?;

let cargo_toml_path = workspace_path.join(CARGO_TOML);
Expand Down
6 changes: 5 additions & 1 deletion examples/escrow/trdelnik-tests/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,12 @@ impl Fixture {
fn new() -> Self {
Fixture {
client: Client::new(system_keypair(0)),
program: program_keypair(1),

// We use the hardcoded program_keypair(1) to ensure users can run these tests without the
// need to modify the program ID in the program's lib.rs source file and in Anchor.toml configuraiton file.
// However the default option in the test template is now to use the keypair generated by Anchor
// located in target/deploy folder using the function anchor_keypair("name_of_your_program").
program: program_keypair(1),
mint_a: keypair(1),
mint_b: keypair(2),
mint_authority: system_keypair(1),
Expand Down
5 changes: 5 additions & 0 deletions examples/turnstile/trdelnik-tests/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ async fn init_fixture() -> Fixture {
// create a test fixture
let fixture = Fixture {
client: Client::new(system_keypair(0)),

// We use the hardcoded program_keypair(1) to ensure users can run these tests without the
// need to modify the program ID in the program's lib.rs source file and in Anchor.toml configuraiton file.
// However the default option in the test template is now to use the keypair generated by Anchor
// located in target/deploy folder using the function anchor_keypair("name_of_your_program").
program: program_keypair(1),
state: keypair(42),
user_initializer: keypair(45),
Expand Down

0 comments on commit d8a6a71

Please sign in to comment.