synthra 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +40 -0
- data/.yardopts +18 -0
- data/ACCESS_DOCS.md +116 -0
- data/ADVANCED_FEATURES_SUMMARY.md +245 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +307 -0
- data/DOCUMENTATION.md +204 -0
- data/DOCUMENTATION_GUIDE.md +194 -0
- data/LICENSE +22 -0
- data/README.md +1458 -0
- data/Rakefile +128 -0
- data/benchmark/README.md +591 -0
- data/benchmark/batch_generation.rb +63 -0
- data/benchmark/engine_comparison.rb +295 -0
- data/benchmark/single_record.rb +108 -0
- data/benchmark/streaming.rb +74 -0
- data/docs/ACTIVERECORD_INFERENCE.md +524 -0
- data/docs/API_SERVER.md +278 -0
- data/docs/CONFIG_FILE.md +315 -0
- data/docs/DATA_CONTRACTS.md +312 -0
- data/docs/ENHANCED_REPL.md +304 -0
- data/docs/FACTORY_BOT.md +271 -0
- data/docs/GITHUB_ACTION.md +420 -0
- data/docs/GRAPHQL_EXPORT.md +303 -0
- data/docs/GRAPHQL_FEDERATION.md +651 -0
- data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
- data/docs/LSP.md +189 -0
- data/docs/MIGRATION_GENERATOR.md +547 -0
- data/docs/MOCK_SERVER.md +280 -0
- data/docs/NATIVE_ENGINE.md +298 -0
- data/docs/OPENAPI_EXPORT.md +252 -0
- data/docs/PERFORMANCE_MODE.md +228 -0
- data/docs/PERSONAS.md +547 -0
- data/docs/PROPERTY_TESTING.md +284 -0
- data/docs/PROTOBUF_EXPORT.md +276 -0
- data/docs/QUALITY_METRICS.md +555 -0
- data/docs/QUICK_REFERENCE.md +88 -0
- data/docs/RAILS_ENGINE.md +404 -0
- data/docs/RAILS_INTEGRATION.md +454 -0
- data/docs/README.md +175 -0
- data/docs/REPL_QUICK_REFERENCE.md +149 -0
- data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
- data/docs/SCENARIOS.md +576 -0
- data/docs/SECURITY_TESTING.md +318 -0
- data/docs/SNAPSHOT_TESTING.md +308 -0
- data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
- data/docs/TERRAFORM_EXPORT.md +447 -0
- data/docs/TIME_TRAVEL.md +507 -0
- data/docs/USAGE_GUIDE.md +980 -0
- data/docs/WEBHOOK_SIMULATOR.md +579 -0
- data/docs/advanced_features.md +183 -0
- data/docs/api_reference.md +153 -0
- data/docs/behaviors.md +138 -0
- data/docs/best_practices.md +191 -0
- data/docs/dsl_reference.md +172 -0
- data/docs/examples.md +162 -0
- data/docs/generation_modes.md +125 -0
- data/docs/getting_started.md +92 -0
- data/docs/index.html +177 -0
- data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
- data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
- data/docs/troubleshooting.md +215 -0
- data/docs/type_reference.md +224 -0
- data/examples/hostile_mode_demo.rb +64 -0
- data/exe/synthra +6 -0
- data/ext/synthra_native/Cargo.lock +972 -0
- data/ext/synthra_native/Cargo.toml +46 -0
- data/ext/synthra_native/extconf.rb +41 -0
- data/ext/synthra_native/src/generator.rs +397 -0
- data/ext/synthra_native/src/lib.rs +229 -0
- data/ext/synthra_native/src/types.rs +1485 -0
- data/lib/generators/synthra/install_generator.rb +86 -0
- data/lib/generators/synthra/templates/api_response.dsl +15 -0
- data/lib/generators/synthra/templates/fake_data.rake +116 -0
- data/lib/generators/synthra/templates/synthra.yml +31 -0
- data/lib/generators/synthra/templates/synthra_support.rb +19 -0
- data/lib/generators/synthra/templates/user.dsl +11 -0
- data/lib/synthra/activerecord_inference.rb +394 -0
- data/lib/synthra/api.rb +381 -0
- data/lib/synthra/api_server.rb +718 -0
- data/lib/synthra/behaviors/applicator.rb +165 -0
- data/lib/synthra/behaviors/base.rb +155 -0
- data/lib/synthra/behaviors/close_connection.rb +60 -0
- data/lib/synthra/behaviors/deprecated.rb +100 -0
- data/lib/synthra/behaviors/failure.rb +69 -0
- data/lib/synthra/behaviors/latency.rb +103 -0
- data/lib/synthra/behaviors/partial_data.rb +83 -0
- data/lib/synthra/behaviors/randomize_order.rb +74 -0
- data/lib/synthra/behaviors/registry.rb +238 -0
- data/lib/synthra/behaviors/simulate_error.rb +79 -0
- data/lib/synthra/cli/commands/base.rb +105 -0
- data/lib/synthra/cli/commands/diff.rb +227 -0
- data/lib/synthra/cli/commands/docs.rb +67 -0
- data/lib/synthra/cli/commands/export.rb +150 -0
- data/lib/synthra/cli/commands/generate.rb +72 -0
- data/lib/synthra/cli/commands/import.rb +80 -0
- data/lib/synthra/cli/commands/lint.rb +53 -0
- data/lib/synthra/cli/commands/live.rb +57 -0
- data/lib/synthra/cli/commands/seed.rb +99 -0
- data/lib/synthra/cli/commands/validate.rb +28 -0
- data/lib/synthra/cli.rb +2471 -0
- data/lib/synthra/config_file.rb +129 -0
- data/lib/synthra/configuration.rb +281 -0
- data/lib/synthra/contracts_registry.rb +408 -0
- data/lib/synthra/database_seeder.rb +268 -0
- data/lib/synthra/deterministic_ids.rb +218 -0
- data/lib/synthra/documentation_generator.rb +414 -0
- data/lib/synthra/engine.rb +251 -0
- data/lib/synthra/errors.rb +1169 -0
- data/lib/synthra/export/base.rb +85 -0
- data/lib/synthra/export/csv.rb +101 -0
- data/lib/synthra/export/graphql.rb +266 -0
- data/lib/synthra/export/graphql_federation.rb +377 -0
- data/lib/synthra/export/graphviz.rb +258 -0
- data/lib/synthra/export/javascript.rb +327 -0
- data/lib/synthra/export/json_data.rb +61 -0
- data/lib/synthra/export/json_schema.rb +290 -0
- data/lib/synthra/export/openapi.rb +514 -0
- data/lib/synthra/export/protobuf.rb +483 -0
- data/lib/synthra/export/python.rb +560 -0
- data/lib/synthra/export/sql.rb +381 -0
- data/lib/synthra/export/sql_insert.rb +152 -0
- data/lib/synthra/export/terraform.rb +501 -0
- data/lib/synthra/export/type_mapping.rb +389 -0
- data/lib/synthra/export/typescript.rb +300 -0
- data/lib/synthra/export/xml_data.rb +104 -0
- data/lib/synthra/export/yaml_data.rb +56 -0
- data/lib/synthra/export.rb +404 -0
- data/lib/synthra/factory_bot_integration.rb +157 -0
- data/lib/synthra/field.rb +440 -0
- data/lib/synthra/functions/registry.rb +104 -0
- data/lib/synthra/generator/context.rb +372 -0
- data/lib/synthra/generator/engine.rb +336 -0
- data/lib/synthra/generator/faker_adapter.rb +425 -0
- data/lib/synthra/generator/modes.rb +444 -0
- data/lib/synthra/generator/resolver.rb +256 -0
- data/lib/synthra/generator/rng.rb +273 -0
- data/lib/synthra/generator/streamer.rb +63 -0
- data/lib/synthra/generator/uniqueness.rb +118 -0
- data/lib/synthra/initializer.rb +97 -0
- data/lib/synthra/limits.rb +279 -0
- data/lib/synthra/live_preview.rb +518 -0
- data/lib/synthra/loader_config.rb +78 -0
- data/lib/synthra/lsp/server.rb +689 -0
- data/lib/synthra/migration_generator.rb +301 -0
- data/lib/synthra/mixin.rb +174 -0
- data/lib/synthra/mock_server.rb +458 -0
- data/lib/synthra/native_engine.rb +304 -0
- data/lib/synthra/openapi_importer.rb +228 -0
- data/lib/synthra/output/json_formatter.rb +40 -0
- data/lib/synthra/output/ndjson_formatter.rb +55 -0
- data/lib/synthra/parser/ast.rb +1287 -0
- data/lib/synthra/parser/lexer.rb +1152 -0
- data/lib/synthra/parser/parser.rb +1664 -0
- data/lib/synthra/parser/tokens.rb +461 -0
- data/lib/synthra/performance_mode.rb +364 -0
- data/lib/synthra/personas.rb +397 -0
- data/lib/synthra/property_testing.rb +172 -0
- data/lib/synthra/quality_metrics.rb +405 -0
- data/lib/synthra/rails_test_helper.rb +248 -0
- data/lib/synthra/registry.rb +533 -0
- data/lib/synthra/relationships.rb +193 -0
- data/lib/synthra/repl/enhanced_repl.rb +607 -0
- data/lib/synthra/repl/formatter.rb +191 -0
- data/lib/synthra/scenarios.rb +423 -0
- data/lib/synthra/schema.rb +605 -0
- data/lib/synthra/schema_inheritance.rb +104 -0
- data/lib/synthra/schema_versioning.rb +212 -0
- data/lib/synthra/snapshot_testing.rb +199 -0
- data/lib/synthra/time_travel.rb +338 -0
- data/lib/synthra/type_definitions.rb +274 -0
- data/lib/synthra/types/address_location/addresses.rb +125 -0
- data/lib/synthra/types/address_location/airports.rb +200 -0
- data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
- data/lib/synthra/types/address_location/locations.rb +406 -0
- data/lib/synthra/types/base.rb +48 -0
- data/lib/synthra/types/commerce_products/commerce.rb +119 -0
- data/lib/synthra/types/commerce_products/companies.rb +71 -0
- data/lib/synthra/types/commerce_products/construction.rb +126 -0
- data/lib/synthra/types/commerce_products/products.rb +205 -0
- data/lib/synthra/types/core/collections.rb +513 -0
- data/lib/synthra/types/core/defaults.rb +76 -0
- data/lib/synthra/types/core/enums.rb +102 -0
- data/lib/synthra/types/core/identifiers.rb +445 -0
- data/lib/synthra/types/core/primitives.rb +586 -0
- data/lib/synthra/types/core/references.rb +466 -0
- data/lib/synthra/types/core/sequences.rb +304 -0
- data/lib/synthra/types/crypto/crypto.rb +162 -0
- data/lib/synthra/types/date_time/dates.rb +387 -0
- data/lib/synthra/types/finance_banking/banking.rb +424 -0
- data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
- data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
- data/lib/synthra/types/formula.rb +184 -0
- data/lib/synthra/types/health_medical/medical.rb +150 -0
- data/lib/synthra/types/hostile_payloads.rb +122 -0
- data/lib/synthra/types/json_array.rb +51 -0
- data/lib/synthra/types/media_entertainment/media.rb +62 -0
- data/lib/synthra/types/naughty_string.rb +30 -0
- data/lib/synthra/types/personal_names/chinese.rb +41 -0
- data/lib/synthra/types/personal_names/identifiers.rb +187 -0
- data/lib/synthra/types/personal_names/names.rb +246 -0
- data/lib/synthra/types/personal_names/national_id.rb +89 -0
- data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
- data/lib/synthra/types/regex.rb +248 -0
- data/lib/synthra/types/registry.rb +182 -0
- data/lib/synthra/types/repeating_element.rb +50 -0
- data/lib/synthra/types/scenario.rb +29 -0
- data/lib/synthra/types/technology_internet/apps.rb +67 -0
- data/lib/synthra/types/technology_internet/communication.rb +162 -0
- data/lib/synthra/types/technology_internet/devices.rb +80 -0
- data/lib/synthra/types/technology_internet/formats.rb +139 -0
- data/lib/synthra/types/technology_internet/networking.rb +143 -0
- data/lib/synthra/types/template.rb +92 -0
- data/lib/synthra/types/text_content/business.rb +128 -0
- data/lib/synthra/types/text_content/colors.rb +70 -0
- data/lib/synthra/types/text_content/misc.rb +237 -0
- data/lib/synthra/types/text_content/security.rb +130 -0
- data/lib/synthra/types/text_content/text_generation.rb +532 -0
- data/lib/synthra/types/travel/travel.rb +150 -0
- data/lib/synthra/utils/string_distance.rb +133 -0
- data/lib/synthra/validator/dsl_validator.rb +339 -0
- data/lib/synthra/validator/path_validator.rb +615 -0
- data/lib/synthra/version.rb +35 -0
- data/lib/synthra/webhook_simulator.rb +341 -0
- data/lib/synthra.rb +259 -0
- data/schemas/address.dsl +16 -0
- data/schemas/api_response.dsl +8 -0
- data/schemas/error_payload.dsl +9 -0
- data/schemas/order.dsl +10 -0
- data/schemas/order_item.dsl +8 -0
- data/schemas/payment.dsl +11 -0
- data/schemas/social_post.dsl +13 -0
- data/schemas/user.dsl +10 -0
- data/scripts/batch_fix_all.rb +96 -0
- data/scripts/delete_old_files.rb +32 -0
- data/scripts/fix_all_grouped_files.rb +137 -0
- data/scripts/fix_all_indentation.rb +48 -0
- data/scripts/fix_all_syntax.rb +124 -0
- data/scripts/fix_grouped_files.rb +184 -0
- data/scripts/fix_syntax_errors.rb +108 -0
- data/scripts/group_domain_types.rb +112 -0
- data/scripts/group_domain_types_fixed.rb +150 -0
- data/scripts/merge_domains_to_one_file.rb +68 -0
- data/scripts/move_existing_types.rb +130 -0
- data/scripts/split_grouped_types.rb +142 -0
- data/tech_docs/README.md +134 -0
- data/tech_docs/advanced/streaming.md +405 -0
- data/tech_docs/advanced/thread_safety.md +253 -0
- data/tech_docs/api/overview.md +485 -0
- data/tech_docs/appendices/type_chart.md +193 -0
- data/tech_docs/basic_concepts.md +383 -0
- data/tech_docs/behaviors/overview.md +346 -0
- data/tech_docs/dsl/complex_types.md +790 -0
- data/tech_docs/dsl/core_types.md +464 -0
- data/tech_docs/dsl/datetime_types.md +325 -0
- data/tech_docs/dsl/field_modifiers.md +414 -0
- data/tech_docs/dsl/grammar.md +431 -0
- data/tech_docs/dsl/schema_definition.md +399 -0
- data/tech_docs/export/README.md +276 -0
- data/tech_docs/installation.md +273 -0
- data/tech_docs/integration/ci_cd.md +707 -0
- data/tech_docs/integration/ci_cd_guide.md +579 -0
- data/tech_docs/integration/factory_bot.md +485 -0
- data/tech_docs/integration/rails.md +630 -0
- data/tech_docs/integration/rspec.md +449 -0
- data/tech_docs/modes/overview.md +350 -0
- data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
- data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
- data/tech_docs/quick_start.md +256 -0
- data/tech_docs/templates/README.md +805 -0
- data/tech_docs/tutorials/advanced.md +371 -0
- data/tech_docs/tutorials/getting_started.md +189 -0
- data/tech_docs/tutorials/intermediate.md +231 -0
- data/tech_docs/tutorials/template_gallery.md +569 -0
- data/tech_example/01_basic_usage.rb +238 -0
- data/tech_example/02_types_demo.rb +336 -0
- data/tech_example/04_cli_usage.md +429 -0
- data/tech_example/05_database_seeding.rb +283 -0
- data/tech_example/07_rspec_integration.rb +359 -0
- data/tech_example/10_custom_types.rb +387 -0
- data/tech_example/12_behaviors.rb +372 -0
- data/tech_example/13_twitter_dm_example.rb +120 -0
- data/tech_example/14_exact_json_structure.rb +253 -0
- data/tech_example/16_lsp_server.rb +56 -0
- data/tech_example/17_property_testing.rb +92 -0
- data/tech_example/18_enhanced_repl.rb +120 -0
- data/tech_example/19_security_fuzzing.rb +145 -0
- data/tech_example/NEW_FEATURES.md +169 -0
- data/tech_example/README.md +118 -0
- data/tech_example/schemas/api_response.dsl +123 -0
- data/tech_example/schemas/ecommerce.dsl +121 -0
- data/tech_example/schemas/twitter_dm.dsl +109 -0
- data/tech_example/schemas/user.dsl +36 -0
- data/vscode-extension/README.md +246 -0
- data/vscode-extension/language-configuration.json +31 -0
- data/vscode-extension/package.json +55 -0
- data/vscode-extension/snippets/fakedatadsl.json +198 -0
- data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
- metadata +478 -0
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
# Webhook Simulation
|
|
2
|
+
|
|
3
|
+
FakeDataDSL's Webhook Simulator lets you **send realistic webhook payloads** to your application, simulating events from external services like Stripe, GitHub, Twilio, and more.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Configure the simulator
|
|
9
|
+
FakeDataDSL::WebhookSimulator.configure do |config|
|
|
10
|
+
config.endpoint = "http://localhost:3000/webhooks"
|
|
11
|
+
config.secret = "whsec_your_webhook_secret"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Send a webhook
|
|
15
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
16
|
+
"stripe.payment_intent.succeeded",
|
|
17
|
+
schema: "StripePaymentIntent"
|
|
18
|
+
)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Basic Usage
|
|
22
|
+
|
|
23
|
+
### Simple Webhook
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
# Send webhook with generated data
|
|
27
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
28
|
+
"user.created",
|
|
29
|
+
schema: "User"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# With custom payload overrides
|
|
33
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
34
|
+
"order.completed",
|
|
35
|
+
schema: "Order",
|
|
36
|
+
data: { status: "completed", total: 99.99 }
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### With Delay
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
# Simulate network latency
|
|
44
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
45
|
+
"payment.failed",
|
|
46
|
+
schema: "PaymentEvent",
|
|
47
|
+
delay: 2.seconds
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Batch Webhooks
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
# Send multiple webhooks in sequence
|
|
55
|
+
FakeDataDSL::WebhookSimulator.send_batch([
|
|
56
|
+
{ event: "order.created", schema: "Order" },
|
|
57
|
+
{ event: "payment.processing", schema: "Payment", delay: 1.second },
|
|
58
|
+
{ event: "payment.succeeded", schema: "Payment", delay: 2.seconds },
|
|
59
|
+
{ event: "order.completed", schema: "Order", delay: 3.seconds }
|
|
60
|
+
])
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
### Global Configuration
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
FakeDataDSL::WebhookSimulator.configure do |config|
|
|
69
|
+
# Target endpoint
|
|
70
|
+
config.endpoint = "http://localhost:3000/webhooks"
|
|
71
|
+
|
|
72
|
+
# Webhook secret for signatures
|
|
73
|
+
config.secret = ENV["WEBHOOK_SECRET"]
|
|
74
|
+
|
|
75
|
+
# Default headers
|
|
76
|
+
config.headers = {
|
|
77
|
+
"Content-Type" => "application/json",
|
|
78
|
+
"User-Agent" => "FakeDataDSL-WebhookSimulator/1.0"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Timeout settings
|
|
82
|
+
config.timeout = 30
|
|
83
|
+
config.open_timeout = 5
|
|
84
|
+
|
|
85
|
+
# Retry settings
|
|
86
|
+
config.max_retries = 3
|
|
87
|
+
config.retry_delay = 1.second
|
|
88
|
+
|
|
89
|
+
# Logging
|
|
90
|
+
config.logger = Rails.logger
|
|
91
|
+
config.log_level = :info
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Per-Request Configuration
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
99
|
+
"event.name",
|
|
100
|
+
schema: "Schema",
|
|
101
|
+
config: {
|
|
102
|
+
endpoint: "http://different-endpoint.com/hooks",
|
|
103
|
+
secret: "different_secret",
|
|
104
|
+
timeout: 60
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Webhook Signatures
|
|
110
|
+
|
|
111
|
+
### Automatic Signing
|
|
112
|
+
|
|
113
|
+
Webhooks are automatically signed based on the provider type:
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
# Stripe-style signature (HMAC-SHA256)
|
|
117
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
118
|
+
"payment_intent.succeeded",
|
|
119
|
+
schema: "StripePayment",
|
|
120
|
+
signature_type: :stripe
|
|
121
|
+
)
|
|
122
|
+
# Adds: Stripe-Signature: t=1234567890,v1=abc123...
|
|
123
|
+
|
|
124
|
+
# GitHub-style signature
|
|
125
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
126
|
+
"push",
|
|
127
|
+
schema: "GitHubPush",
|
|
128
|
+
signature_type: :github
|
|
129
|
+
)
|
|
130
|
+
# Adds: X-Hub-Signature-256: sha256=abc123...
|
|
131
|
+
|
|
132
|
+
# Custom signature
|
|
133
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
134
|
+
"custom.event",
|
|
135
|
+
schema: "Custom",
|
|
136
|
+
signature: ->(payload, secret) {
|
|
137
|
+
OpenSSL::HMAC.hexdigest("SHA512", secret, payload)
|
|
138
|
+
},
|
|
139
|
+
signature_header: "X-Custom-Signature"
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Supported Signature Types
|
|
144
|
+
|
|
145
|
+
| Provider | Type | Header |
|
|
146
|
+
|----------|------|--------|
|
|
147
|
+
| Stripe | `:stripe` | `Stripe-Signature` |
|
|
148
|
+
| GitHub | `:github` | `X-Hub-Signature-256` |
|
|
149
|
+
| Twilio | `:twilio` | `X-Twilio-Signature` |
|
|
150
|
+
| Shopify | `:shopify` | `X-Shopify-Hmac-SHA256` |
|
|
151
|
+
| Custom | `:custom` | Configurable |
|
|
152
|
+
|
|
153
|
+
## Provider Presets
|
|
154
|
+
|
|
155
|
+
### Stripe
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
FakeDataDSL::WebhookSimulator.stripe(
|
|
159
|
+
"payment_intent.succeeded",
|
|
160
|
+
data: {
|
|
161
|
+
amount: 2000,
|
|
162
|
+
currency: "usd",
|
|
163
|
+
customer: "cus_123"
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Uses built-in Stripe event schemas
|
|
168
|
+
# Automatically formats as Stripe webhook structure:
|
|
169
|
+
# {
|
|
170
|
+
# "id": "evt_...",
|
|
171
|
+
# "object": "event",
|
|
172
|
+
# "type": "payment_intent.succeeded",
|
|
173
|
+
# "data": { "object": { ... } }
|
|
174
|
+
# }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### GitHub
|
|
178
|
+
|
|
179
|
+
```ruby
|
|
180
|
+
FakeDataDSL::WebhookSimulator.github(
|
|
181
|
+
"push",
|
|
182
|
+
repository: "owner/repo",
|
|
183
|
+
data: {
|
|
184
|
+
ref: "refs/heads/main",
|
|
185
|
+
commits: [{ message: "Update README" }]
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Twilio
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
FakeDataDSL::WebhookSimulator.twilio(
|
|
194
|
+
"message.received",
|
|
195
|
+
data: {
|
|
196
|
+
from: "+15551234567",
|
|
197
|
+
body: "Hello, world!"
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Custom Provider
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
FakeDataDSL::WebhookSimulator.register_provider(:my_service) do |config|
|
|
206
|
+
config.base_url = "https://my-service.com"
|
|
207
|
+
config.signature_type = :hmac_sha256
|
|
208
|
+
config.signature_header = "X-MyService-Signature"
|
|
209
|
+
config.event_wrapper = ->(event, data) {
|
|
210
|
+
{
|
|
211
|
+
event_type: event,
|
|
212
|
+
timestamp: Time.current.iso8601,
|
|
213
|
+
payload: data
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Use registered provider
|
|
219
|
+
FakeDataDSL::WebhookSimulator.my_service(
|
|
220
|
+
"user.updated",
|
|
221
|
+
schema: "User"
|
|
222
|
+
)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Event Sequences
|
|
226
|
+
|
|
227
|
+
### Define Sequences
|
|
228
|
+
|
|
229
|
+
```ruby
|
|
230
|
+
# Define a sequence of related events
|
|
231
|
+
FakeDataDSL::WebhookSimulator.define_sequence(:checkout_flow) do
|
|
232
|
+
# Step 1: Cart created
|
|
233
|
+
step "cart.created", schema: "Cart"
|
|
234
|
+
|
|
235
|
+
# Step 2: Payment initiated (after 1 second)
|
|
236
|
+
step "payment.initiated", schema: "Payment", delay: 1.second
|
|
237
|
+
|
|
238
|
+
# Step 3: Payment succeeded (after 2 more seconds)
|
|
239
|
+
step "payment.succeeded", schema: "Payment", delay: 2.seconds
|
|
240
|
+
|
|
241
|
+
# Step 4: Order created
|
|
242
|
+
step "order.created", schema: "Order", delay: 500.milliseconds
|
|
243
|
+
|
|
244
|
+
# Step 5: Email sent
|
|
245
|
+
step "notification.sent", schema: "Notification", delay: 1.second
|
|
246
|
+
end
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Run Sequences
|
|
250
|
+
|
|
251
|
+
```ruby
|
|
252
|
+
# Run the sequence
|
|
253
|
+
FakeDataDSL::WebhookSimulator.run_sequence(:checkout_flow)
|
|
254
|
+
|
|
255
|
+
# Run with shared context (data passed between steps)
|
|
256
|
+
FakeDataDSL::WebhookSimulator.run_sequence(:checkout_flow,
|
|
257
|
+
context: { user_id: "user_123", amount: 99.99 }
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# Run with callbacks
|
|
261
|
+
FakeDataDSL::WebhookSimulator.run_sequence(:checkout_flow) do |step, response|
|
|
262
|
+
puts "Step #{step.name}: #{response.status}"
|
|
263
|
+
end
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Conditional Steps
|
|
267
|
+
|
|
268
|
+
```ruby
|
|
269
|
+
FakeDataDSL::WebhookSimulator.define_sequence(:payment_flow) do
|
|
270
|
+
step "payment.initiated", schema: "Payment"
|
|
271
|
+
|
|
272
|
+
# Branch based on previous response
|
|
273
|
+
branch do |context|
|
|
274
|
+
if context[:payment_method] == "card"
|
|
275
|
+
step "payment.card.processing", schema: "CardPayment"
|
|
276
|
+
else
|
|
277
|
+
step "payment.bank.processing", schema: "BankPayment"
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
step "payment.completed", schema: "Payment"
|
|
282
|
+
end
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Testing Integration
|
|
286
|
+
|
|
287
|
+
### RSpec Helpers
|
|
288
|
+
|
|
289
|
+
```ruby
|
|
290
|
+
# spec/rails_helper.rb
|
|
291
|
+
require 'fake_data_dsl/webhook_simulator/rspec'
|
|
292
|
+
|
|
293
|
+
RSpec.configure do |config|
|
|
294
|
+
config.include FakeDataDSL::WebhookSimulator::RSpecHelpers
|
|
295
|
+
end
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
```ruby
|
|
299
|
+
# spec/webhooks/stripe_spec.rb
|
|
300
|
+
RSpec.describe "Stripe Webhooks", type: :request do
|
|
301
|
+
it "handles payment_intent.succeeded" do
|
|
302
|
+
simulate_webhook "stripe.payment_intent.succeeded",
|
|
303
|
+
schema: "StripePayment",
|
|
304
|
+
data: { amount: 5000 }
|
|
305
|
+
|
|
306
|
+
expect(response).to have_http_status(:ok)
|
|
307
|
+
expect(Payment.last.amount).to eq(50.00)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
it "handles the full checkout sequence" do
|
|
311
|
+
simulate_webhook_sequence :checkout_flow
|
|
312
|
+
|
|
313
|
+
expect(Order.count).to eq(1)
|
|
314
|
+
expect(Order.last.status).to eq("completed")
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Minitest Helpers
|
|
320
|
+
|
|
321
|
+
```ruby
|
|
322
|
+
# test/test_helper.rb
|
|
323
|
+
require 'fake_data_dsl/webhook_simulator/minitest'
|
|
324
|
+
|
|
325
|
+
class ActiveSupport::TestCase
|
|
326
|
+
include FakeDataDSL::WebhookSimulator::MinitestHelpers
|
|
327
|
+
end
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
```ruby
|
|
331
|
+
# test/integration/webhooks_test.rb
|
|
332
|
+
class WebhooksTest < ActionDispatch::IntegrationTest
|
|
333
|
+
test "handles stripe webhook" do
|
|
334
|
+
simulate_webhook "stripe.payment_intent.succeeded",
|
|
335
|
+
schema: "StripePayment"
|
|
336
|
+
|
|
337
|
+
assert_response :success
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Error Simulation
|
|
343
|
+
|
|
344
|
+
### Simulate Failures
|
|
345
|
+
|
|
346
|
+
```ruby
|
|
347
|
+
# Simulate webhook delivery failure
|
|
348
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
349
|
+
"event.name",
|
|
350
|
+
schema: "Schema",
|
|
351
|
+
simulate_failure: true # Returns 500 error simulation
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Simulate timeout
|
|
355
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
356
|
+
"event.name",
|
|
357
|
+
schema: "Schema",
|
|
358
|
+
simulate_timeout: true
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
# Simulate partial failure (intermittent)
|
|
362
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
363
|
+
"event.name",
|
|
364
|
+
schema: "Schema",
|
|
365
|
+
failure_rate: 0.3 # 30% chance of failure
|
|
366
|
+
)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Retry Testing
|
|
370
|
+
|
|
371
|
+
```ruby
|
|
372
|
+
# Test retry behavior
|
|
373
|
+
FakeDataDSL::WebhookSimulator.send(
|
|
374
|
+
"event.name",
|
|
375
|
+
schema: "Schema",
|
|
376
|
+
fail_first_n: 2 # Fail first 2 attempts, succeed on 3rd
|
|
377
|
+
)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Recording and Replay
|
|
381
|
+
|
|
382
|
+
### Record Webhooks
|
|
383
|
+
|
|
384
|
+
```ruby
|
|
385
|
+
# Record all webhooks sent
|
|
386
|
+
FakeDataDSL::WebhookSimulator.start_recording
|
|
387
|
+
|
|
388
|
+
# ... send webhooks ...
|
|
389
|
+
|
|
390
|
+
# Stop and save
|
|
391
|
+
recordings = FakeDataDSL::WebhookSimulator.stop_recording
|
|
392
|
+
recordings.save_to("spec/fixtures/webhooks/checkout_flow.json")
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Replay Recordings
|
|
396
|
+
|
|
397
|
+
```ruby
|
|
398
|
+
# Replay recorded webhooks
|
|
399
|
+
FakeDataDSL::WebhookSimulator.replay("spec/fixtures/webhooks/checkout_flow.json")
|
|
400
|
+
|
|
401
|
+
# With timing
|
|
402
|
+
FakeDataDSL::WebhookSimulator.replay("recordings.json",
|
|
403
|
+
preserve_timing: true # Replay with original delays
|
|
404
|
+
)
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## CLI Commands
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# Send single webhook
|
|
411
|
+
fake_data_dsl webhook send user.created \
|
|
412
|
+
--schema User \
|
|
413
|
+
--endpoint http://localhost:3000/webhooks \
|
|
414
|
+
--secret whsec_xxx
|
|
415
|
+
|
|
416
|
+
# Send with data override
|
|
417
|
+
fake_data_dsl webhook send payment.succeeded \
|
|
418
|
+
--schema Payment \
|
|
419
|
+
--data '{"amount": 9999}' \
|
|
420
|
+
--endpoint http://localhost:3000/webhooks
|
|
421
|
+
|
|
422
|
+
# Run sequence
|
|
423
|
+
fake_data_dsl webhook sequence checkout_flow \
|
|
424
|
+
--endpoint http://localhost:3000/webhooks
|
|
425
|
+
|
|
426
|
+
# Record mode
|
|
427
|
+
fake_data_dsl webhook record \
|
|
428
|
+
--output recordings/session.json \
|
|
429
|
+
--duration 60 # Record for 60 seconds
|
|
430
|
+
|
|
431
|
+
# Replay recordings
|
|
432
|
+
fake_data_dsl webhook replay recordings/session.json \
|
|
433
|
+
--endpoint http://localhost:3000/webhooks
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## API Reference
|
|
437
|
+
|
|
438
|
+
### WebhookSimulator.send
|
|
439
|
+
|
|
440
|
+
```ruby
|
|
441
|
+
FakeDataDSL::WebhookSimulator.send(event_name, options = {})
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Parameters:**
|
|
445
|
+
- `event_name` - Event type string (e.g., "user.created")
|
|
446
|
+
- `options[:schema]` - Schema name for payload generation
|
|
447
|
+
- `options[:data]` - Override data
|
|
448
|
+
- `options[:delay]` - Delay before sending
|
|
449
|
+
- `options[:endpoint]` - Override endpoint
|
|
450
|
+
- `options[:secret]` - Override secret
|
|
451
|
+
- `options[:signature_type]` - Signature type
|
|
452
|
+
- `options[:headers]` - Additional headers
|
|
453
|
+
- `options[:config]` - Full config override
|
|
454
|
+
|
|
455
|
+
**Returns:** `WebhookResponse` object
|
|
456
|
+
|
|
457
|
+
### WebhookSimulator.send_batch
|
|
458
|
+
|
|
459
|
+
```ruby
|
|
460
|
+
FakeDataDSL::WebhookSimulator.send_batch(webhooks)
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**Parameters:**
|
|
464
|
+
- `webhooks` - Array of webhook configurations
|
|
465
|
+
|
|
466
|
+
**Returns:** Array of `WebhookResponse` objects
|
|
467
|
+
|
|
468
|
+
### WebhookSimulator.define_sequence
|
|
469
|
+
|
|
470
|
+
```ruby
|
|
471
|
+
FakeDataDSL::WebhookSimulator.define_sequence(name, &block)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**Parameters:**
|
|
475
|
+
- `name` - Sequence name
|
|
476
|
+
- `block` - Sequence definition block
|
|
477
|
+
|
|
478
|
+
### WebhookSimulator.run_sequence
|
|
479
|
+
|
|
480
|
+
```ruby
|
|
481
|
+
FakeDataDSL::WebhookSimulator.run_sequence(name, options = {}, &callback)
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Parameters:**
|
|
485
|
+
- `name` - Sequence name
|
|
486
|
+
- `options[:context]` - Shared context data
|
|
487
|
+
- `callback` - Optional callback for each step
|
|
488
|
+
|
|
489
|
+
**Returns:** Array of `WebhookResponse` objects
|
|
490
|
+
|
|
491
|
+
## Best Practices
|
|
492
|
+
|
|
493
|
+
### 1. Use Consistent Secrets
|
|
494
|
+
|
|
495
|
+
```ruby
|
|
496
|
+
# config/environments/test.rb
|
|
497
|
+
ENV["WEBHOOK_SECRET"] = "test_webhook_secret"
|
|
498
|
+
|
|
499
|
+
# spec/rails_helper.rb
|
|
500
|
+
FakeDataDSL::WebhookSimulator.configure do |config|
|
|
501
|
+
config.secret = ENV["WEBHOOK_SECRET"]
|
|
502
|
+
end
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### 2. Test Error Handling
|
|
506
|
+
|
|
507
|
+
```ruby
|
|
508
|
+
it "handles webhook failures gracefully" do
|
|
509
|
+
simulate_webhook "payment.failed",
|
|
510
|
+
schema: "FailedPayment",
|
|
511
|
+
data: { error_code: "card_declined" }
|
|
512
|
+
|
|
513
|
+
expect(response).to have_http_status(:ok)
|
|
514
|
+
expect(Payment.last.status).to eq("failed")
|
|
515
|
+
expect(User.last).to have_received_email(:payment_failed)
|
|
516
|
+
end
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### 3. Use Sequences for Complex Flows
|
|
520
|
+
|
|
521
|
+
```ruby
|
|
522
|
+
# Better than individual webhook tests
|
|
523
|
+
simulate_webhook_sequence :full_order_lifecycle
|
|
524
|
+
|
|
525
|
+
# Instead of:
|
|
526
|
+
simulate_webhook "order.created"
|
|
527
|
+
simulate_webhook "payment.succeeded"
|
|
528
|
+
simulate_webhook "order.shipped"
|
|
529
|
+
simulate_webhook "order.delivered"
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### 4. Record Production Webhooks for Testing
|
|
533
|
+
|
|
534
|
+
```ruby
|
|
535
|
+
# In development, record real webhooks
|
|
536
|
+
# Then replay in tests for realistic scenarios
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
## Troubleshooting
|
|
540
|
+
|
|
541
|
+
### Signature Verification Failing
|
|
542
|
+
|
|
543
|
+
```ruby
|
|
544
|
+
# Make sure secrets match
|
|
545
|
+
FakeDataDSL::WebhookSimulator.configure do |config|
|
|
546
|
+
config.secret = ENV["WEBHOOK_SECRET"] # Same as your app uses
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# Debug signature
|
|
550
|
+
response = FakeDataDSL::WebhookSimulator.send(...)
|
|
551
|
+
puts response.request_headers["Stripe-Signature"]
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Timeout Issues
|
|
555
|
+
|
|
556
|
+
```ruby
|
|
557
|
+
# Increase timeout
|
|
558
|
+
FakeDataDSL::WebhookSimulator.configure do |config|
|
|
559
|
+
config.timeout = 60
|
|
560
|
+
config.open_timeout = 10
|
|
561
|
+
end
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Endpoint Not Reachable
|
|
565
|
+
|
|
566
|
+
```ruby
|
|
567
|
+
# Make sure your server is running
|
|
568
|
+
# In tests, use request specs not system specs
|
|
569
|
+
RSpec.describe "Webhooks", type: :request do
|
|
570
|
+
# This runs against the test server
|
|
571
|
+
end
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
## See Also
|
|
575
|
+
|
|
576
|
+
- [Mock Server](MOCK_SERVER.md)
|
|
577
|
+
- [API Server](API_SERVER.md)
|
|
578
|
+
- [Scenarios](SCENARIOS.md)
|
|
579
|
+
- [Testing Best Practices](best_practices.md)
|