Microsoft Coyote

repository·main·Indexed 23 days ago

https://github.com/microsoft/coyote

A cross-platform toolset for testing concurrent C# code. Coyote allows developers to turn standard unit tests into concurrency unit tests to deterministically explore and reproduce race conditions, deadlocks, and other nondeterministic bugs. It features a TestingEngine API for wrapping test logic and a CLI tool for rewriting IL in binaries to inject execution control hooks. The toolset supports testing unmodified task-based applications and provides a built-in Actor programming model for building reliable distributed services.

Tokens
129.9K
Snippets
571
Records
898
Agent score
80%

What's inside Coyote

  1. Overview of Coyote sample types

    main

    Coyote samples are categorized into two main approaches:

    1. Testing unmodified C# task-based applications

    These samples demonstrate how to use Coyote to find race conditions, deadlocks, and failover issues in existing C# code without requiring significant changes to the application logic.

    • AccountManager: Testing a NoSQL backend application for race conditions.
    • ImageGalleryAspNet: Testing an ASP.NET Core service.
    • Coffee Machine Failover: Testing failover logic in task-based applications.
    • BoundedBuffer: Using coyote rewrite to find deadlocks in unmodified code.

    2. Building with the Coyote Actor programming model

    These samples show how to use Coyote's built-in actor model to build reliable services from the ground up.

    • HelloWorldActors: Basic Coyote application using actors.
    • CloudMessaging: Using Azure Service Bus for actor communication.
    • Coffee Machine Failover: Testing failover in actor-based applications.
    • Robot Navigator Failover: Testing failover in actor-based applications.
    • Timers in Actors: Using the Coyote actor timer API.
  2. What is Coyote?

    main

    Coyote is a .NET library and tool designed for concurrency unit testing. It helps developers identify concurrency bugs and handle non-determinism (such as message ordering, failures, and timeouts) by systematically exploring different interleavings of concurrent operations.

    Key characteristics include:

    • Systematic Exploration: Unlike stress testing, Coyote takes control of concurrency to manipulate scheduling and explore a large set of behaviors quickly.
    • Reproducibility: When a bug is found, Coyote records the path taken, making the bug 100% reproducible.
    • Binary Rewriting: Coyote can take control of concurrency in your unmodified code using binary rewriting during test time.
    • Actor Model: For advanced users, it provides an in-memory actor and state machine programming model using asynchronous C# APIs and a lightweight runtime.
    • Not a Formal Verification System: It uses intelligent search strategies rather than theorem proving to drive systematic testing.
  3. Key benefits of using Coyote

    main

    Coyote is designed to manage the complexity of asynchronous software development through three main pillars:

    1. Design and Implementation: Provides high-level programming abstractions, including an advanced asynchronous actor programming model for high-performance requirements.
    2. Testing: Offers a high-coverage testing tool and support for writing detailed system specifications. It enables automated testing that can be integrated with standard unit-testing frameworks and parallelized to boost coverage.
    3. Debugging and Confidence: Provides the ability to replay reported bugs, which is critical for concurrency-related issues. It also allows for visualizing test coverage.

    Coyote is lightweight and adds no runtime overhead to unmodified task-based programs via binary rewriting. It is battle-tested and used in production by several Azure services.

  4. Raft project structure and components

    main

    The Raft Azure sample is organized into four distinct projects:

    • Raft: A .NET Core C# class library implementing the Raft Consensus Algorithm using the Coyote Actor Programming Model.
    • Raft.Azure: A C# executable that runs Coyote messages through an Azure Service Bus.
    • Raft.Mocking: Demonstrates how to use mocks to systematically test the application in-memory on a local machine without requiring Azure.
    • Raft.Nondeterminism: Demonstrates how to introduce controlled nondeterminism in Coyote tests to exercise corner-cases.
  5. Use SharedObjects for in-memory actor communication

    main

    The Microsoft.Coyote.Actors.SharedObjects namespace provides thread-safe, in-memory data structures designed to be shared among actors. These objects allow actors to communicate and maintain shared state safely during Coyote testing and execution.

    Available shared types include:

    • SharedCounter: A thread-safe counter.
    • SharedDictionary<TKey, TValue>: A thread-safe dictionary for key-value pairs.
    • SharedDictionary: A static dictionary implementation.
    • SharedRegister<T>: A thread-safe register for holding a single value of type T.
    • SharedRegister: A static register implementation.
  6. Understand the Failover Robot Navigator sample

    main

    The Failover robot navigator service with actors sample demonstrates a failover scenario where a service instance is terminated and replaced by a new one without losing data or interrupting the system's operation.

    Scenario Overview

    A Robot serves drinks to clients using a Navigator service. The workflow is:

    1. The Robot starts at an InitialLocation.
    2. The Robot requests a client and a collision-free route from the Navigator.
    3. The Navigator provides the client details and a route (a list of straight line segments).
    4. The Robot traverses the route, reaches the client, selects an appropriate drink (alcoholic for adults, non-alcoholic for minors), and pours it.
    5. The Robot retreats to the InitialLocation.

    Failover Mechanism

    To test reliability, the FailoverDriver randomly kills the Navigator instance by sending a TerminateEvent and starts a new one. To ensure no requests or responses are lost:

    • The Navigator uses a MockStorage actor (a key-value store) to persist incoming requests from the Robot.
    • Once a request is fully processed and the response is sent, the Navigator deletes the record from MockStorage.
    • The new Navigator instance checks MockStorage to recover the state of any pending requests started by the previous instance.

    Key Components

    • Robot & Navigator: Modeled as state machines.
    • FailoverDriver: A state machine that manages the lifecycle of the Navigator (starting and killing it).
    • MockStorage: An Actor providing persistent key-value storage that survives Navigator restarts.
    • MockCognitiveService & MockRoutePlanner: Mock implementations of external services used for object recognition and path planning.
    • LivenessMonitor: Ensures the system never gets stuck and that the Robot always receives valid responses.
  7. Summary of the Raft Azure Tutorial

    main

    This tutorial covers:

    • Hooking Coyote Actors and StateMachines to production messaging platforms like Azure Service Bus.
    • Implementing the Raft consensus algorithm within a Coyote StateMachine.
    • Using CreateActorIdFromName to reserve ActorIds.
    • Generating execution trace visualizations by registering the ActorRuntimeLogGraphBuilder.
  8. Explore the CloudMessaging Sample Components

    main

    The CloudMessaging sample demonstrates how to use Coyote to build and test distributed systems using the Actor Programming Model. It is composed of several specialized parts:

    • Raft: A core C# class library implementing the Raft Consensus Algorithm via the Coyote Actor Programming Model.
    • Raft.Azure: A C# executable demonstrating how to route Coyote messages through an Azure Service Bus.
    • Raft.Mocking: A demonstration of using mocks to systematically perform in-memory testing of the CloudMessaging application.
    • Raft.Nondeterminism: A demonstration of how to introduce controlled nondeterminism into Coyote tests to systematically exercise corner-cases.
  9. Summary of Raft Mocking Tutorial

    main

    The Raft Mocking tutorial demonstrates how to:

    1. Mock external systems: Replace services like Azure Service Bus with local mocks to increase test speed.
    2. Use Coyote CLI: Utilize the coyote test command to explore different test strategies.
    3. Analyze Coverage: Read Coyote coverage reports and view coverage graphs.
    4. Inject Test Logic: Use Coyote Monitor classes to check global invariants (like safety properties) with minimal production overhead.
    5. Model-Based Testing: Use random seeds to explore non-determinism and integrate these tests into CI processes.
  10. What is Coyote and how does it work?

    main

    Coyote is a cross-platform library and tool for testing concurrent C# code and deterministically reproducing bugs. It allows you to write concurrency unit tests that embrace nondeterminism (such as actors, tasks, or concurrent ASP.NET requests) to find race conditions and complex execution path bugs.

    The Workflow:

    1. Convert to Concurrency Test: Use the TestingEngine API to wrap your existing test logic.
    2. Rewrite Binaries: Run the coyote rewrite CLI command (typically as a post-build task) to automatically rewrite the IL of your test and production binaries. This injects hooks that allow Coyote to control concurrent execution.
    3. Execute: Run the test using a standard unit testing framework (like xUnit). Coyote will execute the test for a configured number of iterations, using intelligent search strategies to explore different execution paths.
    4. Reproduce: If a bug is found, use the engine.TestReport API to obtain a trace that allows for reliable, deterministic reproduction of the bug.