Skip to main content

Run unit tests

After making input verification changes to the queries, running the tests will result in failures with the message, "User must sign this operation." This indicates success, as the original test implementation did not account for signing.

To fix this, the test transactions need to be signed using .sign(keypair). For example, in the test_create_entities function, the transaction is signed with Alice's keypair:

src/test/news_feed_test.rell
val alice_kp = rell.test.keypairs.alice; // <--

function test_create_entities() {
rell.test.tx()
.op(create_user("Alice", alice))
.op(create_user("Bob", bob))
.run();
assert_equals(user @ { } ( @sum 1 ), 2);
rell.test.tx()
.op(ft_auth_operation_for(alice))
.op(follow_user(bob))
.op(ft_auth_operation_for(alice))
.op(make_post("My post"))
.sign(alice_kp)
.run();
assert_true(is_following(alice, bob));
assert_equals(follower @ { } ( @sum 1 ), 1);
assert_equals(post @ { } ( @sum 1 ), 1);
rell.test.tx()
.op(ft_auth_operation_for(alice))
.op(unfollow_user(bob))
.sign(alice_kp)
.run();
assert_equals(follower @ { } ( @sum 1 ), 0);
}

In the second test case, test_follower_calculation, the transaction also needs to be signed:

src/test/news_feed_test.rell
function test_follower_calculation() {
...
rell.test.tx()
.op(ft_auth_operation_for(alice))
.op(follow_user(bob))
.op(ft_auth_operation_for(alice))
.op(follow_user(charlie))
.sign(alice_kp) // <--
.run();
...
}

For the last test case, the follow_user transaction should be signed by Alice, while the make_post transactions should be signed by Bob. A new constant for Bob's keypair is added and the following adjustments are made:

src/test/news_feed_test.rell
val bob_kp = rell.test.keypairs.bob;

function test_pagination_of_posts() {
rell.test.tx()
.op(create_user("Alice", alice))
.op(create_user("Bob", bob)).run();
rell.test.tx()
.op(ft_auth_operation_for(alice))
.op(follow_user(bob))
.sign(alice_kp) // <--
.run();

for (i in range(5)) {
rell.test.tx().op(make_post(bob, "Content %d".format(i))).sign(bob_kp).run(); // <--
}
...
}

All tests now work as expected.

Additional testing

A new test case should be added to confirm that impersonation is not possible and that input validation works correctly:

src/test/news_feed_test.rell
val charlie_kp = rell.test.keypairs.charlie;

function test_input_verification() {
rell.test.tx()
.op(create_user("Alice", alice))
.op(create_user("Bob", bob)).run();

// Bob cannot impersonate alice
rell.test.tx()
.op(ft_auth_operation_for(alice))
.op(follow_user(bob))
.sign(bob_kp)
.run_must_fail();
rell.test.tx()
.op(ft_auth_operation_for(alice))
.op(make_post("My malicous post"))
.sign(bob_kp)
.run_must_fail();

// Alice cannot follow non-existing charlie
val f1 = rell.test.tx()
.op(ft_auth_operation_for(alice))
.op(follow_user(charlie))
.sign(alice_kp)
.run_must_fail();
assert_true(f1.message.contains("does not exist"));

// Charlie cannot create post since he does not exist
val f2 = rell.test.tx()
.op(make_post("My secret post"))
.sign(charlie_kp)
.run_must_fail();
assert_true(f2.message.contains("Expected at least two operations"));
}

Manual testing

For manual testing, as in the previous module, the generated keypairs should be stored instead of just the public keys. This can be done by running:

chr keygen --file <target>

The Chromia CLI looks for .chromia/config, but this can be overridden using the --secret flag of chr tx. Save the keypairs for Alice and Bob as follows:

chr keygen --file .chromia/config-alice
chr keygen --file .chromia/config-bob

These keypairs can now be used for making transactions, ensuring that the correct key is used for signing.

chr node start
chr tx --await create_user Alice 'x"<alice-pubkey>"'
chr tx --await create_user Bob 'x"<bob-pubkey>"'
chr tx --await --secret .chromia/config-bob follow_user 'x"<alice-pubkey>"' 'x"<bob-pubkey>"' # Fails
chr tx --await --secret .chromia/config-alice follow_user 'x"<alice-pubkey>"' 'x"<bob-pubkey>"' # Succeeds

Congratulations! Basic input validation on queries and operations has been learned. In the next module, more secure and structured account management using the ft-library will be explored.