ChaosWriter
ChaosWriter is a lightweight Go library for simulating flaky data streams. It wraps an io.Writer
to inject chaos by applying rate limiting, dynamic rate fluctuations, random delays, and controlled bit-level corruption. This makes it ideal for testing error handling, simulating unreliable network conditions, or fuzzing applications.
Features
- Rate Limiting: Limit write speed to a specified bytes-per-second.
- Dynamic Rate Fluctuations: Simulate variable network conditions.
- Random Delays: Introduce random write delays.
- Bit-level Corruption: Optionally corrupt a percentage of the data bits.
- Fuzzing Support: Optionally process strings with a built-in fuzzer.
Installation
Use go get
to install ChaosWriter:
go get github.com/toxyl/chaoswriter
Usage
ChaosWriter can be used in several ways. Below are three examples demonstrating how to integrate ChaosWriter into your project.
Example 1: Basic Usage with Fuzzing
package main
import (
"fmt"
"os"
"time"
"github.com/toxyl/chaoswriter"
)
func main() {
// Create a ChaosWriter with:
// - A rate of 10 bytes per second with ±90% fluctuation,
// - A 10% chance of corruption per chunk,
// - 10% of bits corrupted in affected chunks,
// - 0-10ms random delay per write.
cw := chaoswriter.New(10, 0.9, 0.10, 0.10, 10*time.Millisecond, os.Stdout)
// Process the string with fuzzing and write it out.
n, _ := cw.Write(
"This is a test to see how much corruption will occur.\n"+
"First we are writing a known text, so we can judge the chaos effects.\n"+
"Then we'll print 10 bytes of random data: [$randBytes:10]\n"+
"And finally we'll print a fuzzed text, such as a random UUID: [#UUID] or a random hash: [#32]",
true,
)
fmt.Printf("\n\nTotal bytes written: %d\n", n)
}
Example 2: Using the Package-Level Write Function
package main
import (
"fmt"
"os"
"time"
"github.com/toxyl/chaoswriter"
)
func main() {
n, _ := chaoswriter.Write(
os.Stdout, // Target writer
"This is a test to see how much corruption will occur.\n"+
"First we are writing a known text, so we can judge the chaos effects.\n"+
"Then we'll print 10 bytes of random data: [$randBytes:10]\n"+
"And finally we'll print a fuzzed text, such as a random UUID: [#UUID] or a random hash: [#32]",
true, // Process string with fuzzer
10, 0.9, // Rate limit: 10B/s with ±90% fluctuation
0.10, 0.10, // Corruption: 10% chance per chunk, 10% corruption intensity
10*time.Millisecond, // 0-10ms random delay per write
)
fmt.Printf("\n\nTotal bytes written: %d\n", n)
}
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"time"
"github.com/toxyl/chaoswriter"
)
func main() {
// Define command-line flags for ChaosWriter options.
fuzz := flag.Bool("fuzz", false, "Enable fuzzing of the input string before writing")
rateBytesSec := flag.Float64("rate", 1024, "Rate limit in bytes per second")
rateFluctuation := flag.Float64("fluctuation", 0.1, "Rate fluctuation as a fraction (0-1)")
corruptionProbability := flag.Float64("corruptionProbability", 0.0, "Probability of corruption (0-1)")
corruptionIntensity := flag.Float64("corruptionIntensity", 0.0, "Intensity of corruption as a fraction of bits (0-1)")
delayStr := flag.String("delay", "0s", "Maximum random delay (e.g., 100ms, 1s)")
flag.Parse()
// Ensure the required positional arguments (input string and target) are provided.
args := flag.Args()
if len(args) < 2 {
fmt.Fprintf(os.Stderr, "Usage: %s [options] <string> <target>\n", os.Args[0])
flag.PrintDefaults()
os.Exit(1)
}
inputStr := args[0]
target := args[1]
// Parse the maximum random delay.
maxDelay, err := time.ParseDuration(*delayStr)
if err != nil {
log.Fatalf("Invalid delay value: %v", err)
}
// Determine the writer: if target is "-", use stdout; otherwise, create the file.
var writer io.Writer
if target == "-" {
writer = os.Stdout
} else {
file, err := os.Create(target)
if err != nil {
log.Fatalf("Failed to create target file: %v", err)
}
defer file.Close()
writer = file
}
// Write the string with chaos injection using the package-level Write function.
written, err := chaoswriter.Write(
writer,
inputStr,
*fuzz,
*rateBytesSec,
*rateFluctuation,
*corruptionProbability,
*corruptionIntensity,
maxDelay,
)
if err != nil {
log.Fatalf("Error writing data: %v", err)
}
fmt.Printf("Successfully wrote %d bytes to %s\n", written, target)
}
Fuzzer Support
When the fuzzing option is enabled (by passing true
as the fuzz
parameter), ChaosWriter processes the input string through a built-in fuzzer. The fuzzer replaces specific tokens in the string with dynamically generated values. It supports the following tokens:
UUIDs and Hashes
[#UUID]
Generates a random UUID (e.g., xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx
).
[#56]
Generates a random 56-character hash.
Random Numbers
[i:6]
Random integer with a 6-character length (zero-padded).
[f:6.2]
Random float with a 6-character integer part and a 2-character fractional part.
[10:500]
Random integer between 10 and 500 (inclusive, can include negative values).
[0.5:5.5]
Random float between 0.5 and 5.5 (inclusive, can include negative values).
Random Strings
[sl:6]
Random lowercase string with 6 characters (a-z).
[su:6]
Random uppercase string with 6 characters (A-Z).
[s:6]
Random mixed-case string with 6 characters (a-z, A-Z).
[al:6]
Random lowercase alphanumeric string with 6 characters (a-z, 0-9).
[au:6]
Random uppercase alphanumeric string with 6 characters (A-Z, 0-9).
[a:6]
Random mixed-case alphanumeric string with 6 characters (a-z, A-Z, 0-9).
Lists and Ranges
[10..500]
Generates a comma-separated list of all integers from 10 to 500 (inclusive).
[a,b,c]
Randomly selects a value from the given list.
Bytes
[$randBytes:n]
Generates n
random bytes.
Data Encoding
[bin:data]
Encodes data as binary.
[b32:data]
Encodes data as Base32.
[b64:data]
Encodes data as Base64.
[b85:data]
Encodes data as Base85.
[hex:data]
Encodes data as hexadecimal.
[url:data]
Encodes data as URL (percent-encoding).
This flexible token replacement system allows you to easily inject dynamic, randomized data into your output streams.
API Overview
ChaosWriter
-
New
Creates a new ChaosWriter
instance that wraps an io.Writer
with the following configuration:
rateBytesSec
: Base rate limit in bytes per second (a minimum value of 0.0001 is enforced).
rateFluctuation
: Maximum fluctuation fraction (0 to 1) applied to the base rate.
corruptionProbability
: Likelihood (0 to 1) that a write operation will corrupt data.
corruptionIntensity
: Fraction (0 to 1) of bits to corrupt when corruption occurs.
maxRandomDelay
: Maximum random delay applied before each write.
w
: The underlying io.Writer
to wrap.
-
Write
Writes a string to the underlying writer, applying rate limiting, random delays, and optional bit-level corruption. If fuzzing is enabled, the string is first processed through the built-in fuzzer.
-
Package-Level Write Function
A convenience function that wraps the creation of a ChaosWriter
and writes a string with chaos injection directly.
License
This project is licensed under the UNLICENSE.