Skip to content

Commit

Permalink
Merge branch 'main' of github.com:stellar/stellar-docs into homepage-…
Browse files Browse the repository at this point in the history
…wayfinding
  • Loading branch information
ElliotFriend committed Dec 20, 2024
2 parents f561a0a + c9e3724 commit cf5bbbe
Show file tree
Hide file tree
Showing 39 changed files with 881 additions and 159 deletions.
62 changes: 62 additions & 0 deletions CROWDIN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Crowdin Translator How-To

Stellar Developer Docs use [Crowdin](https://crowdin.com/) for localization. This document provides steps and resources for managing Stellar Docusaurus Crowdin translations as a Crowdin user with a Translator role.

---

## Overview

As new English source files are added to the Stellar Docusaurus Documentation GitHub repository, they are automatically uploaded to Crowdin. From there, an automated AI translation is run on the files to translate them into other target languages (currently only Spanish at the time of writing).

In cases where the AI translation is inaccurate, a user with the Translator role will need to update and edit the translations manually.

---

## Translator User

To get started, you need to set up a Crowdin account and be added to the Stellar Documents Crowdin project. This involves creating a Crowdin user account and requesting access to the project from a project owner.

For more details, see the following documentation:
[Create an Account](https://support.crowdin.com/for-translators/#create-an-account)

---

## Editor

As a translator, you will have access to the editor, where you can make changes to the content.

**Note:** Crowdin uses the term "strings" for content being translated.

You can access all translated documents via the Crowdin dashboard. From there, you can view each document in the editor.

For more details on working within the editor, see the following documentation:
[Working in the Editor](https://support.crowdin.com/for-translators/#working-in-the-editor)

For a more in-depth look, see:
[Online Editor Guide](https://support.crowdin.com/online-editor/)

---

## Glossary

For common words or phrases, it is good practice to add them to the glossary. The glossary helps the AI translator provide more accurate translations.

Examples include:
- Words or phrases that need to be translated in a specific manner.
- Words or phrases that should not be translated at all.

For more information, see the following documentation:
[Glossary](https://support.crowdin.com/glossary/)

---

## Approving Translations

As documents are translated, they will be assigned a translation percentage highlighted in blue.

To manage files that have been checked or proofread, it is recommended to mark them as approved. Approved files will display an approved percentage highlighted in green.

**Note:** All translations are synced with the Stellar Docusaurus Documentation after they are reviewed and approved. Approval is a check for managing translation files that have been edited.

For more information on approving translations, see the following documentation:
[Proofreading](https://support.crowdin.com/online-editor/#proofreading)
2 changes: 1 addition & 1 deletion docs/build/guides/conventions/deploy-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ This guide walks through the process of deploying a smart contract from installe

### Setup environment

The [deployer example](https://github.com/stellar/soroban-examples/tree/v21.6.0/deployer) demonstrates how to deploy contracts using a contract.
The [deployer example](https://github.com/stellar/soroban-examples/tree/v22.0.1/deployer) demonstrates how to deploy contracts using a contract.

1. Clone the Soroban Examples Repository:

Expand Down
4 changes: 2 additions & 2 deletions docs/build/guides/conventions/upgrading-contracts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ The [upgradeable contract example] demonstrates how to upgrade a Wasm contract.

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)][oigp]

[oigp]: https://gitpod.io/#https://github.com/stellar/soroban-examples/tree/v21.6.0
[upgradeable contract example]: https://github.com/stellar/soroban-examples/tree/v21.6.0/upgradeable_contract
[oigp]: https://gitpod.io/#https://github.com/stellar/soroban-examples/tree/v22.0.1
[upgradeable contract example]: https://github.com/stellar/soroban-examples/tree/v22.0.1/upgradeable_contract
[Rust programming language]: https://www.rust-lang.org/

### Code
Expand Down
9 changes: 9 additions & 0 deletions docs/build/guides/testing/coverage-testing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Coverage Testing
hide_table_of_contents: true
description: Coverage testing finds code not tested.
sidebar_position: 10
draft: true
---

**TODO: Fill in example.**
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
---
title: Detecting Unexpected Changes with Test Snapshots
title: Differential Tests with Test Snapshots
hide_table_of_contents: true
description: Use test snapshots to detect unexpected changes in contract behavior
description: Differential testing using automatic test snapshots.
sidebar_position: 8
---

Tests are written to ensure that contracts behave today as expected, and in the future as well. Over time a contract may change and in all software development there remains the possibility of changes causing side-effects that are unexpected. Testing is one of the ways that we identify unexpected changes.

However tests are limited, as they only show changes to values that the tests assert on.

## Test Snapshots
:::tip

The Soroban Rust SDK generates test snapshots on every test involving an `Env`. Test snapshots are enabled by default. At the end of the test the `Env` writes a JSON file to the `test_snapshots` directory with a full snapshot of all the events published, logged, and the final ledger storage state.
Test snapshots are one tool for performing differential testing. See [Differential Testing] for other ways.

:::

### Test Snapshots

The Soroban Rust SDK generates test snapshots on every test involving an `Env`. Test snapshots are enabled by default. At the end of the test the `Env` writes a JSON file to the `test_snapshots` directory with a full snapshot of all the events published, and the final ledger storage state.

Most tests have a single `Env` and will result in a single test snapshot. Tests that have multiple `Env`s will write multiple test snapshots, one for each `Env`. Test snapshot files are named with a incrementing number on the end to separate the test snapshots for each `Env`.

Expand All @@ -32,8 +39,10 @@ Most tests have a single `Env` and will result in a single test snapshot. Tests

assert_eq!(client.increment(), 1);

// highlight-start
// At the end of the test the Env will automatically write a test snapshot
// to the following directory: test_snapshots/test_abc.1.json
// highlight-end
}
```

Expand All @@ -43,11 +52,16 @@ Most tests have a single `Env` and will result in a single test snapshot. Tests

4. On future updates look out for changes to test snapshots in tests that are unexpected. For example, when changing one part of a contract if the test snapshots for other parts of the contract or unrelated end-to-end tests change, that could signal that side-effects have occurred.

5. As needed, diff test snapshots as needed to look for hints to why the unexpected change may have occurred.
5. Diff test snapshots as needed to look for hints to why an unexpected change has occurred.

:::info

Test snapshots files are verbose. Test snapshots are most useful when changes appear and can be diffed, such as a new event being published, or storage changing.

Note that test snapshots are extremely verbose and thoroughly understanding each in isolation may not be realistic. Test snapshots are most useful when changes appear and can be diffed, such as a new event being published, or storage changing.
:::

To give this a go, check out the [Getting Started] contract or any of the [examples], run the tests, and look for the test snapshots on disk.

[Differential Testing]: ./differential-tests.mdx
[Getting Started]: ../../smart-contracts/getting-started/README.mdx
[examples]: ../../smart-contracts/example-contracts/README.mdx
119 changes: 119 additions & 0 deletions docs/build/guides/testing/differential-tests.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
title: Differential Tests
hide_table_of_contents: true
description: Differential testing detects unintended changes.
sidebar_position: 7
---

Differential testing is the testing of two things to discover differences in their behavior.

The goal is to prove that the two things behave consistently, and that they do not diverge in behavior except for some expected differences. The assertions should be as broad as possible, broadly testing that all observable outcomes do not change, except for any expected changes.

This strategy is effective when building something new that should behave like something that already exists. That could be a new version of a contract that has unchanged behavior from it's previous version. Or it could be the same contract with an updated SDK or other dependency. Or it could be a refactor that expects no functional changes.

This strategy can be used in the context of unit and integration tests, or in the context of fuzz tests as well.

:::tip

All contracts built with the Rust Soroban SDK have a form of differential testing built-in and enabled by default. See [Differential Testing with Test Snapshots].

:::

## How to Write Differential Tests

To experiment with writing a differential test, open a contract that you've deployed, or checkout an example from the [soroban-examples] repository and deploy it.

Assuming the contract has been deployed, and changes are being made to the local copy. We need to check that unchanged behavior in the contract hasn't changed compared to what is deployed.

1. Use the [stellar contract fetch] command to fetch the contract that's already deployed. The contract already deployed will be used as a baseline that the local copy is expected to behave like.

```shell
stellar contract fetch --id C... --out-file contract.wasm
```

2. Import the contract into the tests with the `contractimport!` macro.

```rust
mod deployed {
soroban_sdk::contractimport!(file = "contract.wasm");
}
```

3. Write a test that runs the same logic for the deployed contract and the local contract, comparing the result. Assuming the [increment example] is in use, the test would look something like the following.

```rust
#![cfg(test)]
use crate::{IncrementContract, IncrementContractClient};
use soroban_sdk::{testutils::Events as _, Env};

mod deployed {
soroban_sdk::contractimport!(file = "contract.wasm");
}

#[test]
fn differential_test() {
let env = Env::default();
assert_eq!(
// Baseline – the deployed contract
{
let contract_id = env.register(deployed::WASM, ());
let client = IncrementContractClient::new(&env, &contract_id);
(
// Return Values
(
client.increment(),
client.increment(),
client.increment(),
),
// Events
env.events.all(),
)
},
// Local – the changed or refactored contract
{
let contract_id = env.register(IncrementContract, ());
let client = IncrementContractClient::new(&env, &contract_id);
(
// Return Values
(
client.increment(),
client.increment(),
client.increment(),
),
// Events
env.events.all(),
)
},
);
}
```

4. Run the test to compare the baseline and local observable outcomes.

This test uses the same patterns used in [unit tests] and [integration tests]:

1. Create an environment, the `Env`.
2. Import the Wasm contract to compare with.
3. Register the local contract to be tested.
4. Invoke functions using a client.
5. Assert equality.

:::tip

Differential tests work best when less assumptions are made. Rather than asserting only on specific return values or on implementation details like specific state, asserting on all observable outcomes and including things like events published or return values of other read-only contract functions will help to discover unexpected changes.

:::

:::info

Depending on the test complexity it can be desirable to use an independent `Env` for testing the deployed vs local. However at the moment it is only possible to compare host values, like `String`, `Bytes`, `Vec`, `Map`, if they've been created using the same `Env`. The tracking issue for supportin comparisons across environments is [stellar/rs-soroban-sdk#1360].

:::

[Getting Started]: ../../smart-contracts/getting-started
[increment example]: https://github.com/stellar/soroban-examples/blob/main/increment/src/lib.rs
[Differential Testing with Test Snapshots]: ./differential-tests-with-test-snapshots.mdx
[stellar contract fetch]: ../../../tools/developer-tools/cli/stellar-cli.mdx#stellar-contract-fetch
[integration tests]: ./integration-tests.mdx
[unit tests]: ./unit-tests.mdx
[stellar/rs-soroban-sdk#1360]: https://github.com/stellar/rs-soroban-sdk/issues/1360
126 changes: 126 additions & 0 deletions docs/build/guides/testing/fuzzing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
title: Fuzzing
hide_table_of_contents: true
description: Fuzzing and property testing to find unexpected behavior.
sidebar_position: 5
---

Fuzzing is the process of providing random data to programs to identify unexpected behavior, such as crashes and panics.

Fuzz tests can also be written as property tests that instead of seeking to identify panics and crashes, assert on some property remaining true. Fuzzing as demonstrated here and elsewhere in these docs will use principles from both property testing and fuzzing, but will only use the term fuzzing to refer to both.

The following steps can be used in any Stellar contract workspace. If experimenting, try them in the [increment example]. The contract has an `increment` function that increases a counter value by one on every invocation.

## How to Write Fuzz Tests

1. Install `cargo-fuzz`.

```shell
cargo install --locked cargo-fuzz
```

2. Initialize a fuzz project by running the following command inside your contract directory.

```shell
cargo fuzz init
```

3. Open the contract's `Cargo.toml` file. Add `lib` as a `crate-type`.

```diff
[lib]
-crate-type = ["cdylib"]
+crate-type = ["lib", "cdylib"]
```

4. Open the generated `fuzz/Cargo.toml` file. Add the `soroban-sdk` dependency.

```diff
[dependencies]
libfuzzer-sys = "0.4"
+soroban-sdk = { version = "*", features = ["testutils"] }
```

5. Open the generated `fuzz/src/fuzz_target_1.rs` file. It will look like the below.

```rust
#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
// fuzzed code goes here
});
```

6. Fill out the `fuzz_target!` call with test setup and assertions. For example, for the [increment example]:

```rust
#![no_main]
use libfuzzer_sys::fuzz_target;
use soroban_increment_with_fuzz_contract::{IncrementContract, IncrementContractClient};
use soroban_sdk::{
testutils::arbitrary::{self, Arbitrary},
Env,
};

#[derive(Debug, Arbitrary)]
pub struct Input {
pub by: u64,
}

fuzz_target!(|input: Input| {
let env = Env::default();
let id = env.register(IncrementContract, ());
let client = IncrementContractClient::new(&env, &id);

let mut last: Option<u32> = None;
for _ in input.by.. {
match client.try_increment() {
Ok(Ok(current)) => assert!(Some(current) > last),
Err(Ok(_)) => {} // Expected error
Ok(Err(_)) => panic!("success with wrong type returned"),
Err(Err(_)) => panic!("unrecognised error"),
}
}
});
```

7. Execute the fuzz target.

```shell
cargo +nightly fuzz run --sanitizer=thread fuzz_target_1
```

:::info

If you're developing on MacOS you need to add the `--sanitizer=thread` flag in order to work around a [known issue](https://github.com/stellar/rs-soroban-sdk/issues/1056).

:::

This test uses the same patterns used in [unit tests] and [integration tests]:

1. Create an environment, the `Env`.
2. Register the contract to be tested.
3. Invoke functions using a client.
4. Assert expectations.

:::tip

For a full detailed example, see the [fuzzing example].

:::

:::info

There is another tool for fuzzing Rust code, `cargo-afl`. See the [Rust Fuzz book] for a tutorial for how to use it.

:::

[increment example]: https://github.com/stellar/soroban-examples/blob/main/increment/src/lib.rs
[Differential Testing with Test Snapshots]: ./differential-tests-with-test-snapshots.mdx
[stellar contract fetch]: ../../../tools/developer-tools/cli/stellar-cli.mdx#stellar-contract-fetch
[integration tests]: ./integration-tests.mdx
[unit tests]: ./unit-tests.mdx
[stellar/rs-soroban-sdk#1360]: https://github.com/stellar/rs-soroban-sdk/issues/1360
[fuzzing example]: ../../smart-contracts/example-contracts/fuzzing.mdx
[Rust Fuzz Book]: https://rust-fuzz.github.io/book
Loading

0 comments on commit cf5bbbe

Please sign in to comment.