0.1.2 • Published 1 month ago

@sovereign-sdk/test v0.1.2

Weekly downloads
-
License
-
Repository
github
Last release
1 month ago

@sovereign-sdk/test

Testing utilities for Sovereign SDK rollups, including soak testing and transaction generation.

Installation

npm install @sovereign-sdk/test

Usage

The package provides utilities for testing Sovereign SDK rollups, with a focus on soak testing and transaction generation. Soak testing helps verify the stability and performance of your rollup under sustained load by continuously submitting transactions.

Note: Currently, soak tests require a pre-started rollup node to run against. In a future version, we plan to add functionality to manage the rollup process lifecycle (starting, stopping, and monitoring the node) as part of the test framework.

Transaction Generators

Transaction generators are responsible for creating individual test transactions. They implement the TransactionGenerator interface:

import { TransactionGenerator } from "@sovereign-sdk/test/soak";

class MyTransactionGenerator implements TransactionGenerator<YourTypeSpec> {
  async successful(): Promise<GeneratedInput<YourTypeSpec>> {
    // Create a transaction that should succeed
    const unsignedTransaction = {
      // Your transaction details
    };

    const signer = await getSigner();

    return {
      unsignedTransaction,
      signer,
      onSubmitted: async (result) => {
        // Verify transaction results
        // Check events
        // Validate state changes
      },
    };
  }

  async failure(): Promise<GeneratedInput<YourTypeSpec>> {
    // Create a transaction that should fail
    const unsignedTransaction = {
      // Your invalid transaction details
    };

    const signer = await getSigner();

    return {
      unsignedTransaction,
      signer,
      onSubmitted: async (result) => {
        // Verify the transaction failed as expected
        // Check error messages
        // Validate state remains unchanged
      },
    };
  }
}

Generator Strategies

Generator strategies determine how multiple transactions are generated and executed. The package provides a BasicGeneratorStrategy that generates a fixed number of successful transactions:

import { BasicGeneratorStrategy } from "@sovereign-sdk/test/soak";

const generator = new MyTransactionGenerator();
const strategy = new BasicGeneratorStrategy(generator);

// Generate 100 transactions
const transactions = await strategy.generate(100);

You can also create custom strategies by implementing the GeneratorStrategy interface:

import { GeneratorStrategy, Outcome } from "@sovereign-sdk/test/soak";

class CustomStrategy implements GeneratorStrategy<YourTypeSpec> {
  private readonly generators: TransactionGenerator<YourTypeSpec>[];

  constructor(generators: TransactionGenerator<YourTypeSpec>[]) {
    this.generators = generators;
  }

  async generate(amount: number): Promise<InputWithExpectation<YourTypeSpec>[]> {
    const transactions = [];

    for (let i = 0; i < amount; i++) {
      // Choose a generator based on your strategy
      const generator = this.selectGenerator();
      const transaction = await generator.successful();
      transactions.push({
        input: transaction,
        expectedOutcome: Outcome.Success
      });
    }

    return transactions;
  }

  private selectGenerator(): TransactionGenerator<YourTypeSpec> {
    // Implement your selection logic
    return this.generators[Math.floor(Math.random() * this.generators.length)];
  }
}

Running Soak Tests

To run a soak test, create a test runner with your strategy:

import { TestRunner } from "@sovereign-sdk/test/soak";

const rollup = await createStandardRollup<YourTypeSpec>({
  context: { defaultTxDetails },
});

const strategy = new YourStrategy();
const runner = new TestRunner<S>({
  rollup,
  generator: strategy,
  concurrency: 30, // Adjust based on your needs
});

// Start the test
await runner.run();

// Stop when needed
await runner.stop();

Note: The current API requires manual management of the test runner lifecycle (start/stop). In a future version, we plan to simplify this by handling the lifecycle internally, so users won't need to manage these operations in their code.

Example

See the soak-testing example for a complete implementation of a bank transfer soak test.

API Reference

TransactionGenerator

Interface for generating individual test transactions.

abstract class TransactionGenerator<S extends BaseTypeSpec> {
  abstract successful(): Promise<GeneratedInput<S>>;
  abstract failure(): Promise<GeneratedInput<S>>;
}

GeneratorStrategy

Interface for generating batches of test transactions.

interface GeneratorStrategy<S extends BaseTypeSpec> {
  generate(amount: number): Promise<InputWithExpectation<S>[]>;
}

TestRunner

Class for running soak tests.

class TestRunner<S extends BaseTypeSpec> {
  constructor(options: {
    rollup: StandardRollup<S>;
    generator: GeneratorStrategy<S>;
    concurrency: number;
  });

  run(): Promise<void>;
  stop(): Promise<void>;
}