Data Loading
Load test data from files, generate dynamic data
Loading Data Files
open(path)Read file contents as string (init phase only). Paths are relative to the working directory (where you run fusillade). Absolute paths, .. traversal and symlinks pointing outside the working directory are rejected for security.
new SharedArray(name, fn)Share large read-only data across workers
new SharedCSV(path)Load CSV with automatic header parsing
SharedArray
Efficiently share large read-only datasets across all workers without memory duplication.
// Load data once, share with all workers
const users = new SharedArray('users', () => JSON.parse(open('./data/users.json')));
export default function() {
// Access shared data (read-only)
const user = users[__WORKER_ID % users.length];
http.post('/login', JSON.stringify({ email: user.email, password: user.password }));
}SharedCSV
Load CSV files efficiently with automatic header parsing. Data is shared across all workers.
# users.csv
email,password,name
user1@example.com,pass123,John
user2@example.com,pass456,Jane# Loading CSV
const users = new SharedCSV('./data/users.csv');
export default function() {
// Get row by index (returns object with column names as keys)
const user = users.get(__WORKER_ID % users.length);
http.post('/login', JSON.stringify({ email: user.email, password: user.password }));
// Get random row
const randomUser = users.random();
}SharedCSV Properties & Methods
length: Number of rows (excluding header)
headers: Array of column names
get(index): Get row by index as object
random(): Get random row as object
JSON Files
# users.json
[
{ "id": 1, "email": "user1@example.com", "password": "pass1" },
{ "id": 2, "email": "user2@example.com", "password": "pass2" },
{ "id": 3, "email": "user3@example.com", "password": "pass3" }
]# Loading JSON
// Using SharedArray (recommended for large files)
const users = new SharedArray('users', () => JSON.parse(open('./data/users.json')));
// Or direct loading (simpler for small files)
const config = JSON.parse(open('./config.json'));
export default function() {
// Random user each iteration
const user = users[Math.floor(Math.random() * users.length)];
http.post('https://api.example.com/login', JSON.stringify({
email: user.email,
password: user.password
}), {
headers: { 'Content-Type': 'application/json' }
});
}Sharing Data Across Workers
Data loaded at the top level is shared across all workers. Use setup() to prepare shared state.
// Loaded once, shared by all workers
const users = new SharedArray('users', () => JSON.parse(open('./data/users.json')));
const products = new SharedCSV('./data/products.csv');
export function setup() {
// Authenticate once, share token
const res = http.post('https://api.example.com/login', JSON.stringify({
email: 'admin@example.com',
password: 'admin'
}));
return { token: res.json().token };
}
export default function(data) {
// Each worker gets the token from setup
const user = users[__WORKER_ID % users.length];
http.get(`https://api.example.com/users/${user.id}`, {
headers: { 'Authorization': 'Bearer ' + data.token }
});
}Dynamic Data Generation
utils.uuid()Generate UUID v4
utils.randomString(length)Random alphanumeric string
utils.randomInt(min, max)Random integer in range
utils.randomItem(array)Random element from array
utils.randomEmail()Generate random email address
utils.randomPhone()Generate random US phone number
utils.randomName()Random name {first, last, full}
utils.randomAddress()Random US address {street, city, state, zip, full}
utils.randomDate(startYear, endYear)Random date (YYYY-MM-DD)
utils.sequentialId()Unique sequential ID across workers
export default function() {
const payload = {
id: utils.uuid(),
username: 'user_' + utils.randomString(8),
age: utils.randomInt(18, 65),
tier: utils.randomItem(['free', 'pro', 'enterprise']),
email: utils.randomEmail(), // "xk7f2b1q@test.com"
phone: utils.randomPhone(), // "+1-555-847-2901"
name: utils.randomName().full, // "John Smith"
dob: utils.randomDate(1970, 2000), // "1985-07-23"
orderId: utils.sequentialId(), // unique ID per worker
};
http.post('https://api.example.com/users', JSON.stringify(payload));
}Weighted Random Selection
// Custom weighted selection
function weightedRandom(items) {
const total = items.reduce((sum, item) => sum + item.weight, 0);
let random = Math.random() * total;
for (const item of items) {
random -= item.weight;
if (random <= 0) return item.value;
}
return items[items.length - 1].value;
}
const actions = [
{ value: 'browse', weight: 70 }, // 70% browse
{ value: 'search', weight: 20 }, // 20% search
{ value: 'purchase', weight: 10 }, // 10% purchase
];
export default function() {
const action = weightedRandom(actions);
switch (action) {
case 'browse':
http.get('https://api.example.com/products');
break;
case 'search':
http.get('https://api.example.com/search?q=' + utils.randomString(5));
break;
case 'purchase':
http.post('https://api.example.com/orders', JSON.stringify({ product: 1 }));
break;
}
}Unique Data per Worker
const users = new SharedCSV('./data/users.csv');
export default function() {
// Each worker gets a unique user (wraps around if more workers than users)
const user = users.get(__WORKER_ID % users.length);
// Or unique per iteration
const item = users.get(__ITERATION % users.length);
print(`Worker ${__WORKER_ID} iteration ${__ITERATION} using ${user.email}`);
}Per-Worker State
Use __WORKER_STATE to persist data across iterations within each worker.
export default function() {
// Track per-worker state across iterations
__WORKER_STATE.loginCount = (__WORKER_STATE.loginCount || 0) + 1;
console.log(`Worker ${__WORKER_ID} iteration ${__ITERATION}, logins: ${__WORKER_STATE.loginCount}`);
// Store session data that persists across iterations
if (!__WORKER_STATE.token) {
const res = http.post('/login', JSON.stringify(credentials));
__WORKER_STATE.token = res.json().token;
}
// Use cached token in subsequent iterations
http.get('/api/data', {
headers: { 'Authorization': `Bearer ${__WORKER_STATE.token}` }
});
}Environment Variables
Access environment variables via the __ENV global object.
// Access environment variables
const apiKey = __ENV.API_KEY;
const baseUrl = __ENV.BASE_URL || 'https://api.example.com';
export default function() {
http.get(baseUrl + '/data', {
headers: { 'X-API-Key': apiKey }
});
}
// Run with:
// API_KEY=secret123 BASE_URL=https://staging.api.com fusillade run test.jsAutomatic .env File Loading
Fusillade automatically loads .env files when running tests. It checks:
1. The script's directory first
2. The current working directory
# .env file format
API_KEY=your-secret-key
BASE_URL=https://api.example.com
DEBUG=trueEnvironment variables set in the shell take precedence over .env file values.
Binary Files
// Load binary file for upload testing
const imageFile = http.file('./data/test-image.png', 'upload.png', 'image/png');
export default function() {
const form = new FormData();
form.append('file', imageFile);
form.append('description', 'Test upload');
http.post('https://api.example.com/upload', form.body(), {
headers: form.headers()
});
}Working with Large Datasets
1. Data is loaded once at script initialization, not per iteration
2. SharedArray/SharedCSV share data across workers without duplication
3. For very large datasets, consider loading only what you need
4. Use __WORKER_ID and __ITERATION to partition data across workers
// Partition large dataset across workers
const allUsers = new SharedCSV('./data/million_users.csv');
const chunkSize = Math.ceil(allUsers.length / options.workers);
export default function() {
const start = __WORKER_ID * chunkSize;
const end = Math.min(start + chunkSize, allUsers.length);
// Each worker works with its own subset
const idx = start + (__ITERATION % (end - start));
const user = allUsers.get(idx);
}