Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
670
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/README.md
vendored
Normal file
670
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/README.md
vendored
Normal file
@@ -0,0 +1,670 @@
|
||||
# CI/CD Automation Examples for agentic-synth
|
||||
|
||||
Comprehensive examples demonstrating how to integrate agentic-synth into your CI/CD pipelines for automated test data generation.
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains production-ready examples for generating synthetic test data in CI/CD environments:
|
||||
|
||||
- **test-data-generator.ts** - Generate database fixtures, API mocks, user sessions, load test data, and environment configurations
|
||||
- **pipeline-testing.ts** - Create dynamic test cases, edge cases, performance tests, security tests, and regression tests
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install @ruvector/agentic-synth
|
||||
|
||||
# Set up environment variables
|
||||
export GEMINI_API_KEY="your-api-key-here"
|
||||
# OR
|
||||
export OPENROUTER_API_KEY="your-api-key-here"
|
||||
```
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```typescript
|
||||
import { CICDTestDataGenerator } from './test-data-generator';
|
||||
|
||||
// Generate all test data
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: './test-fixtures',
|
||||
provider: 'gemini',
|
||||
seed: 'reproducible-seed'
|
||||
});
|
||||
|
||||
await generator.generateAll();
|
||||
```
|
||||
|
||||
## GitHub Actions Integration
|
||||
|
||||
### Example Workflow
|
||||
|
||||
Create `.github/workflows/test-data-generation.yml`:
|
||||
|
||||
```yaml
|
||||
name: Generate Test Data
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
generate-test-data:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Generate test data
|
||||
env:
|
||||
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
node -e "
|
||||
import('./test-data-generator.js').then(async ({ CICDTestDataGenerator }) => {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: './test-fixtures',
|
||||
seed: process.env.GITHUB_SHA
|
||||
});
|
||||
await generator.generateAll();
|
||||
});
|
||||
"
|
||||
|
||||
- name: Upload test data
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-data
|
||||
path: test-fixtures/
|
||||
retention-days: 7
|
||||
|
||||
- name: Run tests with generated data
|
||||
run: npm test
|
||||
```
|
||||
|
||||
### Parallel Test Generation
|
||||
|
||||
```yaml
|
||||
name: Parallel Test Data Generation
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
data-type: [fixtures, mocks, sessions, performance]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Generate ${{ matrix.data-type }} data
|
||||
env:
|
||||
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
||||
run: |
|
||||
node generate-${{ matrix.data-type }}.js
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.data-type }}-data
|
||||
path: test-data/
|
||||
```
|
||||
|
||||
## GitLab CI Integration
|
||||
|
||||
### Example Pipeline
|
||||
|
||||
Create `.gitlab-ci.yml`:
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
- generate
|
||||
- test
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
TEST_DATA_DIR: test-fixtures
|
||||
|
||||
generate-test-data:
|
||||
stage: generate
|
||||
image: node:20
|
||||
|
||||
before_script:
|
||||
- npm ci
|
||||
|
||||
script:
|
||||
- |
|
||||
node -e "
|
||||
import('./test-data-generator.js').then(async ({ CICDTestDataGenerator }) => {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: process.env.TEST_DATA_DIR,
|
||||
seed: process.env.CI_COMMIT_SHORT_SHA
|
||||
});
|
||||
await generator.generateAll({
|
||||
users: 100,
|
||||
posts: 500,
|
||||
apiMocks: 20,
|
||||
loadTestRequests: 10000
|
||||
});
|
||||
});
|
||||
"
|
||||
|
||||
artifacts:
|
||||
paths:
|
||||
- test-fixtures/
|
||||
expire_in: 1 week
|
||||
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- node_modules/
|
||||
|
||||
integration-tests:
|
||||
stage: test
|
||||
dependencies:
|
||||
- generate-test-data
|
||||
|
||||
script:
|
||||
- npm run test:integration
|
||||
|
||||
coverage: '/Coverage: \d+\.\d+%/'
|
||||
|
||||
performance-tests:
|
||||
stage: test
|
||||
dependencies:
|
||||
- generate-test-data
|
||||
|
||||
script:
|
||||
- npm run test:performance
|
||||
|
||||
artifacts:
|
||||
reports:
|
||||
performance: performance-report.json
|
||||
```
|
||||
|
||||
### Multi-Environment Testing
|
||||
|
||||
```yaml
|
||||
.generate-template:
|
||||
stage: generate
|
||||
image: node:20
|
||||
script:
|
||||
- |
|
||||
node -e "
|
||||
import('./test-data-generator.js').then(async ({ CICDTestDataGenerator }) => {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: './test-data',
|
||||
seed: process.env.CI_COMMIT_SHA
|
||||
});
|
||||
await generator.generateEnvironmentConfigs({
|
||||
environments: ['${ENVIRONMENT}']
|
||||
});
|
||||
});
|
||||
"
|
||||
artifacts:
|
||||
paths:
|
||||
- test-data/
|
||||
|
||||
generate-dev:
|
||||
extends: .generate-template
|
||||
variables:
|
||||
ENVIRONMENT: development
|
||||
|
||||
generate-staging:
|
||||
extends: .generate-template
|
||||
variables:
|
||||
ENVIRONMENT: staging
|
||||
|
||||
generate-production:
|
||||
extends: .generate-template
|
||||
variables:
|
||||
ENVIRONMENT: production
|
||||
only:
|
||||
- main
|
||||
```
|
||||
|
||||
## Jenkins Integration
|
||||
|
||||
### Example Jenkinsfile
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
GEMINI_API_KEY = credentials('gemini-api-key')
|
||||
TEST_DATA_DIR = "${WORKSPACE}/test-data"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Setup') {
|
||||
steps {
|
||||
nodejs(nodeJSInstallationName: 'Node 20') {
|
||||
sh 'npm ci'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Generate Test Data') {
|
||||
steps {
|
||||
nodejs(nodeJSInstallationName: 'Node 20') {
|
||||
script {
|
||||
sh """
|
||||
node -e "
|
||||
import('./test-data-generator.js').then(async ({ CICDTestDataGenerator }) => {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: process.env.TEST_DATA_DIR,
|
||||
seed: process.env.BUILD_NUMBER
|
||||
});
|
||||
await generator.generateAll();
|
||||
});
|
||||
"
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Run Tests') {
|
||||
parallel {
|
||||
stage('Unit Tests') {
|
||||
steps {
|
||||
sh 'npm run test:unit'
|
||||
}
|
||||
}
|
||||
stage('Integration Tests') {
|
||||
steps {
|
||||
sh 'npm run test:integration'
|
||||
}
|
||||
}
|
||||
stage('E2E Tests') {
|
||||
steps {
|
||||
sh 'npm run test:e2e'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: 'test-data/**', allowEmptyArchive: true
|
||||
junit 'test-results/**/*.xml'
|
||||
}
|
||||
success {
|
||||
echo 'Test data generation and tests completed successfully!'
|
||||
}
|
||||
failure {
|
||||
echo 'Test data generation or tests failed!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Multi-Branch Pipeline
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Generate Test Data') {
|
||||
steps {
|
||||
script {
|
||||
def dataTypes = ['fixtures', 'mocks', 'sessions', 'performance']
|
||||
def jobs = [:]
|
||||
|
||||
dataTypes.each { dataType ->
|
||||
jobs[dataType] = {
|
||||
node {
|
||||
nodejs(nodeJSInstallationName: 'Node 20') {
|
||||
sh """
|
||||
node -e "
|
||||
import('./test-data-generator.js').then(async ({ CICDTestDataGenerator }) => {
|
||||
const generator = new CICDTestDataGenerator();
|
||||
await generator.generate${dataType.capitalize()}();
|
||||
});
|
||||
"
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parallel jobs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Test Data Generation
|
||||
|
||||
```typescript
|
||||
import { CICDTestDataGenerator } from './test-data-generator';
|
||||
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: './custom-test-data',
|
||||
format: 'json',
|
||||
provider: 'gemini',
|
||||
seed: 'my-seed-123'
|
||||
});
|
||||
|
||||
// Generate specific datasets
|
||||
await generator.generateDatabaseFixtures({
|
||||
users: 50,
|
||||
posts: 200,
|
||||
comments: 500
|
||||
});
|
||||
|
||||
await generator.generateAPIMockResponses({
|
||||
endpoints: ['/api/users', '/api/products'],
|
||||
responsesPerEndpoint: 10,
|
||||
includeErrors: true
|
||||
});
|
||||
|
||||
await generator.generateLoadTestData({
|
||||
requestCount: 100000,
|
||||
concurrent: 50,
|
||||
duration: 30
|
||||
});
|
||||
```
|
||||
|
||||
### Pipeline Testing
|
||||
|
||||
```typescript
|
||||
import { PipelineTester } from './pipeline-testing';
|
||||
|
||||
const tester = new PipelineTester({
|
||||
outputDir: './pipeline-tests',
|
||||
seed: process.env.CI_COMMIT_SHA
|
||||
});
|
||||
|
||||
// Generate comprehensive test suite
|
||||
await tester.generateComprehensiveTestSuite({
|
||||
feature: 'authentication',
|
||||
testCases: 50,
|
||||
edgeCases: 30,
|
||||
performanceTests: 20000,
|
||||
securityTests: 40
|
||||
});
|
||||
|
||||
// Generate security-specific tests
|
||||
await tester.generateSecurityTestData({
|
||||
attackVectors: ['sql_injection', 'xss', 'csrf'],
|
||||
count: 50
|
||||
});
|
||||
|
||||
// Generate performance test data
|
||||
await tester.generatePerformanceTestData({
|
||||
scenario: 'high-load',
|
||||
dataPoints: 50000,
|
||||
concurrent: true
|
||||
});
|
||||
```
|
||||
|
||||
### Environment-Specific Configuration
|
||||
|
||||
```typescript
|
||||
import { CICDTestDataGenerator } from './test-data-generator';
|
||||
|
||||
const environment = process.env.NODE_ENV || 'development';
|
||||
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: `./test-data/${environment}`,
|
||||
seed: `${environment}-${Date.now()}`
|
||||
});
|
||||
|
||||
// Generate environment-specific configs
|
||||
await generator.generateEnvironmentConfigs({
|
||||
environments: [environment],
|
||||
includeSecrets: environment !== 'production'
|
||||
});
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Reproducible Seeds
|
||||
|
||||
Always use deterministic seeds in CI/CD to ensure reproducible test data:
|
||||
|
||||
```typescript
|
||||
const generator = new CICDTestDataGenerator({
|
||||
seed: process.env.CI_COMMIT_SHA || process.env.BUILD_NUMBER
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Cache Generated Data
|
||||
|
||||
Cache test data between pipeline runs to speed up execution:
|
||||
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: test-fixtures/
|
||||
key: test-data-${{ hashFiles('**/test-schema.json') }}
|
||||
|
||||
# GitLab CI
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- test-fixtures/
|
||||
```
|
||||
|
||||
### 3. Parallelize Generation
|
||||
|
||||
Generate different types of test data in parallel for faster pipelines:
|
||||
|
||||
```typescript
|
||||
await Promise.all([
|
||||
generator.generateDatabaseFixtures(),
|
||||
generator.generateAPIMockResponses(),
|
||||
generator.generateUserSessions(),
|
||||
generator.generateEnvironmentConfigs()
|
||||
]);
|
||||
```
|
||||
|
||||
### 4. Validate Generated Data
|
||||
|
||||
Always validate generated data before running tests:
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod';
|
||||
|
||||
const userSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
email: z.string().email(),
|
||||
username: z.string().min(3)
|
||||
});
|
||||
|
||||
const result = await generator.generateDatabaseFixtures();
|
||||
result.data.forEach(user => userSchema.parse(user));
|
||||
```
|
||||
|
||||
### 5. Clean Up Test Data
|
||||
|
||||
Clean up generated test data after pipeline completion:
|
||||
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: rm -rf test-fixtures/
|
||||
|
||||
# GitLab CI
|
||||
after_script:
|
||||
- rm -rf test-fixtures/
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Batch Generation
|
||||
|
||||
```typescript
|
||||
const batchOptions = Array.from({ length: 10 }, (_, i) => ({
|
||||
count: 1000,
|
||||
schema: mySchema,
|
||||
seed: `batch-${i}`
|
||||
}));
|
||||
|
||||
const results = await synth.generateBatch('structured', batchOptions, 5);
|
||||
```
|
||||
|
||||
### Streaming for Large Datasets
|
||||
|
||||
```typescript
|
||||
for await (const dataPoint of synth.generateStream('timeseries', {
|
||||
count: 1000000,
|
||||
interval: '1s'
|
||||
})) {
|
||||
await processDataPoint(dataPoint);
|
||||
}
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
|
||||
```typescript
|
||||
const generator = new CICDTestDataGenerator({
|
||||
cacheStrategy: 'memory',
|
||||
cacheTTL: 3600
|
||||
});
|
||||
|
||||
// Generate in chunks for large datasets
|
||||
const chunkSize = 10000;
|
||||
for (let i = 0; i < totalRecords; i += chunkSize) {
|
||||
const chunk = await generator.generateDatabaseFixtures({
|
||||
users: chunkSize,
|
||||
seed: `chunk-${i}`
|
||||
});
|
||||
await processChunk(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. API Rate Limiting
|
||||
|
||||
```typescript
|
||||
const generator = new CICDTestDataGenerator({
|
||||
maxRetries: 5,
|
||||
timeout: 60000
|
||||
});
|
||||
```
|
||||
|
||||
#### 2. Large Dataset Generation
|
||||
|
||||
```typescript
|
||||
// Use batch generation for large datasets
|
||||
const results = await synth.generateBatch('structured', batchOptions, 3);
|
||||
```
|
||||
|
||||
#### 3. Memory Issues
|
||||
|
||||
```typescript
|
||||
// Use streaming for very large datasets
|
||||
for await (const item of synth.generateStream('structured', options)) {
|
||||
await processItem(item);
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Complete GitHub Actions Workflow
|
||||
|
||||
```yaml
|
||||
name: CI/CD with Test Data Generation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
generate-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Cache test data
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: test-fixtures/
|
||||
key: test-data-${{ hashFiles('**/schema.json') }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
test-data-${{ hashFiles('**/schema.json') }}-
|
||||
|
||||
- name: Generate test data
|
||||
env:
|
||||
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
run: npm run generate:test-data
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test:unit
|
||||
|
||||
- name: Run integration tests
|
||||
run: npm run test:integration
|
||||
|
||||
- name: Run E2E tests
|
||||
run: npm run test:e2e
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: ./coverage/coverage-final.json
|
||||
|
||||
- name: Upload test data artifact
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-data-debug
|
||||
path: test-fixtures/
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [agentic-synth Documentation](../../README.md)
|
||||
- [GitHub Actions Documentation](https://docs.github.com/actions)
|
||||
- [GitLab CI Documentation](https://docs.gitlab.com/ee/ci/)
|
||||
- [Jenkins Documentation](https://www.jenkins.io/doc/)
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Open an issue on [GitHub](https://github.com/ruvnet/ruvector/issues)
|
||||
- Check the [main documentation](../../README.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT - See LICENSE file for details
|
||||
150
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.d.ts
vendored
Normal file
150
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.d.ts
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* CI/CD Pipeline Testing Examples
|
||||
*
|
||||
* This module demonstrates how to use agentic-synth for comprehensive
|
||||
* pipeline testing including:
|
||||
* - Dynamic test case generation
|
||||
* - Edge case scenario creation
|
||||
* - Performance test data at scale
|
||||
* - Security testing datasets
|
||||
* - Multi-stage pipeline data flows
|
||||
*
|
||||
* @module pipeline-testing
|
||||
*/
|
||||
import { GenerationResult } from '../../src/index.js';
|
||||
/**
|
||||
* Pipeline testing configuration
|
||||
*/
|
||||
export interface PipelineTestConfig {
|
||||
provider?: 'gemini' | 'openrouter';
|
||||
apiKey?: string;
|
||||
outputDir?: string;
|
||||
seed?: string | number;
|
||||
parallel?: boolean;
|
||||
concurrency?: number;
|
||||
}
|
||||
/**
|
||||
* Test case metadata
|
||||
*/
|
||||
export interface TestCase {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
priority: 'critical' | 'high' | 'medium' | 'low';
|
||||
data: any;
|
||||
expectedResult?: any;
|
||||
assertions?: string[];
|
||||
}
|
||||
/**
|
||||
* Pipeline testing orchestrator
|
||||
*/
|
||||
export declare class PipelineTester {
|
||||
private synth;
|
||||
private config;
|
||||
constructor(config?: PipelineTestConfig);
|
||||
/**
|
||||
* Generate dynamic test cases based on specifications
|
||||
*
|
||||
* Creates comprehensive test cases from high-level requirements,
|
||||
* including positive, negative, and edge cases.
|
||||
*/
|
||||
generateDynamicTestCases(options: {
|
||||
feature: string;
|
||||
scenarios?: string[];
|
||||
count?: number;
|
||||
includeBoundary?: boolean;
|
||||
includeNegative?: boolean;
|
||||
}): Promise<GenerationResult<TestCase>>;
|
||||
/**
|
||||
* Generate edge case scenarios
|
||||
*
|
||||
* Creates extreme and boundary condition test data to catch
|
||||
* potential bugs and edge cases.
|
||||
*/
|
||||
generateEdgeCases(options: {
|
||||
dataType: string;
|
||||
count?: number;
|
||||
extremes?: boolean;
|
||||
}): Promise<GenerationResult>;
|
||||
/**
|
||||
* Generate performance test data at scale
|
||||
*
|
||||
* Creates large-scale datasets for performance and stress testing
|
||||
* with realistic data distributions.
|
||||
*/
|
||||
generatePerformanceTestData(options: {
|
||||
scenario: string;
|
||||
dataPoints?: number;
|
||||
concurrent?: boolean;
|
||||
timeRange?: {
|
||||
start: Date;
|
||||
end: Date;
|
||||
};
|
||||
}): Promise<GenerationResult>;
|
||||
/**
|
||||
* Generate security testing datasets
|
||||
*
|
||||
* Creates security-focused test data including:
|
||||
* - SQL injection payloads
|
||||
* - XSS attack vectors
|
||||
* - Authentication bypass attempts
|
||||
* - CSRF tokens and scenarios
|
||||
* - Rate limiting tests
|
||||
*/
|
||||
generateSecurityTestData(options?: {
|
||||
attackVectors?: string[];
|
||||
count?: number;
|
||||
}): Promise<GenerationResult>;
|
||||
/**
|
||||
* Generate multi-stage pipeline test data
|
||||
*
|
||||
* Creates interconnected test data that flows through
|
||||
* multiple pipeline stages (build, test, deploy).
|
||||
*/
|
||||
generatePipelineData(options?: {
|
||||
stages?: string[];
|
||||
jobsPerStage?: number;
|
||||
}): Promise<Record<string, GenerationResult>>;
|
||||
/**
|
||||
* Generate regression test data
|
||||
*
|
||||
* Creates test data specifically for regression testing,
|
||||
* including historical bug scenarios and known issues.
|
||||
*/
|
||||
generateRegressionTests(options?: {
|
||||
bugCount?: number;
|
||||
includeFixed?: boolean;
|
||||
}): Promise<GenerationResult>;
|
||||
/**
|
||||
* Generate comprehensive test suite
|
||||
*
|
||||
* Combines all test data generation methods into a complete
|
||||
* test suite for CI/CD pipelines.
|
||||
*/
|
||||
generateComprehensiveTestSuite(options?: {
|
||||
feature: string;
|
||||
testCases?: number;
|
||||
edgeCases?: number;
|
||||
performanceTests?: number;
|
||||
securityTests?: number;
|
||||
}): Promise<void>;
|
||||
/**
|
||||
* Save result to file
|
||||
*/
|
||||
private saveResult;
|
||||
}
|
||||
/**
|
||||
* Example: GitHub Actions Integration
|
||||
*/
|
||||
declare function githubActionsPipelineTest(): Promise<void>;
|
||||
/**
|
||||
* Example: GitLab CI Integration
|
||||
*/
|
||||
declare function gitlabCIPipelineTest(): Promise<void>;
|
||||
/**
|
||||
* Example: Jenkins Pipeline Integration
|
||||
*/
|
||||
declare function jenkinsPipelineTest(): Promise<void>;
|
||||
export { githubActionsPipelineTest, gitlabCIPipelineTest, jenkinsPipelineTest };
|
||||
//# sourceMappingURL=pipeline-testing.d.ts.map
|
||||
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"pipeline-testing.d.ts","sourceRoot":"","sources":["pipeline-testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA6B,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAI7F;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,IAAI,EAAE,GAAG,CAAC;IACV,cAAc,CAAC,EAAE,GAAG,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,GAAE,kBAAuB;IAkB3C;;;;;OAKG;IACG,wBAAwB,CAAC,OAAO,EAAE;QACtC,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,GAAG,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAgFvC;;;;;OAKG;IACG,iBAAiB,CAAC,OAAO,EAAE;QAC/B,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyG7B;;;;;OAKG;IACG,2BAA2B,CAAC,OAAO,EAAE;QACzC,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,GAAG,EAAE,IAAI,CAAA;SAAE,CAAC;KACxC,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuC7B;;;;;;;;;OASG;IACG,wBAAwB,CAAC,OAAO,GAAE;QACtC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,KAAK,CAAC,EAAE,MAAM,CAAC;KACX,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiElC;;;;;OAKG;IACG,oBAAoB,CAAC,OAAO,GAAE;QAClC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IA4ElD;;;;;OAKG;IACG,uBAAuB,CAAC,OAAO,GAAE;QACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,OAAO,CAAC;KACnB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4DlC;;;;;OAKG;IACG,8BAA8B,CAAC,OAAO,GAAE;QAC5C,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;KACC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC1C;;OAEG;YACW,UAAU;CAczB;AAED;;GAEG;AACH,iBAAe,yBAAyB,kBAavC;AAED;;GAEG;AACH,iBAAe,oBAAoB,kBAUlC;AAED;;GAEG;AACH,iBAAe,mBAAmB,kBASjC;AAGD,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACpB,CAAC"}
|
||||
583
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.js
vendored
Normal file
583
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.js
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
"use strict";
|
||||
/**
|
||||
* CI/CD Pipeline Testing Examples
|
||||
*
|
||||
* This module demonstrates how to use agentic-synth for comprehensive
|
||||
* pipeline testing including:
|
||||
* - Dynamic test case generation
|
||||
* - Edge case scenario creation
|
||||
* - Performance test data at scale
|
||||
* - Security testing datasets
|
||||
* - Multi-stage pipeline data flows
|
||||
*
|
||||
* @module pipeline-testing
|
||||
*/
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PipelineTester = void 0;
|
||||
exports.githubActionsPipelineTest = githubActionsPipelineTest;
|
||||
exports.gitlabCIPipelineTest = gitlabCIPipelineTest;
|
||||
exports.jenkinsPipelineTest = jenkinsPipelineTest;
|
||||
const index_js_1 = require("../../src/index.js");
|
||||
const fs = __importStar(require("fs/promises"));
|
||||
const path = __importStar(require("path"));
|
||||
/**
|
||||
* Pipeline testing orchestrator
|
||||
*/
|
||||
class PipelineTester {
|
||||
constructor(config = {}) {
|
||||
this.config = {
|
||||
provider: config.provider || 'gemini',
|
||||
apiKey: config.apiKey || process.env.GEMINI_API_KEY,
|
||||
outputDir: config.outputDir || './pipeline-tests',
|
||||
seed: config.seed || Date.now(),
|
||||
parallel: config.parallel !== false,
|
||||
concurrency: config.concurrency || 5
|
||||
};
|
||||
this.synth = (0, index_js_1.createSynth)({
|
||||
provider: this.config.provider,
|
||||
apiKey: this.config.apiKey,
|
||||
cacheStrategy: 'memory',
|
||||
maxRetries: 3
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Generate dynamic test cases based on specifications
|
||||
*
|
||||
* Creates comprehensive test cases from high-level requirements,
|
||||
* including positive, negative, and edge cases.
|
||||
*/
|
||||
async generateDynamicTestCases(options) {
|
||||
const { feature, scenarios = ['happy_path', 'error_handling', 'edge_cases'], count = 20, includeBoundary = true, includeNegative = true } = options;
|
||||
console.log(`Generating test cases for feature: ${feature}...`);
|
||||
try {
|
||||
const testCaseSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
name: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
category: {
|
||||
type: 'enum',
|
||||
values: ['unit', 'integration', 'e2e', 'performance', 'security'],
|
||||
required: true
|
||||
},
|
||||
scenario: {
|
||||
type: 'enum',
|
||||
values: scenarios,
|
||||
required: true
|
||||
},
|
||||
priority: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
testType: {
|
||||
type: 'enum',
|
||||
values: ['positive', 'negative', 'boundary', 'edge'],
|
||||
required: true
|
||||
},
|
||||
input: { type: 'object', required: true },
|
||||
expectedOutput: { type: 'object', required: true },
|
||||
preconditions: { type: 'array', items: { type: 'string' } },
|
||||
steps: { type: 'array', items: { type: 'string' } },
|
||||
assertions: { type: 'array', items: { type: 'string' } },
|
||||
tags: { type: 'array', items: { type: 'string' } },
|
||||
timeout: { type: 'integer', min: 1000, max: 60000, required: true },
|
||||
retryable: { type: 'boolean', required: true },
|
||||
flaky: { type: 'boolean', required: true },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
author: { type: 'string' },
|
||||
createdAt: { type: 'timestamp' },
|
||||
jiraTicket: { type: 'string' },
|
||||
relatedTests: { type: 'array', items: { type: 'string' } }
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = await this.synth.generateStructured({
|
||||
count,
|
||||
schema: testCaseSchema,
|
||||
seed: this.config.seed,
|
||||
constraints: {
|
||||
feature,
|
||||
includeBoundary,
|
||||
includeNegative
|
||||
}
|
||||
});
|
||||
await this.saveResult('test-cases', result);
|
||||
console.log('✅ Test cases generated successfully');
|
||||
console.log(` Total cases: ${result.metadata.count}`);
|
||||
console.log(` Duration: ${result.metadata.duration}ms`);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate test cases:', error);
|
||||
throw new index_js_1.SynthError('Test case generation failed', 'TEST_CASE_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate edge case scenarios
|
||||
*
|
||||
* Creates extreme and boundary condition test data to catch
|
||||
* potential bugs and edge cases.
|
||||
*/
|
||||
async generateEdgeCases(options) {
|
||||
const { dataType, count = 30, extremes = true } = options;
|
||||
console.log(`Generating edge cases for ${dataType}...`);
|
||||
try {
|
||||
// Define schemas for different edge case types
|
||||
const edgeCaseSchemas = {
|
||||
string: {
|
||||
type: 'string',
|
||||
variants: [
|
||||
'empty',
|
||||
'very_long',
|
||||
'special_characters',
|
||||
'unicode',
|
||||
'sql_injection',
|
||||
'xss_payload',
|
||||
'null_bytes',
|
||||
'whitespace_only'
|
||||
]
|
||||
},
|
||||
number: {
|
||||
type: 'number',
|
||||
variants: [
|
||||
'zero',
|
||||
'negative',
|
||||
'very_large',
|
||||
'very_small',
|
||||
'float_precision',
|
||||
'infinity',
|
||||
'nan',
|
||||
'negative_zero'
|
||||
]
|
||||
},
|
||||
array: {
|
||||
type: 'array',
|
||||
variants: [
|
||||
'empty',
|
||||
'single_element',
|
||||
'very_large',
|
||||
'nested_deeply',
|
||||
'mixed_types',
|
||||
'circular_reference'
|
||||
]
|
||||
},
|
||||
object: {
|
||||
type: 'object',
|
||||
variants: [
|
||||
'empty',
|
||||
'null_values',
|
||||
'undefined_values',
|
||||
'nested_deeply',
|
||||
'large_keys',
|
||||
'special_key_names'
|
||||
]
|
||||
}
|
||||
};
|
||||
const schema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
edgeCase: { type: 'string', required: true },
|
||||
variant: { type: 'string', required: true },
|
||||
value: { type: 'any', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
expectedBehavior: { type: 'string', required: true },
|
||||
category: {
|
||||
type: 'enum',
|
||||
values: ['boundary', 'extreme', 'invalid', 'malformed', 'security'],
|
||||
required: true
|
||||
},
|
||||
severity: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
testData: { type: 'object', required: true }
|
||||
};
|
||||
const result = await this.synth.generateStructured({
|
||||
count,
|
||||
schema,
|
||||
seed: this.config.seed,
|
||||
constraints: {
|
||||
dataType,
|
||||
extremes,
|
||||
variants: edgeCaseSchemas[dataType]?.variants || []
|
||||
}
|
||||
});
|
||||
await this.saveResult('edge-cases', result);
|
||||
console.log('✅ Edge cases generated successfully');
|
||||
console.log(` Total cases: ${result.metadata.count}`);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate edge cases:', error);
|
||||
throw new index_js_1.SynthError('Edge case generation failed', 'EDGE_CASE_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate performance test data at scale
|
||||
*
|
||||
* Creates large-scale datasets for performance and stress testing
|
||||
* with realistic data distributions.
|
||||
*/
|
||||
async generatePerformanceTestData(options) {
|
||||
const { scenario, dataPoints = 100000, concurrent = true, timeRange = {
|
||||
start: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
|
||||
end: new Date()
|
||||
} } = options;
|
||||
console.log(`Generating performance test data for ${scenario}...`);
|
||||
try {
|
||||
// Generate time-series data for realistic performance testing
|
||||
const result = await this.synth.generateTimeSeries({
|
||||
count: dataPoints,
|
||||
startDate: timeRange.start,
|
||||
endDate: timeRange.end,
|
||||
interval: '1m',
|
||||
metrics: ['requests', 'latency', 'errors', 'cpu', 'memory'],
|
||||
trend: 'random',
|
||||
seasonality: true,
|
||||
noise: 0.2
|
||||
});
|
||||
await this.saveResult(`performance-${scenario}`, result);
|
||||
console.log('✅ Performance test data generated successfully');
|
||||
console.log(` Data points: ${result.metadata.count}`);
|
||||
console.log(` Duration: ${result.metadata.duration}ms`);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate performance test data:', error);
|
||||
throw new index_js_1.SynthError('Performance data generation failed', 'PERF_DATA_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate security testing datasets
|
||||
*
|
||||
* Creates security-focused test data including:
|
||||
* - SQL injection payloads
|
||||
* - XSS attack vectors
|
||||
* - Authentication bypass attempts
|
||||
* - CSRF tokens and scenarios
|
||||
* - Rate limiting tests
|
||||
*/
|
||||
async generateSecurityTestData(options = {}) {
|
||||
const { attackVectors = ['sql_injection', 'xss', 'csrf', 'auth_bypass', 'path_traversal'], count = 50 } = options;
|
||||
console.log('Generating security test data...');
|
||||
try {
|
||||
const securityTestSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
attackType: {
|
||||
type: 'enum',
|
||||
values: attackVectors,
|
||||
required: true
|
||||
},
|
||||
severity: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
payload: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
targetEndpoint: { type: 'string', required: true },
|
||||
method: { type: 'enum', values: ['GET', 'POST', 'PUT', 'DELETE'], required: true },
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Content-Type': { type: 'string' },
|
||||
'Authorization': { type: 'string' },
|
||||
'X-CSRF-Token': { type: 'string' }
|
||||
}
|
||||
},
|
||||
expectedResponse: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
statusCode: { type: 'integer' },
|
||||
blocked: { type: 'boolean' },
|
||||
sanitized: { type: 'boolean' }
|
||||
}
|
||||
},
|
||||
mitigation: { type: 'string', required: true },
|
||||
cvssScore: { type: 'decimal', min: 0, max: 10, required: false },
|
||||
references: { type: 'array', items: { type: 'url' } }
|
||||
};
|
||||
const result = await this.synth.generateStructured({
|
||||
count,
|
||||
schema: securityTestSchema,
|
||||
seed: this.config.seed
|
||||
});
|
||||
await this.saveResult('security-tests', result);
|
||||
console.log('✅ Security test data generated successfully');
|
||||
console.log(` Test cases: ${result.metadata.count}`);
|
||||
console.log(` Attack vectors: ${attackVectors.join(', ')}`);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate security test data:', error);
|
||||
throw new index_js_1.SynthError('Security test generation failed', 'SECURITY_TEST_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate multi-stage pipeline test data
|
||||
*
|
||||
* Creates interconnected test data that flows through
|
||||
* multiple pipeline stages (build, test, deploy).
|
||||
*/
|
||||
async generatePipelineData(options = {}) {
|
||||
const { stages = ['build', 'test', 'deploy'], jobsPerStage = 10 } = options;
|
||||
console.log('Generating multi-stage pipeline data...');
|
||||
try {
|
||||
const results = {};
|
||||
for (const stage of stages) {
|
||||
const stageSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
stage: { type: 'string', required: true, default: stage },
|
||||
jobName: { type: 'string', required: true },
|
||||
status: {
|
||||
type: 'enum',
|
||||
values: ['pending', 'running', 'success', 'failed', 'cancelled', 'skipped'],
|
||||
required: true
|
||||
},
|
||||
startedAt: { type: 'timestamp', required: true },
|
||||
completedAt: { type: 'timestamp', required: false },
|
||||
duration: { type: 'integer', min: 0, required: false },
|
||||
exitCode: { type: 'integer', required: false },
|
||||
logs: { type: 'text', required: false },
|
||||
artifacts: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
path: { type: 'string' },
|
||||
size: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
},
|
||||
dependencies: { type: 'array', items: { type: 'string' } },
|
||||
environment: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
variables: { type: 'object' }
|
||||
}
|
||||
},
|
||||
metrics: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cpuUsage: { type: 'decimal' },
|
||||
memoryUsage: { type: 'decimal' },
|
||||
diskIO: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = await this.synth.generateStructured({
|
||||
count: jobsPerStage,
|
||||
schema: stageSchema,
|
||||
seed: `${this.config.seed}-${stage}`
|
||||
});
|
||||
results[stage] = result;
|
||||
await this.saveResult(`pipeline-${stage}`, result);
|
||||
}
|
||||
console.log('✅ Pipeline data generated successfully');
|
||||
console.log(` Stages: ${stages.join(' → ')}`);
|
||||
console.log(` Jobs per stage: ${jobsPerStage}`);
|
||||
return results;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate pipeline data:', error);
|
||||
throw new index_js_1.SynthError('Pipeline data generation failed', 'PIPELINE_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate regression test data
|
||||
*
|
||||
* Creates test data specifically for regression testing,
|
||||
* including historical bug scenarios and known issues.
|
||||
*/
|
||||
async generateRegressionTests(options = {}) {
|
||||
const { bugCount = 25, includeFixed = true } = options;
|
||||
console.log('Generating regression test data...');
|
||||
try {
|
||||
const regressionSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
bugId: { type: 'string', required: true },
|
||||
title: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
severity: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
status: {
|
||||
type: 'enum',
|
||||
values: ['open', 'fixed', 'verified', 'wont_fix'],
|
||||
required: true
|
||||
},
|
||||
reproducibleSteps: { type: 'array', items: { type: 'string' } },
|
||||
testData: { type: 'object', required: true },
|
||||
expectedBehavior: { type: 'text', required: true },
|
||||
actualBehavior: { type: 'text', required: true },
|
||||
fixedInVersion: { type: 'string', required: false },
|
||||
relatedBugs: { type: 'array', items: { type: 'string' } },
|
||||
affectedVersions: { type: 'array', items: { type: 'string' } },
|
||||
testCoverage: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
unitTest: { type: 'boolean' },
|
||||
integrationTest: { type: 'boolean' },
|
||||
e2eTest: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = await this.synth.generateStructured({
|
||||
count: bugCount,
|
||||
schema: regressionSchema,
|
||||
seed: this.config.seed,
|
||||
constraints: { includeFixed }
|
||||
});
|
||||
await this.saveResult('regression-tests', result);
|
||||
console.log('✅ Regression test data generated successfully');
|
||||
console.log(` Bug scenarios: ${result.metadata.count}`);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate regression test data:', error);
|
||||
throw new index_js_1.SynthError('Regression test generation failed', 'REGRESSION_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate comprehensive test suite
|
||||
*
|
||||
* Combines all test data generation methods into a complete
|
||||
* test suite for CI/CD pipelines.
|
||||
*/
|
||||
async generateComprehensiveTestSuite(options = { feature: 'default' }) {
|
||||
console.log('🚀 Generating comprehensive test suite...\n');
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
// Run all generators in parallel for maximum speed
|
||||
await Promise.all([
|
||||
this.generateDynamicTestCases({
|
||||
feature: options.feature,
|
||||
count: options.testCases || 30
|
||||
}),
|
||||
this.generateEdgeCases({
|
||||
dataType: 'string',
|
||||
count: options.edgeCases || 20
|
||||
}),
|
||||
this.generatePerformanceTestData({
|
||||
scenario: options.feature,
|
||||
dataPoints: options.performanceTests || 10000
|
||||
}),
|
||||
this.generateSecurityTestData({
|
||||
count: options.securityTests || 30
|
||||
}),
|
||||
this.generatePipelineData(),
|
||||
this.generateRegressionTests()
|
||||
]);
|
||||
const duration = Date.now() - startTime;
|
||||
console.log(`\n✅ Comprehensive test suite generated in ${duration}ms`);
|
||||
console.log(`📁 Output directory: ${path.resolve(this.config.outputDir)}`);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('\n❌ Failed to generate test suite:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Save result to file
|
||||
*/
|
||||
async saveResult(name, result) {
|
||||
try {
|
||||
await fs.mkdir(this.config.outputDir, { recursive: true });
|
||||
const filepath = path.join(this.config.outputDir, `${name}.json`);
|
||||
await fs.writeFile(filepath, JSON.stringify(result.data, null, 2), 'utf-8');
|
||||
const metadataPath = path.join(this.config.outputDir, `${name}.metadata.json`);
|
||||
await fs.writeFile(metadataPath, JSON.stringify(result.metadata, null, 2), 'utf-8');
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to save ${name}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.PipelineTester = PipelineTester;
|
||||
/**
|
||||
* Example: GitHub Actions Integration
|
||||
*/
|
||||
async function githubActionsPipelineTest() {
|
||||
const tester = new PipelineTester({
|
||||
outputDir: process.env.GITHUB_WORKSPACE + '/test-data',
|
||||
seed: process.env.GITHUB_SHA
|
||||
});
|
||||
await tester.generateComprehensiveTestSuite({
|
||||
feature: process.env.FEATURE_NAME || 'default',
|
||||
testCases: 50,
|
||||
edgeCases: 30,
|
||||
performanceTests: 20000,
|
||||
securityTests: 40
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Example: GitLab CI Integration
|
||||
*/
|
||||
async function gitlabCIPipelineTest() {
|
||||
const tester = new PipelineTester({
|
||||
outputDir: process.env.CI_PROJECT_DIR + '/test-data',
|
||||
seed: process.env.CI_COMMIT_SHORT_SHA
|
||||
});
|
||||
await tester.generatePipelineData({
|
||||
stages: ['build', 'test', 'security', 'deploy'],
|
||||
jobsPerStage: 15
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Example: Jenkins Pipeline Integration
|
||||
*/
|
||||
async function jenkinsPipelineTest() {
|
||||
const tester = new PipelineTester({
|
||||
outputDir: process.env.WORKSPACE + '/test-data',
|
||||
seed: process.env.BUILD_NUMBER
|
||||
});
|
||||
await tester.generateComprehensiveTestSuite({
|
||||
feature: process.env.JOB_NAME || 'default'
|
||||
});
|
||||
}
|
||||
// Run if called directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
const tester = new PipelineTester();
|
||||
tester.generateComprehensiveTestSuite({ feature: 'example' }).catch(console.error);
|
||||
}
|
||||
//# sourceMappingURL=pipeline-testing.js.map
|
||||
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
685
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.ts
vendored
Normal file
685
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/pipeline-testing.ts
vendored
Normal file
@@ -0,0 +1,685 @@
|
||||
/**
|
||||
* CI/CD Pipeline Testing Examples
|
||||
*
|
||||
* This module demonstrates how to use agentic-synth for comprehensive
|
||||
* pipeline testing including:
|
||||
* - Dynamic test case generation
|
||||
* - Edge case scenario creation
|
||||
* - Performance test data at scale
|
||||
* - Security testing datasets
|
||||
* - Multi-stage pipeline data flows
|
||||
*
|
||||
* @module pipeline-testing
|
||||
*/
|
||||
|
||||
import { AgenticSynth, createSynth, GenerationResult, SynthError } from '../../src/index.js';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* Pipeline testing configuration
|
||||
*/
|
||||
export interface PipelineTestConfig {
|
||||
provider?: 'gemini' | 'openrouter';
|
||||
apiKey?: string;
|
||||
outputDir?: string;
|
||||
seed?: string | number;
|
||||
parallel?: boolean;
|
||||
concurrency?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case metadata
|
||||
*/
|
||||
export interface TestCase {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
priority: 'critical' | 'high' | 'medium' | 'low';
|
||||
data: any;
|
||||
expectedResult?: any;
|
||||
assertions?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Pipeline testing orchestrator
|
||||
*/
|
||||
export class PipelineTester {
|
||||
private synth: AgenticSynth;
|
||||
private config: PipelineTestConfig;
|
||||
|
||||
constructor(config: PipelineTestConfig = {}) {
|
||||
this.config = {
|
||||
provider: config.provider || 'gemini',
|
||||
apiKey: config.apiKey || process.env.GEMINI_API_KEY,
|
||||
outputDir: config.outputDir || './pipeline-tests',
|
||||
seed: config.seed || Date.now(),
|
||||
parallel: config.parallel !== false,
|
||||
concurrency: config.concurrency || 5
|
||||
};
|
||||
|
||||
this.synth = createSynth({
|
||||
provider: this.config.provider,
|
||||
apiKey: this.config.apiKey,
|
||||
cacheStrategy: 'memory',
|
||||
maxRetries: 3
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate dynamic test cases based on specifications
|
||||
*
|
||||
* Creates comprehensive test cases from high-level requirements,
|
||||
* including positive, negative, and edge cases.
|
||||
*/
|
||||
async generateDynamicTestCases(options: {
|
||||
feature: string;
|
||||
scenarios?: string[];
|
||||
count?: number;
|
||||
includeBoundary?: boolean;
|
||||
includeNegative?: boolean;
|
||||
}): Promise<GenerationResult<TestCase>> {
|
||||
const {
|
||||
feature,
|
||||
scenarios = ['happy_path', 'error_handling', 'edge_cases'],
|
||||
count = 20,
|
||||
includeBoundary = true,
|
||||
includeNegative = true
|
||||
} = options;
|
||||
|
||||
console.log(`Generating test cases for feature: ${feature}...`);
|
||||
|
||||
try {
|
||||
const testCaseSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
name: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
category: {
|
||||
type: 'enum',
|
||||
values: ['unit', 'integration', 'e2e', 'performance', 'security'],
|
||||
required: true
|
||||
},
|
||||
scenario: {
|
||||
type: 'enum',
|
||||
values: scenarios,
|
||||
required: true
|
||||
},
|
||||
priority: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
testType: {
|
||||
type: 'enum',
|
||||
values: ['positive', 'negative', 'boundary', 'edge'],
|
||||
required: true
|
||||
},
|
||||
input: { type: 'object', required: true },
|
||||
expectedOutput: { type: 'object', required: true },
|
||||
preconditions: { type: 'array', items: { type: 'string' } },
|
||||
steps: { type: 'array', items: { type: 'string' } },
|
||||
assertions: { type: 'array', items: { type: 'string' } },
|
||||
tags: { type: 'array', items: { type: 'string' } },
|
||||
timeout: { type: 'integer', min: 1000, max: 60000, required: true },
|
||||
retryable: { type: 'boolean', required: true },
|
||||
flaky: { type: 'boolean', required: true },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
author: { type: 'string' },
|
||||
createdAt: { type: 'timestamp' },
|
||||
jiraTicket: { type: 'string' },
|
||||
relatedTests: { type: 'array', items: { type: 'string' } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = await this.synth.generateStructured({
|
||||
count,
|
||||
schema: testCaseSchema,
|
||||
seed: this.config.seed,
|
||||
constraints: {
|
||||
feature,
|
||||
includeBoundary,
|
||||
includeNegative
|
||||
}
|
||||
});
|
||||
|
||||
await this.saveResult('test-cases', result);
|
||||
|
||||
console.log('✅ Test cases generated successfully');
|
||||
console.log(` Total cases: ${result.metadata.count}`);
|
||||
console.log(` Duration: ${result.metadata.duration}ms`);
|
||||
|
||||
return result as GenerationResult<TestCase>;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate test cases:', error);
|
||||
throw new SynthError('Test case generation failed', 'TEST_CASE_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate edge case scenarios
|
||||
*
|
||||
* Creates extreme and boundary condition test data to catch
|
||||
* potential bugs and edge cases.
|
||||
*/
|
||||
async generateEdgeCases(options: {
|
||||
dataType: string;
|
||||
count?: number;
|
||||
extremes?: boolean;
|
||||
}): Promise<GenerationResult> {
|
||||
const {
|
||||
dataType,
|
||||
count = 30,
|
||||
extremes = true
|
||||
} = options;
|
||||
|
||||
console.log(`Generating edge cases for ${dataType}...`);
|
||||
|
||||
try {
|
||||
// Define schemas for different edge case types
|
||||
const edgeCaseSchemas: Record<string, any> = {
|
||||
string: {
|
||||
type: 'string',
|
||||
variants: [
|
||||
'empty',
|
||||
'very_long',
|
||||
'special_characters',
|
||||
'unicode',
|
||||
'sql_injection',
|
||||
'xss_payload',
|
||||
'null_bytes',
|
||||
'whitespace_only'
|
||||
]
|
||||
},
|
||||
number: {
|
||||
type: 'number',
|
||||
variants: [
|
||||
'zero',
|
||||
'negative',
|
||||
'very_large',
|
||||
'very_small',
|
||||
'float_precision',
|
||||
'infinity',
|
||||
'nan',
|
||||
'negative_zero'
|
||||
]
|
||||
},
|
||||
array: {
|
||||
type: 'array',
|
||||
variants: [
|
||||
'empty',
|
||||
'single_element',
|
||||
'very_large',
|
||||
'nested_deeply',
|
||||
'mixed_types',
|
||||
'circular_reference'
|
||||
]
|
||||
},
|
||||
object: {
|
||||
type: 'object',
|
||||
variants: [
|
||||
'empty',
|
||||
'null_values',
|
||||
'undefined_values',
|
||||
'nested_deeply',
|
||||
'large_keys',
|
||||
'special_key_names'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const schema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
edgeCase: { type: 'string', required: true },
|
||||
variant: { type: 'string', required: true },
|
||||
value: { type: 'any', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
expectedBehavior: { type: 'string', required: true },
|
||||
category: {
|
||||
type: 'enum',
|
||||
values: ['boundary', 'extreme', 'invalid', 'malformed', 'security'],
|
||||
required: true
|
||||
},
|
||||
severity: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
testData: { type: 'object', required: true }
|
||||
};
|
||||
|
||||
const result = await this.synth.generateStructured({
|
||||
count,
|
||||
schema,
|
||||
seed: this.config.seed,
|
||||
constraints: {
|
||||
dataType,
|
||||
extremes,
|
||||
variants: edgeCaseSchemas[dataType]?.variants || []
|
||||
}
|
||||
});
|
||||
|
||||
await this.saveResult('edge-cases', result);
|
||||
|
||||
console.log('✅ Edge cases generated successfully');
|
||||
console.log(` Total cases: ${result.metadata.count}`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate edge cases:', error);
|
||||
throw new SynthError('Edge case generation failed', 'EDGE_CASE_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate performance test data at scale
|
||||
*
|
||||
* Creates large-scale datasets for performance and stress testing
|
||||
* with realistic data distributions.
|
||||
*/
|
||||
async generatePerformanceTestData(options: {
|
||||
scenario: string;
|
||||
dataPoints?: number;
|
||||
concurrent?: boolean;
|
||||
timeRange?: { start: Date; end: Date };
|
||||
}): Promise<GenerationResult> {
|
||||
const {
|
||||
scenario,
|
||||
dataPoints = 100000,
|
||||
concurrent = true,
|
||||
timeRange = {
|
||||
start: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
|
||||
end: new Date()
|
||||
}
|
||||
} = options;
|
||||
|
||||
console.log(`Generating performance test data for ${scenario}...`);
|
||||
|
||||
try {
|
||||
// Generate time-series data for realistic performance testing
|
||||
const result = await this.synth.generateTimeSeries({
|
||||
count: dataPoints,
|
||||
startDate: timeRange.start,
|
||||
endDate: timeRange.end,
|
||||
interval: '1m',
|
||||
metrics: ['requests', 'latency', 'errors', 'cpu', 'memory'],
|
||||
trend: 'random',
|
||||
seasonality: true,
|
||||
noise: 0.2
|
||||
});
|
||||
|
||||
await this.saveResult(`performance-${scenario}`, result);
|
||||
|
||||
console.log('✅ Performance test data generated successfully');
|
||||
console.log(` Data points: ${result.metadata.count}`);
|
||||
console.log(` Duration: ${result.metadata.duration}ms`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate performance test data:', error);
|
||||
throw new SynthError('Performance data generation failed', 'PERF_DATA_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate security testing datasets
|
||||
*
|
||||
* Creates security-focused test data including:
|
||||
* - SQL injection payloads
|
||||
* - XSS attack vectors
|
||||
* - Authentication bypass attempts
|
||||
* - CSRF tokens and scenarios
|
||||
* - Rate limiting tests
|
||||
*/
|
||||
async generateSecurityTestData(options: {
|
||||
attackVectors?: string[];
|
||||
count?: number;
|
||||
} = {}): Promise<GenerationResult> {
|
||||
const {
|
||||
attackVectors = ['sql_injection', 'xss', 'csrf', 'auth_bypass', 'path_traversal'],
|
||||
count = 50
|
||||
} = options;
|
||||
|
||||
console.log('Generating security test data...');
|
||||
|
||||
try {
|
||||
const securityTestSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
attackType: {
|
||||
type: 'enum',
|
||||
values: attackVectors,
|
||||
required: true
|
||||
},
|
||||
severity: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
payload: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
targetEndpoint: { type: 'string', required: true },
|
||||
method: { type: 'enum', values: ['GET', 'POST', 'PUT', 'DELETE'], required: true },
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Content-Type': { type: 'string' },
|
||||
'Authorization': { type: 'string' },
|
||||
'X-CSRF-Token': { type: 'string' }
|
||||
}
|
||||
},
|
||||
expectedResponse: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
statusCode: { type: 'integer' },
|
||||
blocked: { type: 'boolean' },
|
||||
sanitized: { type: 'boolean' }
|
||||
}
|
||||
},
|
||||
mitigation: { type: 'string', required: true },
|
||||
cvssScore: { type: 'decimal', min: 0, max: 10, required: false },
|
||||
references: { type: 'array', items: { type: 'url' } }
|
||||
};
|
||||
|
||||
const result = await this.synth.generateStructured({
|
||||
count,
|
||||
schema: securityTestSchema,
|
||||
seed: this.config.seed
|
||||
});
|
||||
|
||||
await this.saveResult('security-tests', result);
|
||||
|
||||
console.log('✅ Security test data generated successfully');
|
||||
console.log(` Test cases: ${result.metadata.count}`);
|
||||
console.log(` Attack vectors: ${attackVectors.join(', ')}`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate security test data:', error);
|
||||
throw new SynthError('Security test generation failed', 'SECURITY_TEST_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate multi-stage pipeline test data
|
||||
*
|
||||
* Creates interconnected test data that flows through
|
||||
* multiple pipeline stages (build, test, deploy).
|
||||
*/
|
||||
async generatePipelineData(options: {
|
||||
stages?: string[];
|
||||
jobsPerStage?: number;
|
||||
} = {}): Promise<Record<string, GenerationResult>> {
|
||||
const {
|
||||
stages = ['build', 'test', 'deploy'],
|
||||
jobsPerStage = 10
|
||||
} = options;
|
||||
|
||||
console.log('Generating multi-stage pipeline data...');
|
||||
|
||||
try {
|
||||
const results: Record<string, GenerationResult> = {};
|
||||
|
||||
for (const stage of stages) {
|
||||
const stageSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
stage: { type: 'string', required: true, default: stage },
|
||||
jobName: { type: 'string', required: true },
|
||||
status: {
|
||||
type: 'enum',
|
||||
values: ['pending', 'running', 'success', 'failed', 'cancelled', 'skipped'],
|
||||
required: true
|
||||
},
|
||||
startedAt: { type: 'timestamp', required: true },
|
||||
completedAt: { type: 'timestamp', required: false },
|
||||
duration: { type: 'integer', min: 0, required: false },
|
||||
exitCode: { type: 'integer', required: false },
|
||||
logs: { type: 'text', required: false },
|
||||
artifacts: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
path: { type: 'string' },
|
||||
size: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
},
|
||||
dependencies: { type: 'array', items: { type: 'string' } },
|
||||
environment: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
variables: { type: 'object' }
|
||||
}
|
||||
},
|
||||
metrics: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cpuUsage: { type: 'decimal' },
|
||||
memoryUsage: { type: 'decimal' },
|
||||
diskIO: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = await this.synth.generateStructured({
|
||||
count: jobsPerStage,
|
||||
schema: stageSchema,
|
||||
seed: `${this.config.seed}-${stage}`
|
||||
});
|
||||
|
||||
results[stage] = result;
|
||||
await this.saveResult(`pipeline-${stage}`, result);
|
||||
}
|
||||
|
||||
console.log('✅ Pipeline data generated successfully');
|
||||
console.log(` Stages: ${stages.join(' → ')}`);
|
||||
console.log(` Jobs per stage: ${jobsPerStage}`);
|
||||
|
||||
return results;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate pipeline data:', error);
|
||||
throw new SynthError('Pipeline data generation failed', 'PIPELINE_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate regression test data
|
||||
*
|
||||
* Creates test data specifically for regression testing,
|
||||
* including historical bug scenarios and known issues.
|
||||
*/
|
||||
async generateRegressionTests(options: {
|
||||
bugCount?: number;
|
||||
includeFixed?: boolean;
|
||||
} = {}): Promise<GenerationResult> {
|
||||
const {
|
||||
bugCount = 25,
|
||||
includeFixed = true
|
||||
} = options;
|
||||
|
||||
console.log('Generating regression test data...');
|
||||
|
||||
try {
|
||||
const regressionSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
bugId: { type: 'string', required: true },
|
||||
title: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
severity: {
|
||||
type: 'enum',
|
||||
values: ['critical', 'high', 'medium', 'low'],
|
||||
required: true
|
||||
},
|
||||
status: {
|
||||
type: 'enum',
|
||||
values: ['open', 'fixed', 'verified', 'wont_fix'],
|
||||
required: true
|
||||
},
|
||||
reproducibleSteps: { type: 'array', items: { type: 'string' } },
|
||||
testData: { type: 'object', required: true },
|
||||
expectedBehavior: { type: 'text', required: true },
|
||||
actualBehavior: { type: 'text', required: true },
|
||||
fixedInVersion: { type: 'string', required: false },
|
||||
relatedBugs: { type: 'array', items: { type: 'string' } },
|
||||
affectedVersions: { type: 'array', items: { type: 'string' } },
|
||||
testCoverage: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
unitTest: { type: 'boolean' },
|
||||
integrationTest: { type: 'boolean' },
|
||||
e2eTest: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = await this.synth.generateStructured({
|
||||
count: bugCount,
|
||||
schema: regressionSchema,
|
||||
seed: this.config.seed,
|
||||
constraints: { includeFixed }
|
||||
});
|
||||
|
||||
await this.saveResult('regression-tests', result);
|
||||
|
||||
console.log('✅ Regression test data generated successfully');
|
||||
console.log(` Bug scenarios: ${result.metadata.count}`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate regression test data:', error);
|
||||
throw new SynthError('Regression test generation failed', 'REGRESSION_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate comprehensive test suite
|
||||
*
|
||||
* Combines all test data generation methods into a complete
|
||||
* test suite for CI/CD pipelines.
|
||||
*/
|
||||
async generateComprehensiveTestSuite(options: {
|
||||
feature: string;
|
||||
testCases?: number;
|
||||
edgeCases?: number;
|
||||
performanceTests?: number;
|
||||
securityTests?: number;
|
||||
} = { feature: 'default' }): Promise<void> {
|
||||
console.log('🚀 Generating comprehensive test suite...\n');
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Run all generators in parallel for maximum speed
|
||||
await Promise.all([
|
||||
this.generateDynamicTestCases({
|
||||
feature: options.feature,
|
||||
count: options.testCases || 30
|
||||
}),
|
||||
this.generateEdgeCases({
|
||||
dataType: 'string',
|
||||
count: options.edgeCases || 20
|
||||
}),
|
||||
this.generatePerformanceTestData({
|
||||
scenario: options.feature,
|
||||
dataPoints: options.performanceTests || 10000
|
||||
}),
|
||||
this.generateSecurityTestData({
|
||||
count: options.securityTests || 30
|
||||
}),
|
||||
this.generatePipelineData(),
|
||||
this.generateRegressionTests()
|
||||
]);
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
console.log(`\n✅ Comprehensive test suite generated in ${duration}ms`);
|
||||
console.log(`📁 Output directory: ${path.resolve(this.config.outputDir!)}`);
|
||||
} catch (error) {
|
||||
console.error('\n❌ Failed to generate test suite:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save result to file
|
||||
*/
|
||||
private async saveResult(name: string, result: GenerationResult): Promise<void> {
|
||||
try {
|
||||
await fs.mkdir(this.config.outputDir!, { recursive: true });
|
||||
|
||||
const filepath = path.join(this.config.outputDir!, `${name}.json`);
|
||||
await fs.writeFile(filepath, JSON.stringify(result.data, null, 2), 'utf-8');
|
||||
|
||||
const metadataPath = path.join(this.config.outputDir!, `${name}.metadata.json`);
|
||||
await fs.writeFile(metadataPath, JSON.stringify(result.metadata, null, 2), 'utf-8');
|
||||
} catch (error) {
|
||||
console.error(`Failed to save ${name}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: GitHub Actions Integration
|
||||
*/
|
||||
async function githubActionsPipelineTest() {
|
||||
const tester = new PipelineTester({
|
||||
outputDir: process.env.GITHUB_WORKSPACE + '/test-data',
|
||||
seed: process.env.GITHUB_SHA
|
||||
});
|
||||
|
||||
await tester.generateComprehensiveTestSuite({
|
||||
feature: process.env.FEATURE_NAME || 'default',
|
||||
testCases: 50,
|
||||
edgeCases: 30,
|
||||
performanceTests: 20000,
|
||||
securityTests: 40
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: GitLab CI Integration
|
||||
*/
|
||||
async function gitlabCIPipelineTest() {
|
||||
const tester = new PipelineTester({
|
||||
outputDir: process.env.CI_PROJECT_DIR + '/test-data',
|
||||
seed: process.env.CI_COMMIT_SHORT_SHA
|
||||
});
|
||||
|
||||
await tester.generatePipelineData({
|
||||
stages: ['build', 'test', 'security', 'deploy'],
|
||||
jobsPerStage: 15
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Jenkins Pipeline Integration
|
||||
*/
|
||||
async function jenkinsPipelineTest() {
|
||||
const tester = new PipelineTester({
|
||||
outputDir: process.env.WORKSPACE + '/test-data',
|
||||
seed: process.env.BUILD_NUMBER
|
||||
});
|
||||
|
||||
await tester.generateComprehensiveTestSuite({
|
||||
feature: process.env.JOB_NAME || 'default'
|
||||
});
|
||||
}
|
||||
|
||||
// Export for use in CI/CD scripts
|
||||
export {
|
||||
githubActionsPipelineTest,
|
||||
gitlabCIPipelineTest,
|
||||
jenkinsPipelineTest
|
||||
};
|
||||
|
||||
// Run if called directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
const tester = new PipelineTester();
|
||||
tester.generateComprehensiveTestSuite({ feature: 'example' }).catch(console.error);
|
||||
}
|
||||
131
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.d.ts
vendored
Normal file
131
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.d.ts
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* CI/CD Test Data Generator Examples
|
||||
*
|
||||
* This module demonstrates how to use agentic-synth to generate
|
||||
* comprehensive test data for CI/CD pipelines including:
|
||||
* - Database fixtures for integration tests
|
||||
* - API mock responses
|
||||
* - User session data for E2E tests
|
||||
* - Load testing datasets
|
||||
* - Configuration variations for multi-environment testing
|
||||
*
|
||||
* @module test-data-generator
|
||||
*/
|
||||
import { GenerationResult } from '../../src/index.js';
|
||||
/**
|
||||
* Configuration for test data generation
|
||||
*/
|
||||
export interface TestDataConfig {
|
||||
outputDir: string;
|
||||
format: 'json' | 'csv' | 'array';
|
||||
provider?: 'gemini' | 'openrouter';
|
||||
apiKey?: string;
|
||||
seed?: string | number;
|
||||
}
|
||||
/**
|
||||
* Test data generator class for CI/CD pipelines
|
||||
*/
|
||||
export declare class CICDTestDataGenerator {
|
||||
private synth;
|
||||
private config;
|
||||
constructor(config?: Partial<TestDataConfig>);
|
||||
/**
|
||||
* Generate database fixtures for integration tests
|
||||
*
|
||||
* Creates realistic database records with proper relationships
|
||||
* and constraints for testing database operations.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const generator = new CICDTestDataGenerator();
|
||||
* const fixtures = await generator.generateDatabaseFixtures({
|
||||
* users: 50,
|
||||
* posts: 200,
|
||||
* comments: 500
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
generateDatabaseFixtures(options?: {
|
||||
users?: number;
|
||||
posts?: number;
|
||||
comments?: number;
|
||||
orders?: number;
|
||||
products?: number;
|
||||
}): Promise<Record<string, GenerationResult>>;
|
||||
/**
|
||||
* Generate API mock responses for testing
|
||||
*
|
||||
* Creates realistic API responses with various status codes,
|
||||
* headers, and payloads for comprehensive API testing.
|
||||
*/
|
||||
generateAPIMockResponses(options?: {
|
||||
endpoints?: string[];
|
||||
responsesPerEndpoint?: number;
|
||||
includeErrors?: boolean;
|
||||
}): Promise<GenerationResult>;
|
||||
/**
|
||||
* Generate user session data for E2E tests
|
||||
*
|
||||
* Creates realistic user sessions with cookies, tokens,
|
||||
* and session state for end-to-end testing.
|
||||
*/
|
||||
generateUserSessions(options?: {
|
||||
sessionCount?: number;
|
||||
includeAnonymous?: boolean;
|
||||
}): Promise<GenerationResult>;
|
||||
/**
|
||||
* Generate load testing datasets
|
||||
*
|
||||
* Creates large-scale datasets for load and performance testing
|
||||
* with configurable data patterns and distributions.
|
||||
*/
|
||||
generateLoadTestData(options?: {
|
||||
requestCount?: number;
|
||||
concurrent?: number;
|
||||
duration?: number;
|
||||
}): Promise<GenerationResult>;
|
||||
/**
|
||||
* Generate configuration variations for multi-environment testing
|
||||
*
|
||||
* Creates configuration files for different environments
|
||||
* (dev, staging, production) with realistic values.
|
||||
*/
|
||||
generateEnvironmentConfigs(options?: {
|
||||
environments?: string[];
|
||||
includeSecrets?: boolean;
|
||||
}): Promise<Record<string, GenerationResult>>;
|
||||
/**
|
||||
* Generate all test data at once
|
||||
*
|
||||
* Convenience method to generate all types of test data
|
||||
* in a single operation.
|
||||
*/
|
||||
generateAll(options?: {
|
||||
users?: number;
|
||||
posts?: number;
|
||||
comments?: number;
|
||||
orders?: number;
|
||||
products?: number;
|
||||
apiMocks?: number;
|
||||
sessions?: number;
|
||||
loadTestRequests?: number;
|
||||
}): Promise<void>;
|
||||
/**
|
||||
* Save generation result to file
|
||||
*/
|
||||
private saveToFile;
|
||||
}
|
||||
/**
|
||||
* Example usage in CI/CD pipeline
|
||||
*/
|
||||
declare function cicdExample(): Promise<void>;
|
||||
/**
|
||||
* GitHub Actions example
|
||||
*/
|
||||
declare function githubActionsExample(): Promise<void>;
|
||||
/**
|
||||
* GitLab CI example
|
||||
*/
|
||||
declare function gitlabCIExample(): Promise<void>;
|
||||
export { cicdExample, githubActionsExample, gitlabCIExample };
|
||||
//# sourceMappingURL=test-data-generator.d.ts.map
|
||||
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"test-data-generator.d.ts","sourceRoot":"","sources":["test-data-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA6B,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAI7F;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,MAAM,CAAiB;gBAEnB,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM;IAmBhD;;;;;;;;;;;;;;;OAeG;IACG,wBAAwB,CAAC,OAAO,GAAE;QACtC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAuKlD;;;;;OAKG;IACG,wBAAwB,CAAC,OAAO,GAAE;QACtC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;KACpB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAkDlC;;;;;OAKG;IACG,oBAAoB,CAAC,OAAO,GAAE;QAClC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;KACvB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4DlC;;;;;OAKG;IACG,oBAAoB,CAAC,OAAO,GAAE;QAClC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmElC;;;;;OAKG;IACG,0BAA0B,CAAC,OAAO,GAAE;QACxC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,cAAc,CAAC,EAAE,OAAO,CAAC;KACrB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IA4FlD;;;;;OAKG;IACG,WAAW,CAAC,OAAO,GAAE;QACzB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCtB;;OAEG;YACW,UAAU;CAyCzB;AAED;;GAEG;AACH,iBAAe,WAAW,kBAsBzB;AAED;;GAEG;AACH,iBAAe,oBAAoB,kBAQlC;AAED;;GAEG;AACH,iBAAe,eAAe,kBAO7B;AAGD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,eAAe,EAChB,CAAC"}
|
||||
624
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.js
vendored
Normal file
624
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.js
vendored
Normal file
@@ -0,0 +1,624 @@
|
||||
"use strict";
|
||||
/**
|
||||
* CI/CD Test Data Generator Examples
|
||||
*
|
||||
* This module demonstrates how to use agentic-synth to generate
|
||||
* comprehensive test data for CI/CD pipelines including:
|
||||
* - Database fixtures for integration tests
|
||||
* - API mock responses
|
||||
* - User session data for E2E tests
|
||||
* - Load testing datasets
|
||||
* - Configuration variations for multi-environment testing
|
||||
*
|
||||
* @module test-data-generator
|
||||
*/
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CICDTestDataGenerator = void 0;
|
||||
exports.cicdExample = cicdExample;
|
||||
exports.githubActionsExample = githubActionsExample;
|
||||
exports.gitlabCIExample = gitlabCIExample;
|
||||
const index_js_1 = require("../../src/index.js");
|
||||
const fs = __importStar(require("fs/promises"));
|
||||
const path = __importStar(require("path"));
|
||||
/**
|
||||
* Test data generator class for CI/CD pipelines
|
||||
*/
|
||||
class CICDTestDataGenerator {
|
||||
constructor(config = {}) {
|
||||
this.config = {
|
||||
outputDir: config.outputDir || './test-data',
|
||||
format: config.format || 'json',
|
||||
provider: config.provider || 'gemini',
|
||||
apiKey: config.apiKey || process.env.GEMINI_API_KEY,
|
||||
seed: config.seed
|
||||
};
|
||||
// Initialize agentic-synth
|
||||
this.synth = (0, index_js_1.createSynth)({
|
||||
provider: this.config.provider,
|
||||
apiKey: this.config.apiKey,
|
||||
cacheStrategy: 'memory',
|
||||
cacheTTL: 3600,
|
||||
maxRetries: 3
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Generate database fixtures for integration tests
|
||||
*
|
||||
* Creates realistic database records with proper relationships
|
||||
* and constraints for testing database operations.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const generator = new CICDTestDataGenerator();
|
||||
* const fixtures = await generator.generateDatabaseFixtures({
|
||||
* users: 50,
|
||||
* posts: 200,
|
||||
* comments: 500
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
async generateDatabaseFixtures(options = {}) {
|
||||
const { users = 10, posts = 50, comments = 100, orders = 25, products = 30 } = options;
|
||||
console.log('Generating database fixtures...');
|
||||
try {
|
||||
// Generate users with realistic data
|
||||
const usersSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
username: { type: 'string', required: true, pattern: '^[a-z0-9_]{3,20}$' },
|
||||
email: { type: 'email', required: true },
|
||||
firstName: { type: 'string', required: true },
|
||||
lastName: { type: 'string', required: true },
|
||||
passwordHash: { type: 'string', required: true },
|
||||
role: { type: 'enum', values: ['admin', 'user', 'moderator'], required: true },
|
||||
isActive: { type: 'boolean', required: true },
|
||||
emailVerified: { type: 'boolean', required: true },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
lastLoginAt: { type: 'timestamp', required: false },
|
||||
profile: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bio: { type: 'string' },
|
||||
avatar: { type: 'url' },
|
||||
timezone: { type: 'string' },
|
||||
language: { type: 'string' }
|
||||
}
|
||||
}
|
||||
};
|
||||
// Generate posts with foreign key relationships
|
||||
const postsSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
userId: { type: 'uuid', required: true }, // Foreign key to users
|
||||
title: { type: 'string', required: true, minLength: 10, maxLength: 200 },
|
||||
content: { type: 'text', required: true, minLength: 100 },
|
||||
slug: { type: 'string', required: true },
|
||||
status: { type: 'enum', values: ['draft', 'published', 'archived'], required: true },
|
||||
publishedAt: { type: 'timestamp', required: false },
|
||||
viewCount: { type: 'integer', min: 0, max: 1000000, required: true },
|
||||
tags: { type: 'array', items: { type: 'string' } },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
updatedAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
// Generate comments with nested relationships
|
||||
const commentsSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
postId: { type: 'uuid', required: true }, // Foreign key to posts
|
||||
userId: { type: 'uuid', required: true }, // Foreign key to users
|
||||
parentId: { type: 'uuid', required: false }, // Self-referencing for nested comments
|
||||
content: { type: 'text', required: true, minLength: 10, maxLength: 1000 },
|
||||
isEdited: { type: 'boolean', required: true },
|
||||
isDeleted: { type: 'boolean', required: true },
|
||||
upvotes: { type: 'integer', min: 0, required: true },
|
||||
downvotes: { type: 'integer', min: 0, required: true },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
updatedAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
// Generate products for e-commerce tests
|
||||
const productsSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
sku: { type: 'string', required: true, pattern: '^[A-Z0-9-]{8,15}$' },
|
||||
name: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
price: { type: 'decimal', min: 0.01, max: 10000, required: true },
|
||||
currency: { type: 'string', required: true, default: 'USD' },
|
||||
stockQuantity: { type: 'integer', min: 0, max: 10000, required: true },
|
||||
category: { type: 'string', required: true },
|
||||
brand: { type: 'string', required: false },
|
||||
weight: { type: 'decimal', min: 0, required: false },
|
||||
dimensions: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
length: { type: 'decimal' },
|
||||
width: { type: 'decimal' },
|
||||
height: { type: 'decimal' },
|
||||
unit: { type: 'string', default: 'cm' }
|
||||
}
|
||||
},
|
||||
images: { type: 'array', items: { type: 'url' } },
|
||||
isActive: { type: 'boolean', required: true },
|
||||
createdAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
// Generate orders with complex relationships
|
||||
const ordersSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
userId: { type: 'uuid', required: true },
|
||||
orderNumber: { type: 'string', required: true, pattern: '^ORD-[0-9]{10}$' },
|
||||
status: { type: 'enum', values: ['pending', 'processing', 'shipped', 'delivered', 'cancelled'], required: true },
|
||||
subtotal: { type: 'decimal', min: 0, required: true },
|
||||
tax: { type: 'decimal', min: 0, required: true },
|
||||
shipping: { type: 'decimal', min: 0, required: true },
|
||||
total: { type: 'decimal', min: 0, required: true },
|
||||
currency: { type: 'string', required: true, default: 'USD' },
|
||||
paymentMethod: { type: 'enum', values: ['credit_card', 'paypal', 'bank_transfer'], required: true },
|
||||
paymentStatus: { type: 'enum', values: ['pending', 'completed', 'failed', 'refunded'], required: true },
|
||||
shippingAddress: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
street: { type: 'string' },
|
||||
city: { type: 'string' },
|
||||
state: { type: 'string' },
|
||||
postalCode: { type: 'string' },
|
||||
country: { type: 'string' }
|
||||
}
|
||||
},
|
||||
items: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
productId: { type: 'uuid' },
|
||||
quantity: { type: 'integer', min: 1 },
|
||||
price: { type: 'decimal' }
|
||||
}
|
||||
}
|
||||
},
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
updatedAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
// Generate all fixtures in parallel
|
||||
const [usersResult, postsResult, commentsResult, productsResult, ordersResult] = await Promise.all([
|
||||
this.synth.generateStructured({ count: users, schema: usersSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: posts, schema: postsSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: comments, schema: commentsSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: products, schema: productsSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: orders, schema: ordersSchema, seed: this.config.seed })
|
||||
]);
|
||||
// Save to files
|
||||
await this.saveToFile('users', usersResult);
|
||||
await this.saveToFile('posts', postsResult);
|
||||
await this.saveToFile('comments', commentsResult);
|
||||
await this.saveToFile('products', productsResult);
|
||||
await this.saveToFile('orders', ordersResult);
|
||||
console.log('✅ Database fixtures generated successfully');
|
||||
console.log(` Users: ${usersResult.metadata.count}`);
|
||||
console.log(` Posts: ${postsResult.metadata.count}`);
|
||||
console.log(` Comments: ${commentsResult.metadata.count}`);
|
||||
console.log(` Products: ${productsResult.metadata.count}`);
|
||||
console.log(` Orders: ${ordersResult.metadata.count}`);
|
||||
return {
|
||||
users: usersResult,
|
||||
posts: postsResult,
|
||||
comments: commentsResult,
|
||||
products: productsResult,
|
||||
orders: ordersResult
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate database fixtures:', error);
|
||||
throw new index_js_1.SynthError('Database fixture generation failed', 'FIXTURE_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate API mock responses for testing
|
||||
*
|
||||
* Creates realistic API responses with various status codes,
|
||||
* headers, and payloads for comprehensive API testing.
|
||||
*/
|
||||
async generateAPIMockResponses(options = {}) {
|
||||
const { endpoints = ['/api/users', '/api/posts', '/api/products', '/api/orders'], responsesPerEndpoint = 5, includeErrors = true } = options;
|
||||
console.log('Generating API mock responses...');
|
||||
try {
|
||||
const mockResponseSchema = {
|
||||
endpoint: { type: 'string', required: true },
|
||||
method: { type: 'enum', values: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], required: true },
|
||||
statusCode: { type: 'integer', required: true },
|
||||
statusText: { type: 'string', required: true },
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Content-Type': { type: 'string' },
|
||||
'X-Request-Id': { type: 'uuid' },
|
||||
'X-RateLimit-Limit': { type: 'integer' },
|
||||
'X-RateLimit-Remaining': { type: 'integer' },
|
||||
'Cache-Control': { type: 'string' }
|
||||
}
|
||||
},
|
||||
body: { type: 'object', required: true },
|
||||
latency: { type: 'integer', min: 10, max: 5000, required: true },
|
||||
timestamp: { type: 'timestamp', required: true }
|
||||
};
|
||||
const totalResponses = endpoints.length * responsesPerEndpoint;
|
||||
const result = await this.synth.generateStructured({
|
||||
count: totalResponses,
|
||||
schema: mockResponseSchema,
|
||||
seed: this.config.seed
|
||||
});
|
||||
await this.saveToFile('api-mocks', result);
|
||||
console.log('✅ API mock responses generated successfully');
|
||||
console.log(` Total responses: ${result.metadata.count}`);
|
||||
console.log(` Endpoints: ${endpoints.length}`);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate API mocks:', error);
|
||||
throw new index_js_1.SynthError('API mock generation failed', 'MOCK_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate user session data for E2E tests
|
||||
*
|
||||
* Creates realistic user sessions with cookies, tokens,
|
||||
* and session state for end-to-end testing.
|
||||
*/
|
||||
async generateUserSessions(options = {}) {
|
||||
const { sessionCount = 20, includeAnonymous = true } = options;
|
||||
console.log('Generating user session data...');
|
||||
try {
|
||||
const sessionSchema = {
|
||||
sessionId: { type: 'uuid', required: true },
|
||||
userId: { type: 'uuid', required: false }, // Null for anonymous sessions
|
||||
isAuthenticated: { type: 'boolean', required: true },
|
||||
username: { type: 'string', required: false },
|
||||
email: { type: 'email', required: false },
|
||||
token: { type: 'string', required: false }, // JWT token
|
||||
refreshToken: { type: 'string', required: false },
|
||||
tokenExpiry: { type: 'timestamp', required: false },
|
||||
cookies: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
sessionId: { type: 'string' },
|
||||
csrfToken: { type: 'string' },
|
||||
preferences: { type: 'string' }
|
||||
}
|
||||
},
|
||||
userAgent: { type: 'string', required: true },
|
||||
ipAddress: { type: 'string', required: true },
|
||||
location: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
country: { type: 'string' },
|
||||
city: { type: 'string' },
|
||||
timezone: { type: 'string' }
|
||||
}
|
||||
},
|
||||
permissions: { type: 'array', items: { type: 'string' } },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
lastActivityAt: { type: 'timestamp', required: true },
|
||||
expiresAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
const result = await this.synth.generateStructured({
|
||||
count: sessionCount,
|
||||
schema: sessionSchema,
|
||||
seed: this.config.seed
|
||||
});
|
||||
await this.saveToFile('user-sessions', result);
|
||||
console.log('✅ User session data generated successfully');
|
||||
console.log(` Sessions: ${result.metadata.count}`);
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate user sessions:', error);
|
||||
throw new index_js_1.SynthError('Session generation failed', 'SESSION_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate load testing datasets
|
||||
*
|
||||
* Creates large-scale datasets for load and performance testing
|
||||
* with configurable data patterns and distributions.
|
||||
*/
|
||||
async generateLoadTestData(options = {}) {
|
||||
const { requestCount = 10000, concurrent = 100, duration = 10 } = options;
|
||||
console.log('Generating load test data...');
|
||||
try {
|
||||
const loadTestSchema = {
|
||||
requestId: { type: 'uuid', required: true },
|
||||
endpoint: { type: 'string', required: true },
|
||||
method: { type: 'enum', values: ['GET', 'POST', 'PUT', 'DELETE'], required: true },
|
||||
payload: { type: 'object', required: false },
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Authorization': { type: 'string' },
|
||||
'Content-Type': { type: 'string' },
|
||||
'User-Agent': { type: 'string' }
|
||||
}
|
||||
},
|
||||
timestamp: { type: 'timestamp', required: true },
|
||||
priority: { type: 'enum', values: ['low', 'medium', 'high', 'critical'], required: true },
|
||||
expectedStatusCode: { type: 'integer', required: true },
|
||||
timeout: { type: 'integer', min: 1000, max: 30000, required: true }
|
||||
};
|
||||
// Generate in batches for better performance
|
||||
const batchSize = 1000;
|
||||
const batches = Math.ceil(requestCount / batchSize);
|
||||
const batchOptions = Array.from({ length: batches }, () => ({
|
||||
count: batchSize,
|
||||
schema: loadTestSchema,
|
||||
seed: this.config.seed
|
||||
}));
|
||||
const results = await this.synth.generateBatch('structured', batchOptions, concurrent);
|
||||
// Combine all results
|
||||
const combinedData = results.flatMap(r => r.data);
|
||||
const combinedResult = {
|
||||
data: combinedData,
|
||||
metadata: {
|
||||
count: combinedData.length,
|
||||
generatedAt: new Date(),
|
||||
provider: results[0].metadata.provider,
|
||||
model: results[0].metadata.model,
|
||||
cached: false,
|
||||
duration: results.reduce((sum, r) => sum + r.metadata.duration, 0)
|
||||
}
|
||||
};
|
||||
await this.saveToFile('load-test-data', combinedResult);
|
||||
console.log('✅ Load test data generated successfully');
|
||||
console.log(` Requests: ${combinedResult.metadata.count}`);
|
||||
console.log(` Duration: ${combinedResult.metadata.duration}ms`);
|
||||
return combinedResult;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate load test data:', error);
|
||||
throw new index_js_1.SynthError('Load test data generation failed', 'LOAD_TEST_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate configuration variations for multi-environment testing
|
||||
*
|
||||
* Creates configuration files for different environments
|
||||
* (dev, staging, production) with realistic values.
|
||||
*/
|
||||
async generateEnvironmentConfigs(options = {}) {
|
||||
const { environments = ['development', 'staging', 'production'], includeSecrets = false } = options;
|
||||
console.log('Generating environment configurations...');
|
||||
try {
|
||||
const configSchema = {
|
||||
environment: { type: 'string', required: true },
|
||||
app: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
version: { type: 'string', pattern: '^\\d+\\.\\d+\\.\\d+$' },
|
||||
port: { type: 'integer', min: 3000, max: 9999 },
|
||||
host: { type: 'string' },
|
||||
logLevel: { type: 'enum', values: ['debug', 'info', 'warn', 'error'] }
|
||||
}
|
||||
},
|
||||
database: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
host: { type: 'string' },
|
||||
port: { type: 'integer' },
|
||||
name: { type: 'string' },
|
||||
username: { type: 'string' },
|
||||
password: { type: 'string', required: includeSecrets },
|
||||
ssl: { type: 'boolean' },
|
||||
poolSize: { type: 'integer', min: 5, max: 100 },
|
||||
timeout: { type: 'integer' }
|
||||
}
|
||||
},
|
||||
redis: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
host: { type: 'string' },
|
||||
port: { type: 'integer' },
|
||||
password: { type: 'string', required: includeSecrets },
|
||||
db: { type: 'integer', min: 0, max: 15 }
|
||||
}
|
||||
},
|
||||
api: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
baseUrl: { type: 'url' },
|
||||
timeout: { type: 'integer' },
|
||||
retries: { type: 'integer', min: 0, max: 5 },
|
||||
rateLimit: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
maxRequests: { type: 'integer' },
|
||||
windowMs: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
features: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
authentication: { type: 'boolean' },
|
||||
caching: { type: 'boolean' },
|
||||
monitoring: { type: 'boolean' },
|
||||
analytics: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
};
|
||||
const results = {};
|
||||
for (const env of environments) {
|
||||
const result = await this.synth.generateStructured({
|
||||
count: 1,
|
||||
schema: { ...configSchema, environment: { type: 'string', default: env } },
|
||||
seed: `${this.config.seed}-${env}`
|
||||
});
|
||||
results[env] = result;
|
||||
await this.saveToFile(`config-${env}`, result);
|
||||
}
|
||||
console.log('✅ Environment configurations generated successfully');
|
||||
console.log(` Environments: ${environments.join(', ')}`);
|
||||
return results;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to generate environment configs:', error);
|
||||
throw new index_js_1.SynthError('Config generation failed', 'CONFIG_ERROR', error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate all test data at once
|
||||
*
|
||||
* Convenience method to generate all types of test data
|
||||
* in a single operation.
|
||||
*/
|
||||
async generateAll(options = {}) {
|
||||
console.log('🚀 Generating all test data...\n');
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
await Promise.all([
|
||||
this.generateDatabaseFixtures({
|
||||
users: options.users,
|
||||
posts: options.posts,
|
||||
comments: options.comments,
|
||||
orders: options.orders,
|
||||
products: options.products
|
||||
}),
|
||||
this.generateAPIMockResponses({
|
||||
responsesPerEndpoint: options.apiMocks || 5
|
||||
}),
|
||||
this.generateUserSessions({
|
||||
sessionCount: options.sessions || 20
|
||||
}),
|
||||
this.generateEnvironmentConfigs()
|
||||
]);
|
||||
// Load test data generation is CPU-intensive, run separately
|
||||
if (options.loadTestRequests && options.loadTestRequests > 0) {
|
||||
await this.generateLoadTestData({
|
||||
requestCount: options.loadTestRequests
|
||||
});
|
||||
}
|
||||
const duration = Date.now() - startTime;
|
||||
console.log(`\n✅ All test data generated successfully in ${duration}ms`);
|
||||
console.log(`📁 Output directory: ${path.resolve(this.config.outputDir)}`);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('\n❌ Failed to generate test data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Save generation result to file
|
||||
*/
|
||||
async saveToFile(name, result) {
|
||||
try {
|
||||
// Ensure output directory exists
|
||||
await fs.mkdir(this.config.outputDir, { recursive: true });
|
||||
const filename = `${name}.${this.config.format}`;
|
||||
const filepath = path.join(this.config.outputDir, filename);
|
||||
let content;
|
||||
if (this.config.format === 'json') {
|
||||
content = JSON.stringify(result.data, null, 2);
|
||||
}
|
||||
else if (this.config.format === 'csv') {
|
||||
// Simple CSV conversion (you might want to use a library for production)
|
||||
if (result.data.length === 0) {
|
||||
content = '';
|
||||
}
|
||||
else {
|
||||
const headers = Object.keys(result.data[0]);
|
||||
const rows = result.data.map((item) => headers.map(header => JSON.stringify(item[header] ?? '')).join(','));
|
||||
content = [headers.join(','), ...rows].join('\n');
|
||||
}
|
||||
}
|
||||
else {
|
||||
content = JSON.stringify(result.data, null, 2);
|
||||
}
|
||||
await fs.writeFile(filepath, content, 'utf-8');
|
||||
// Also save metadata
|
||||
const metadataPath = path.join(this.config.outputDir, `${name}.metadata.json`);
|
||||
await fs.writeFile(metadataPath, JSON.stringify(result.metadata, null, 2), 'utf-8');
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to save ${name}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.CICDTestDataGenerator = CICDTestDataGenerator;
|
||||
/**
|
||||
* Example usage in CI/CD pipeline
|
||||
*/
|
||||
async function cicdExample() {
|
||||
// Initialize generator
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: './test-fixtures',
|
||||
format: 'json',
|
||||
provider: 'gemini',
|
||||
seed: process.env.CI_COMMIT_SHA || 'default-seed' // Use commit SHA for reproducibility
|
||||
});
|
||||
// Generate all test data
|
||||
await generator.generateAll({
|
||||
users: 50,
|
||||
posts: 200,
|
||||
comments: 500,
|
||||
orders: 100,
|
||||
products: 75,
|
||||
apiMocks: 10,
|
||||
sessions: 30,
|
||||
loadTestRequests: 5000
|
||||
});
|
||||
console.log('Test data ready for CI/CD pipeline');
|
||||
}
|
||||
/**
|
||||
* GitHub Actions example
|
||||
*/
|
||||
async function githubActionsExample() {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: process.env.GITHUB_WORKSPACE + '/test-data',
|
||||
seed: process.env.GITHUB_SHA
|
||||
});
|
||||
await generator.generateDatabaseFixtures();
|
||||
await generator.generateAPIMockResponses();
|
||||
}
|
||||
/**
|
||||
* GitLab CI example
|
||||
*/
|
||||
async function gitlabCIExample() {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: process.env.CI_PROJECT_DIR + '/test-data',
|
||||
seed: process.env.CI_COMMIT_SHORT_SHA
|
||||
});
|
||||
await generator.generateAll();
|
||||
}
|
||||
// Run if called directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
cicdExample().catch(console.error);
|
||||
}
|
||||
//# sourceMappingURL=test-data-generator.js.map
|
||||
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
715
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.ts
vendored
Normal file
715
vendor/ruvector/npm/packages/agentic-synth/examples/cicd/test-data-generator.ts
vendored
Normal file
@@ -0,0 +1,715 @@
|
||||
/**
|
||||
* CI/CD Test Data Generator Examples
|
||||
*
|
||||
* This module demonstrates how to use agentic-synth to generate
|
||||
* comprehensive test data for CI/CD pipelines including:
|
||||
* - Database fixtures for integration tests
|
||||
* - API mock responses
|
||||
* - User session data for E2E tests
|
||||
* - Load testing datasets
|
||||
* - Configuration variations for multi-environment testing
|
||||
*
|
||||
* @module test-data-generator
|
||||
*/
|
||||
|
||||
import { AgenticSynth, createSynth, GenerationResult, SynthError } from '../../src/index.js';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* Configuration for test data generation
|
||||
*/
|
||||
export interface TestDataConfig {
|
||||
outputDir: string;
|
||||
format: 'json' | 'csv' | 'array';
|
||||
provider?: 'gemini' | 'openrouter';
|
||||
apiKey?: string;
|
||||
seed?: string | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test data generator class for CI/CD pipelines
|
||||
*/
|
||||
export class CICDTestDataGenerator {
|
||||
private synth: AgenticSynth;
|
||||
private config: TestDataConfig;
|
||||
|
||||
constructor(config: Partial<TestDataConfig> = {}) {
|
||||
this.config = {
|
||||
outputDir: config.outputDir || './test-data',
|
||||
format: config.format || 'json',
|
||||
provider: config.provider || 'gemini',
|
||||
apiKey: config.apiKey || process.env.GEMINI_API_KEY,
|
||||
seed: config.seed
|
||||
};
|
||||
|
||||
// Initialize agentic-synth
|
||||
this.synth = createSynth({
|
||||
provider: this.config.provider,
|
||||
apiKey: this.config.apiKey,
|
||||
cacheStrategy: 'memory',
|
||||
cacheTTL: 3600,
|
||||
maxRetries: 3
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate database fixtures for integration tests
|
||||
*
|
||||
* Creates realistic database records with proper relationships
|
||||
* and constraints for testing database operations.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const generator = new CICDTestDataGenerator();
|
||||
* const fixtures = await generator.generateDatabaseFixtures({
|
||||
* users: 50,
|
||||
* posts: 200,
|
||||
* comments: 500
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
async generateDatabaseFixtures(options: {
|
||||
users?: number;
|
||||
posts?: number;
|
||||
comments?: number;
|
||||
orders?: number;
|
||||
products?: number;
|
||||
} = {}): Promise<Record<string, GenerationResult>> {
|
||||
const {
|
||||
users = 10,
|
||||
posts = 50,
|
||||
comments = 100,
|
||||
orders = 25,
|
||||
products = 30
|
||||
} = options;
|
||||
|
||||
console.log('Generating database fixtures...');
|
||||
|
||||
try {
|
||||
// Generate users with realistic data
|
||||
const usersSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
username: { type: 'string', required: true, pattern: '^[a-z0-9_]{3,20}$' },
|
||||
email: { type: 'email', required: true },
|
||||
firstName: { type: 'string', required: true },
|
||||
lastName: { type: 'string', required: true },
|
||||
passwordHash: { type: 'string', required: true },
|
||||
role: { type: 'enum', values: ['admin', 'user', 'moderator'], required: true },
|
||||
isActive: { type: 'boolean', required: true },
|
||||
emailVerified: { type: 'boolean', required: true },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
lastLoginAt: { type: 'timestamp', required: false },
|
||||
profile: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bio: { type: 'string' },
|
||||
avatar: { type: 'url' },
|
||||
timezone: { type: 'string' },
|
||||
language: { type: 'string' }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Generate posts with foreign key relationships
|
||||
const postsSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
userId: { type: 'uuid', required: true }, // Foreign key to users
|
||||
title: { type: 'string', required: true, minLength: 10, maxLength: 200 },
|
||||
content: { type: 'text', required: true, minLength: 100 },
|
||||
slug: { type: 'string', required: true },
|
||||
status: { type: 'enum', values: ['draft', 'published', 'archived'], required: true },
|
||||
publishedAt: { type: 'timestamp', required: false },
|
||||
viewCount: { type: 'integer', min: 0, max: 1000000, required: true },
|
||||
tags: { type: 'array', items: { type: 'string' } },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
updatedAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
|
||||
// Generate comments with nested relationships
|
||||
const commentsSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
postId: { type: 'uuid', required: true }, // Foreign key to posts
|
||||
userId: { type: 'uuid', required: true }, // Foreign key to users
|
||||
parentId: { type: 'uuid', required: false }, // Self-referencing for nested comments
|
||||
content: { type: 'text', required: true, minLength: 10, maxLength: 1000 },
|
||||
isEdited: { type: 'boolean', required: true },
|
||||
isDeleted: { type: 'boolean', required: true },
|
||||
upvotes: { type: 'integer', min: 0, required: true },
|
||||
downvotes: { type: 'integer', min: 0, required: true },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
updatedAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
|
||||
// Generate products for e-commerce tests
|
||||
const productsSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
sku: { type: 'string', required: true, pattern: '^[A-Z0-9-]{8,15}$' },
|
||||
name: { type: 'string', required: true },
|
||||
description: { type: 'text', required: true },
|
||||
price: { type: 'decimal', min: 0.01, max: 10000, required: true },
|
||||
currency: { type: 'string', required: true, default: 'USD' },
|
||||
stockQuantity: { type: 'integer', min: 0, max: 10000, required: true },
|
||||
category: { type: 'string', required: true },
|
||||
brand: { type: 'string', required: false },
|
||||
weight: { type: 'decimal', min: 0, required: false },
|
||||
dimensions: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
length: { type: 'decimal' },
|
||||
width: { type: 'decimal' },
|
||||
height: { type: 'decimal' },
|
||||
unit: { type: 'string', default: 'cm' }
|
||||
}
|
||||
},
|
||||
images: { type: 'array', items: { type: 'url' } },
|
||||
isActive: { type: 'boolean', required: true },
|
||||
createdAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
|
||||
// Generate orders with complex relationships
|
||||
const ordersSchema = {
|
||||
id: { type: 'uuid', required: true },
|
||||
userId: { type: 'uuid', required: true },
|
||||
orderNumber: { type: 'string', required: true, pattern: '^ORD-[0-9]{10}$' },
|
||||
status: { type: 'enum', values: ['pending', 'processing', 'shipped', 'delivered', 'cancelled'], required: true },
|
||||
subtotal: { type: 'decimal', min: 0, required: true },
|
||||
tax: { type: 'decimal', min: 0, required: true },
|
||||
shipping: { type: 'decimal', min: 0, required: true },
|
||||
total: { type: 'decimal', min: 0, required: true },
|
||||
currency: { type: 'string', required: true, default: 'USD' },
|
||||
paymentMethod: { type: 'enum', values: ['credit_card', 'paypal', 'bank_transfer'], required: true },
|
||||
paymentStatus: { type: 'enum', values: ['pending', 'completed', 'failed', 'refunded'], required: true },
|
||||
shippingAddress: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
street: { type: 'string' },
|
||||
city: { type: 'string' },
|
||||
state: { type: 'string' },
|
||||
postalCode: { type: 'string' },
|
||||
country: { type: 'string' }
|
||||
}
|
||||
},
|
||||
items: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
productId: { type: 'uuid' },
|
||||
quantity: { type: 'integer', min: 1 },
|
||||
price: { type: 'decimal' }
|
||||
}
|
||||
}
|
||||
},
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
updatedAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
|
||||
// Generate all fixtures in parallel
|
||||
const [usersResult, postsResult, commentsResult, productsResult, ordersResult] =
|
||||
await Promise.all([
|
||||
this.synth.generateStructured({ count: users, schema: usersSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: posts, schema: postsSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: comments, schema: commentsSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: products, schema: productsSchema, seed: this.config.seed }),
|
||||
this.synth.generateStructured({ count: orders, schema: ordersSchema, seed: this.config.seed })
|
||||
]);
|
||||
|
||||
// Save to files
|
||||
await this.saveToFile('users', usersResult);
|
||||
await this.saveToFile('posts', postsResult);
|
||||
await this.saveToFile('comments', commentsResult);
|
||||
await this.saveToFile('products', productsResult);
|
||||
await this.saveToFile('orders', ordersResult);
|
||||
|
||||
console.log('✅ Database fixtures generated successfully');
|
||||
console.log(` Users: ${usersResult.metadata.count}`);
|
||||
console.log(` Posts: ${postsResult.metadata.count}`);
|
||||
console.log(` Comments: ${commentsResult.metadata.count}`);
|
||||
console.log(` Products: ${productsResult.metadata.count}`);
|
||||
console.log(` Orders: ${ordersResult.metadata.count}`);
|
||||
|
||||
return {
|
||||
users: usersResult,
|
||||
posts: postsResult,
|
||||
comments: commentsResult,
|
||||
products: productsResult,
|
||||
orders: ordersResult
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate database fixtures:', error);
|
||||
throw new SynthError('Database fixture generation failed', 'FIXTURE_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate API mock responses for testing
|
||||
*
|
||||
* Creates realistic API responses with various status codes,
|
||||
* headers, and payloads for comprehensive API testing.
|
||||
*/
|
||||
async generateAPIMockResponses(options: {
|
||||
endpoints?: string[];
|
||||
responsesPerEndpoint?: number;
|
||||
includeErrors?: boolean;
|
||||
} = {}): Promise<GenerationResult> {
|
||||
const {
|
||||
endpoints = ['/api/users', '/api/posts', '/api/products', '/api/orders'],
|
||||
responsesPerEndpoint = 5,
|
||||
includeErrors = true
|
||||
} = options;
|
||||
|
||||
console.log('Generating API mock responses...');
|
||||
|
||||
try {
|
||||
const mockResponseSchema = {
|
||||
endpoint: { type: 'string', required: true },
|
||||
method: { type: 'enum', values: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], required: true },
|
||||
statusCode: { type: 'integer', required: true },
|
||||
statusText: { type: 'string', required: true },
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Content-Type': { type: 'string' },
|
||||
'X-Request-Id': { type: 'uuid' },
|
||||
'X-RateLimit-Limit': { type: 'integer' },
|
||||
'X-RateLimit-Remaining': { type: 'integer' },
|
||||
'Cache-Control': { type: 'string' }
|
||||
}
|
||||
},
|
||||
body: { type: 'object', required: true },
|
||||
latency: { type: 'integer', min: 10, max: 5000, required: true },
|
||||
timestamp: { type: 'timestamp', required: true }
|
||||
};
|
||||
|
||||
const totalResponses = endpoints.length * responsesPerEndpoint;
|
||||
const result = await this.synth.generateStructured({
|
||||
count: totalResponses,
|
||||
schema: mockResponseSchema,
|
||||
seed: this.config.seed
|
||||
});
|
||||
|
||||
await this.saveToFile('api-mocks', result);
|
||||
|
||||
console.log('✅ API mock responses generated successfully');
|
||||
console.log(` Total responses: ${result.metadata.count}`);
|
||||
console.log(` Endpoints: ${endpoints.length}`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate API mocks:', error);
|
||||
throw new SynthError('API mock generation failed', 'MOCK_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate user session data for E2E tests
|
||||
*
|
||||
* Creates realistic user sessions with cookies, tokens,
|
||||
* and session state for end-to-end testing.
|
||||
*/
|
||||
async generateUserSessions(options: {
|
||||
sessionCount?: number;
|
||||
includeAnonymous?: boolean;
|
||||
} = {}): Promise<GenerationResult> {
|
||||
const {
|
||||
sessionCount = 20,
|
||||
includeAnonymous = true
|
||||
} = options;
|
||||
|
||||
console.log('Generating user session data...');
|
||||
|
||||
try {
|
||||
const sessionSchema = {
|
||||
sessionId: { type: 'uuid', required: true },
|
||||
userId: { type: 'uuid', required: false }, // Null for anonymous sessions
|
||||
isAuthenticated: { type: 'boolean', required: true },
|
||||
username: { type: 'string', required: false },
|
||||
email: { type: 'email', required: false },
|
||||
token: { type: 'string', required: false }, // JWT token
|
||||
refreshToken: { type: 'string', required: false },
|
||||
tokenExpiry: { type: 'timestamp', required: false },
|
||||
cookies: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
sessionId: { type: 'string' },
|
||||
csrfToken: { type: 'string' },
|
||||
preferences: { type: 'string' }
|
||||
}
|
||||
},
|
||||
userAgent: { type: 'string', required: true },
|
||||
ipAddress: { type: 'string', required: true },
|
||||
location: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
country: { type: 'string' },
|
||||
city: { type: 'string' },
|
||||
timezone: { type: 'string' }
|
||||
}
|
||||
},
|
||||
permissions: { type: 'array', items: { type: 'string' } },
|
||||
createdAt: { type: 'timestamp', required: true },
|
||||
lastActivityAt: { type: 'timestamp', required: true },
|
||||
expiresAt: { type: 'timestamp', required: true }
|
||||
};
|
||||
|
||||
const result = await this.synth.generateStructured({
|
||||
count: sessionCount,
|
||||
schema: sessionSchema,
|
||||
seed: this.config.seed
|
||||
});
|
||||
|
||||
await this.saveToFile('user-sessions', result);
|
||||
|
||||
console.log('✅ User session data generated successfully');
|
||||
console.log(` Sessions: ${result.metadata.count}`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate user sessions:', error);
|
||||
throw new SynthError('Session generation failed', 'SESSION_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate load testing datasets
|
||||
*
|
||||
* Creates large-scale datasets for load and performance testing
|
||||
* with configurable data patterns and distributions.
|
||||
*/
|
||||
async generateLoadTestData(options: {
|
||||
requestCount?: number;
|
||||
concurrent?: number;
|
||||
duration?: number; // in minutes
|
||||
} = {}): Promise<GenerationResult> {
|
||||
const {
|
||||
requestCount = 10000,
|
||||
concurrent = 100,
|
||||
duration = 10
|
||||
} = options;
|
||||
|
||||
console.log('Generating load test data...');
|
||||
|
||||
try {
|
||||
const loadTestSchema = {
|
||||
requestId: { type: 'uuid', required: true },
|
||||
endpoint: { type: 'string', required: true },
|
||||
method: { type: 'enum', values: ['GET', 'POST', 'PUT', 'DELETE'], required: true },
|
||||
payload: { type: 'object', required: false },
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Authorization': { type: 'string' },
|
||||
'Content-Type': { type: 'string' },
|
||||
'User-Agent': { type: 'string' }
|
||||
}
|
||||
},
|
||||
timestamp: { type: 'timestamp', required: true },
|
||||
priority: { type: 'enum', values: ['low', 'medium', 'high', 'critical'], required: true },
|
||||
expectedStatusCode: { type: 'integer', required: true },
|
||||
timeout: { type: 'integer', min: 1000, max: 30000, required: true }
|
||||
};
|
||||
|
||||
// Generate in batches for better performance
|
||||
const batchSize = 1000;
|
||||
const batches = Math.ceil(requestCount / batchSize);
|
||||
const batchOptions = Array.from({ length: batches }, () => ({
|
||||
count: batchSize,
|
||||
schema: loadTestSchema,
|
||||
seed: this.config.seed
|
||||
}));
|
||||
|
||||
const results = await this.synth.generateBatch('structured', batchOptions, concurrent);
|
||||
|
||||
// Combine all results
|
||||
const combinedData = results.flatMap(r => r.data);
|
||||
const combinedResult: GenerationResult = {
|
||||
data: combinedData,
|
||||
metadata: {
|
||||
count: combinedData.length,
|
||||
generatedAt: new Date(),
|
||||
provider: results[0].metadata.provider,
|
||||
model: results[0].metadata.model,
|
||||
cached: false,
|
||||
duration: results.reduce((sum, r) => sum + r.metadata.duration, 0)
|
||||
}
|
||||
};
|
||||
|
||||
await this.saveToFile('load-test-data', combinedResult);
|
||||
|
||||
console.log('✅ Load test data generated successfully');
|
||||
console.log(` Requests: ${combinedResult.metadata.count}`);
|
||||
console.log(` Duration: ${combinedResult.metadata.duration}ms`);
|
||||
|
||||
return combinedResult;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate load test data:', error);
|
||||
throw new SynthError('Load test data generation failed', 'LOAD_TEST_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate configuration variations for multi-environment testing
|
||||
*
|
||||
* Creates configuration files for different environments
|
||||
* (dev, staging, production) with realistic values.
|
||||
*/
|
||||
async generateEnvironmentConfigs(options: {
|
||||
environments?: string[];
|
||||
includeSecrets?: boolean;
|
||||
} = {}): Promise<Record<string, GenerationResult>> {
|
||||
const {
|
||||
environments = ['development', 'staging', 'production'],
|
||||
includeSecrets = false
|
||||
} = options;
|
||||
|
||||
console.log('Generating environment configurations...');
|
||||
|
||||
try {
|
||||
const configSchema = {
|
||||
environment: { type: 'string', required: true },
|
||||
app: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
version: { type: 'string', pattern: '^\\d+\\.\\d+\\.\\d+$' },
|
||||
port: { type: 'integer', min: 3000, max: 9999 },
|
||||
host: { type: 'string' },
|
||||
logLevel: { type: 'enum', values: ['debug', 'info', 'warn', 'error'] }
|
||||
}
|
||||
},
|
||||
database: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
host: { type: 'string' },
|
||||
port: { type: 'integer' },
|
||||
name: { type: 'string' },
|
||||
username: { type: 'string' },
|
||||
password: { type: 'string', required: includeSecrets },
|
||||
ssl: { type: 'boolean' },
|
||||
poolSize: { type: 'integer', min: 5, max: 100 },
|
||||
timeout: { type: 'integer' }
|
||||
}
|
||||
},
|
||||
redis: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
host: { type: 'string' },
|
||||
port: { type: 'integer' },
|
||||
password: { type: 'string', required: includeSecrets },
|
||||
db: { type: 'integer', min: 0, max: 15 }
|
||||
}
|
||||
},
|
||||
api: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
baseUrl: { type: 'url' },
|
||||
timeout: { type: 'integer' },
|
||||
retries: { type: 'integer', min: 0, max: 5 },
|
||||
rateLimit: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
maxRequests: { type: 'integer' },
|
||||
windowMs: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
features: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
authentication: { type: 'boolean' },
|
||||
caching: { type: 'boolean' },
|
||||
monitoring: { type: 'boolean' },
|
||||
analytics: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const results: Record<string, GenerationResult> = {};
|
||||
|
||||
for (const env of environments) {
|
||||
const result = await this.synth.generateStructured({
|
||||
count: 1,
|
||||
schema: { ...configSchema, environment: { type: 'string', default: env } },
|
||||
seed: `${this.config.seed}-${env}`
|
||||
});
|
||||
|
||||
results[env] = result;
|
||||
await this.saveToFile(`config-${env}`, result);
|
||||
}
|
||||
|
||||
console.log('✅ Environment configurations generated successfully');
|
||||
console.log(` Environments: ${environments.join(', ')}`);
|
||||
|
||||
return results;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to generate environment configs:', error);
|
||||
throw new SynthError('Config generation failed', 'CONFIG_ERROR', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate all test data at once
|
||||
*
|
||||
* Convenience method to generate all types of test data
|
||||
* in a single operation.
|
||||
*/
|
||||
async generateAll(options: {
|
||||
users?: number;
|
||||
posts?: number;
|
||||
comments?: number;
|
||||
orders?: number;
|
||||
products?: number;
|
||||
apiMocks?: number;
|
||||
sessions?: number;
|
||||
loadTestRequests?: number;
|
||||
} = {}): Promise<void> {
|
||||
console.log('🚀 Generating all test data...\n');
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
await Promise.all([
|
||||
this.generateDatabaseFixtures({
|
||||
users: options.users,
|
||||
posts: options.posts,
|
||||
comments: options.comments,
|
||||
orders: options.orders,
|
||||
products: options.products
|
||||
}),
|
||||
this.generateAPIMockResponses({
|
||||
responsesPerEndpoint: options.apiMocks || 5
|
||||
}),
|
||||
this.generateUserSessions({
|
||||
sessionCount: options.sessions || 20
|
||||
}),
|
||||
this.generateEnvironmentConfigs()
|
||||
]);
|
||||
|
||||
// Load test data generation is CPU-intensive, run separately
|
||||
if (options.loadTestRequests && options.loadTestRequests > 0) {
|
||||
await this.generateLoadTestData({
|
||||
requestCount: options.loadTestRequests
|
||||
});
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
console.log(`\n✅ All test data generated successfully in ${duration}ms`);
|
||||
console.log(`📁 Output directory: ${path.resolve(this.config.outputDir)}`);
|
||||
} catch (error) {
|
||||
console.error('\n❌ Failed to generate test data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save generation result to file
|
||||
*/
|
||||
private async saveToFile(name: string, result: GenerationResult): Promise<void> {
|
||||
try {
|
||||
// Ensure output directory exists
|
||||
await fs.mkdir(this.config.outputDir, { recursive: true });
|
||||
|
||||
const filename = `${name}.${this.config.format}`;
|
||||
const filepath = path.join(this.config.outputDir, filename);
|
||||
|
||||
let content: string;
|
||||
|
||||
if (this.config.format === 'json') {
|
||||
content = JSON.stringify(result.data, null, 2);
|
||||
} else if (this.config.format === 'csv') {
|
||||
// Simple CSV conversion (you might want to use a library for production)
|
||||
if (result.data.length === 0) {
|
||||
content = '';
|
||||
} else {
|
||||
const headers = Object.keys(result.data[0]);
|
||||
const rows = result.data.map((item: any) =>
|
||||
headers.map(header => JSON.stringify(item[header] ?? '')).join(',')
|
||||
);
|
||||
content = [headers.join(','), ...rows].join('\n');
|
||||
}
|
||||
} else {
|
||||
content = JSON.stringify(result.data, null, 2);
|
||||
}
|
||||
|
||||
await fs.writeFile(filepath, content, 'utf-8');
|
||||
|
||||
// Also save metadata
|
||||
const metadataPath = path.join(this.config.outputDir, `${name}.metadata.json`);
|
||||
await fs.writeFile(
|
||||
metadataPath,
|
||||
JSON.stringify(result.metadata, null, 2),
|
||||
'utf-8'
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(`Failed to save ${name}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage in CI/CD pipeline
|
||||
*/
|
||||
async function cicdExample() {
|
||||
// Initialize generator
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: './test-fixtures',
|
||||
format: 'json',
|
||||
provider: 'gemini',
|
||||
seed: process.env.CI_COMMIT_SHA || 'default-seed' // Use commit SHA for reproducibility
|
||||
});
|
||||
|
||||
// Generate all test data
|
||||
await generator.generateAll({
|
||||
users: 50,
|
||||
posts: 200,
|
||||
comments: 500,
|
||||
orders: 100,
|
||||
products: 75,
|
||||
apiMocks: 10,
|
||||
sessions: 30,
|
||||
loadTestRequests: 5000
|
||||
});
|
||||
|
||||
console.log('Test data ready for CI/CD pipeline');
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub Actions example
|
||||
*/
|
||||
async function githubActionsExample() {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: process.env.GITHUB_WORKSPACE + '/test-data',
|
||||
seed: process.env.GITHUB_SHA
|
||||
});
|
||||
|
||||
await generator.generateDatabaseFixtures();
|
||||
await generator.generateAPIMockResponses();
|
||||
}
|
||||
|
||||
/**
|
||||
* GitLab CI example
|
||||
*/
|
||||
async function gitlabCIExample() {
|
||||
const generator = new CICDTestDataGenerator({
|
||||
outputDir: process.env.CI_PROJECT_DIR + '/test-data',
|
||||
seed: process.env.CI_COMMIT_SHORT_SHA
|
||||
});
|
||||
|
||||
await generator.generateAll();
|
||||
}
|
||||
|
||||
// Export for use in CI/CD scripts
|
||||
export {
|
||||
cicdExample,
|
||||
githubActionsExample,
|
||||
gitlabCIExample
|
||||
};
|
||||
|
||||
// Run if called directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
cicdExample().catch(console.error);
|
||||
}
|
||||
Reference in New Issue
Block a user