webhookdb 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.
Files changed (364) hide show
  1. checksums.yaml +7 -0
  2. data/data/messages/layouts/blank.email.liquid +10 -0
  3. data/data/messages/layouts/minimal.email.liquid +28 -0
  4. data/data/messages/layouts/standard.email.liquid +28 -0
  5. data/data/messages/partials/button.liquid +15 -0
  6. data/data/messages/partials/environment_banner.liquid +9 -0
  7. data/data/messages/partials/footer.liquid +22 -0
  8. data/data/messages/partials/greeting.liquid +3 -0
  9. data/data/messages/partials/logo_header.liquid +18 -0
  10. data/data/messages/partials/signoff.liquid +1 -0
  11. data/data/messages/styles/v1.liquid +346 -0
  12. data/data/messages/templates/errors/icalendar_fetch.email.liquid +29 -0
  13. data/data/messages/templates/invite.email.liquid +15 -0
  14. data/data/messages/templates/new_customer.email.liquid +24 -0
  15. data/data/messages/templates/org_database_migration_finished.email.liquid +7 -0
  16. data/data/messages/templates/org_database_migration_started.email.liquid +9 -0
  17. data/data/messages/templates/specs/_field_partial.liquid +1 -0
  18. data/data/messages/templates/specs/basic.email.liquid +2 -0
  19. data/data/messages/templates/specs/basic.fake.liquid +1 -0
  20. data/data/messages/templates/specs/with_field.email.liquid +2 -0
  21. data/data/messages/templates/specs/with_field.fake.liquid +1 -0
  22. data/data/messages/templates/specs/with_include.email.liquid +2 -0
  23. data/data/messages/templates/specs/with_partial.email.liquid +1 -0
  24. data/data/messages/templates/verification.email.liquid +14 -0
  25. data/data/messages/templates/verification.sms.liquid +1 -0
  26. data/data/messages/web/install-customer-login.liquid +48 -0
  27. data/data/messages/web/install-error.liquid +17 -0
  28. data/data/messages/web/install-success.liquid +35 -0
  29. data/data/messages/web/install.liquid +20 -0
  30. data/data/messages/web/partials/footer.liquid +4 -0
  31. data/data/messages/web/partials/form_error.liquid +1 -0
  32. data/data/messages/web/partials/header.liquid +3 -0
  33. data/data/messages/web/styles.liquid +134 -0
  34. data/data/windows_tz.txt +461 -0
  35. data/db/migrations/001_testing_pixies.rb +13 -0
  36. data/db/migrations/002_initial.rb +132 -0
  37. data/db/migrations/003_ux_overhaul.rb +20 -0
  38. data/db/migrations/004_incremental_backfill.rb +9 -0
  39. data/db/migrations/005_log_webhooks.rb +24 -0
  40. data/db/migrations/006_generalize_roles.rb +29 -0
  41. data/db/migrations/007_org_dns.rb +12 -0
  42. data/db/migrations/008_webhook_subscriptions.rb +19 -0
  43. data/db/migrations/009_nonunique_stripe_subscription_customer.rb +16 -0
  44. data/db/migrations/010_drop_integration_soft_delete.rb +14 -0
  45. data/db/migrations/011_webhook_subscriptions_created_at.rb +10 -0
  46. data/db/migrations/012_webhook_subscriptions_created_by.rb +9 -0
  47. data/db/migrations/013_default_org_membership.rb +30 -0
  48. data/db/migrations/014_webhook_subscription_deliveries.rb +26 -0
  49. data/db/migrations/015_dependent_integrations.rb +9 -0
  50. data/db/migrations/016_encrypted_columns.rb +9 -0
  51. data/db/migrations/017_skip_verification.rb +9 -0
  52. data/db/migrations/018_sync_targets.rb +25 -0
  53. data/db/migrations/019_org_schema.rb +9 -0
  54. data/db/migrations/020_org_database_migrations.rb +25 -0
  55. data/db/migrations/021_no_default_org_schema.rb +14 -0
  56. data/db/migrations/022_database_document.rb +15 -0
  57. data/db/migrations/023_sync_target_schema.rb +9 -0
  58. data/db/migrations/024_org_semaphore_jobs.rb +9 -0
  59. data/db/migrations/025_integration_backfill_cursor.rb +9 -0
  60. data/db/migrations/026_undo_integration_backfill_cursor.rb +9 -0
  61. data/db/migrations/027_sync_target_http_sync.rb +12 -0
  62. data/db/migrations/028_logged_webhook_path.rb +24 -0
  63. data/db/migrations/029_encrypt_columns.rb +97 -0
  64. data/db/migrations/030_org_sync_target_timeout.rb +9 -0
  65. data/db/migrations/031_org_max_query_rows.rb +9 -0
  66. data/db/migrations/032_remove_db_defaults.rb +12 -0
  67. data/db/migrations/033_backfill_jobs.rb +26 -0
  68. data/db/migrations/034_backfill_job_criteria.rb +9 -0
  69. data/db/migrations/035_synchronous_backfill.rb +9 -0
  70. data/db/migrations/036_oauth.rb +26 -0
  71. data/db/migrations/037_oauth_used.rb +9 -0
  72. data/lib/amigo/durable_job.rb +416 -0
  73. data/lib/pry/clipboard.rb +111 -0
  74. data/lib/sequel/advisory_lock.rb +65 -0
  75. data/lib/webhookdb/admin.rb +4 -0
  76. data/lib/webhookdb/admin_api/auth.rb +36 -0
  77. data/lib/webhookdb/admin_api/customers.rb +63 -0
  78. data/lib/webhookdb/admin_api/database_documents.rb +20 -0
  79. data/lib/webhookdb/admin_api/entities.rb +66 -0
  80. data/lib/webhookdb/admin_api/message_deliveries.rb +61 -0
  81. data/lib/webhookdb/admin_api/roles.rb +15 -0
  82. data/lib/webhookdb/admin_api.rb +34 -0
  83. data/lib/webhookdb/aggregate_result.rb +63 -0
  84. data/lib/webhookdb/api/auth.rb +122 -0
  85. data/lib/webhookdb/api/connstr_auth.rb +36 -0
  86. data/lib/webhookdb/api/db.rb +188 -0
  87. data/lib/webhookdb/api/demo.rb +14 -0
  88. data/lib/webhookdb/api/entities.rb +198 -0
  89. data/lib/webhookdb/api/helpers.rb +253 -0
  90. data/lib/webhookdb/api/install.rb +296 -0
  91. data/lib/webhookdb/api/me.rb +53 -0
  92. data/lib/webhookdb/api/organizations.rb +254 -0
  93. data/lib/webhookdb/api/replay.rb +64 -0
  94. data/lib/webhookdb/api/service_integrations.rb +402 -0
  95. data/lib/webhookdb/api/services.rb +27 -0
  96. data/lib/webhookdb/api/stripe.rb +22 -0
  97. data/lib/webhookdb/api/subscriptions.rb +67 -0
  98. data/lib/webhookdb/api/sync_targets.rb +232 -0
  99. data/lib/webhookdb/api/system.rb +37 -0
  100. data/lib/webhookdb/api/webhook_subscriptions.rb +96 -0
  101. data/lib/webhookdb/api.rb +92 -0
  102. data/lib/webhookdb/apps.rb +93 -0
  103. data/lib/webhookdb/async/audit_logger.rb +38 -0
  104. data/lib/webhookdb/async/autoscaler.rb +84 -0
  105. data/lib/webhookdb/async/job.rb +18 -0
  106. data/lib/webhookdb/async/job_logger.rb +45 -0
  107. data/lib/webhookdb/async/scheduled_job.rb +18 -0
  108. data/lib/webhookdb/async.rb +142 -0
  109. data/lib/webhookdb/aws.rb +98 -0
  110. data/lib/webhookdb/backfill_job.rb +107 -0
  111. data/lib/webhookdb/backfiller.rb +107 -0
  112. data/lib/webhookdb/cloudflare.rb +39 -0
  113. data/lib/webhookdb/connection_cache.rb +177 -0
  114. data/lib/webhookdb/console.rb +71 -0
  115. data/lib/webhookdb/convertkit.rb +14 -0
  116. data/lib/webhookdb/crypto.rb +66 -0
  117. data/lib/webhookdb/customer/reset_code.rb +94 -0
  118. data/lib/webhookdb/customer.rb +347 -0
  119. data/lib/webhookdb/database_document.rb +72 -0
  120. data/lib/webhookdb/db_adapter/column_types.rb +37 -0
  121. data/lib/webhookdb/db_adapter/default_sql.rb +187 -0
  122. data/lib/webhookdb/db_adapter/pg.rb +96 -0
  123. data/lib/webhookdb/db_adapter/snowflake.rb +137 -0
  124. data/lib/webhookdb/db_adapter.rb +208 -0
  125. data/lib/webhookdb/dbutil.rb +92 -0
  126. data/lib/webhookdb/demo_mode.rb +100 -0
  127. data/lib/webhookdb/developer_alert.rb +51 -0
  128. data/lib/webhookdb/email_octopus.rb +21 -0
  129. data/lib/webhookdb/enumerable.rb +18 -0
  130. data/lib/webhookdb/fixtures/backfill_jobs.rb +72 -0
  131. data/lib/webhookdb/fixtures/customers.rb +65 -0
  132. data/lib/webhookdb/fixtures/database_documents.rb +27 -0
  133. data/lib/webhookdb/fixtures/faker.rb +41 -0
  134. data/lib/webhookdb/fixtures/logged_webhooks.rb +56 -0
  135. data/lib/webhookdb/fixtures/message_deliveries.rb +59 -0
  136. data/lib/webhookdb/fixtures/oauth_sessions.rb +24 -0
  137. data/lib/webhookdb/fixtures/organization_database_migrations.rb +37 -0
  138. data/lib/webhookdb/fixtures/organization_memberships.rb +54 -0
  139. data/lib/webhookdb/fixtures/organizations.rb +32 -0
  140. data/lib/webhookdb/fixtures/reset_codes.rb +23 -0
  141. data/lib/webhookdb/fixtures/service_integrations.rb +42 -0
  142. data/lib/webhookdb/fixtures/subscriptions.rb +33 -0
  143. data/lib/webhookdb/fixtures/sync_targets.rb +32 -0
  144. data/lib/webhookdb/fixtures/webhook_subscriptions.rb +35 -0
  145. data/lib/webhookdb/fixtures.rb +15 -0
  146. data/lib/webhookdb/formatting.rb +56 -0
  147. data/lib/webhookdb/front.rb +49 -0
  148. data/lib/webhookdb/github.rb +22 -0
  149. data/lib/webhookdb/google_calendar.rb +29 -0
  150. data/lib/webhookdb/heroku.rb +21 -0
  151. data/lib/webhookdb/http.rb +114 -0
  152. data/lib/webhookdb/icalendar.rb +17 -0
  153. data/lib/webhookdb/id.rb +17 -0
  154. data/lib/webhookdb/idempotency.rb +90 -0
  155. data/lib/webhookdb/increase.rb +42 -0
  156. data/lib/webhookdb/intercom.rb +23 -0
  157. data/lib/webhookdb/jobs/amigo_test_jobs.rb +118 -0
  158. data/lib/webhookdb/jobs/backfill.rb +32 -0
  159. data/lib/webhookdb/jobs/create_mirror_table.rb +18 -0
  160. data/lib/webhookdb/jobs/create_stripe_customer.rb +17 -0
  161. data/lib/webhookdb/jobs/customer_created_notify_internal.rb +22 -0
  162. data/lib/webhookdb/jobs/demo_mode_sync_data.rb +19 -0
  163. data/lib/webhookdb/jobs/deprecated_jobs.rb +19 -0
  164. data/lib/webhookdb/jobs/developer_alert_handle.rb +14 -0
  165. data/lib/webhookdb/jobs/durable_job_recheck_poller.rb +17 -0
  166. data/lib/webhookdb/jobs/emailer.rb +15 -0
  167. data/lib/webhookdb/jobs/icalendar_enqueue_syncs.rb +25 -0
  168. data/lib/webhookdb/jobs/icalendar_sync.rb +23 -0
  169. data/lib/webhookdb/jobs/logged_webhook_replay.rb +17 -0
  170. data/lib/webhookdb/jobs/logged_webhook_resilient_replay.rb +15 -0
  171. data/lib/webhookdb/jobs/message_dispatched.rb +16 -0
  172. data/lib/webhookdb/jobs/organization_database_migration_notify_finished.rb +21 -0
  173. data/lib/webhookdb/jobs/organization_database_migration_notify_started.rb +21 -0
  174. data/lib/webhookdb/jobs/organization_database_migration_run.rb +24 -0
  175. data/lib/webhookdb/jobs/prepare_database_connections.rb +22 -0
  176. data/lib/webhookdb/jobs/process_webhook.rb +47 -0
  177. data/lib/webhookdb/jobs/renew_watch_channel.rb +24 -0
  178. data/lib/webhookdb/jobs/replication_migration.rb +24 -0
  179. data/lib/webhookdb/jobs/reset_code_create_dispatch.rb +23 -0
  180. data/lib/webhookdb/jobs/scheduled_backfills.rb +77 -0
  181. data/lib/webhookdb/jobs/send_invite.rb +15 -0
  182. data/lib/webhookdb/jobs/send_test_webhook.rb +25 -0
  183. data/lib/webhookdb/jobs/send_webhook.rb +20 -0
  184. data/lib/webhookdb/jobs/sync_target_enqueue_scheduled.rb +16 -0
  185. data/lib/webhookdb/jobs/sync_target_run_sync.rb +38 -0
  186. data/lib/webhookdb/jobs/trim_logged_webhooks.rb +15 -0
  187. data/lib/webhookdb/jobs/webhook_resource_notify_integrations.rb +30 -0
  188. data/lib/webhookdb/jobs/webhook_subscription_delivery_attempt.rb +29 -0
  189. data/lib/webhookdb/jobs.rb +4 -0
  190. data/lib/webhookdb/json.rb +113 -0
  191. data/lib/webhookdb/liquid/expose.rb +27 -0
  192. data/lib/webhookdb/liquid/filters.rb +16 -0
  193. data/lib/webhookdb/liquid/liquification.rb +26 -0
  194. data/lib/webhookdb/liquid/partial.rb +12 -0
  195. data/lib/webhookdb/logged_webhook/resilient.rb +95 -0
  196. data/lib/webhookdb/logged_webhook.rb +194 -0
  197. data/lib/webhookdb/message/body.rb +25 -0
  198. data/lib/webhookdb/message/delivery.rb +127 -0
  199. data/lib/webhookdb/message/email_transport.rb +133 -0
  200. data/lib/webhookdb/message/fake_transport.rb +54 -0
  201. data/lib/webhookdb/message/liquid_drops.rb +29 -0
  202. data/lib/webhookdb/message/template.rb +89 -0
  203. data/lib/webhookdb/message/transport.rb +43 -0
  204. data/lib/webhookdb/message.rb +150 -0
  205. data/lib/webhookdb/messages/error_icalendar_fetch.rb +42 -0
  206. data/lib/webhookdb/messages/invite.rb +23 -0
  207. data/lib/webhookdb/messages/new_customer.rb +14 -0
  208. data/lib/webhookdb/messages/org_database_migration_finished.rb +23 -0
  209. data/lib/webhookdb/messages/org_database_migration_started.rb +24 -0
  210. data/lib/webhookdb/messages/specs.rb +57 -0
  211. data/lib/webhookdb/messages/verification.rb +23 -0
  212. data/lib/webhookdb/method_utilities.rb +82 -0
  213. data/lib/webhookdb/microsoft_calendar.rb +36 -0
  214. data/lib/webhookdb/nextpax.rb +14 -0
  215. data/lib/webhookdb/oauth/front.rb +58 -0
  216. data/lib/webhookdb/oauth/intercom.rb +58 -0
  217. data/lib/webhookdb/oauth/session.rb +24 -0
  218. data/lib/webhookdb/oauth.rb +80 -0
  219. data/lib/webhookdb/organization/alerting.rb +35 -0
  220. data/lib/webhookdb/organization/database_migration.rb +151 -0
  221. data/lib/webhookdb/organization/db_builder.rb +429 -0
  222. data/lib/webhookdb/organization.rb +506 -0
  223. data/lib/webhookdb/organization_membership.rb +58 -0
  224. data/lib/webhookdb/phone_number.rb +38 -0
  225. data/lib/webhookdb/plaid.rb +23 -0
  226. data/lib/webhookdb/platform.rb +27 -0
  227. data/lib/webhookdb/plivo.rb +52 -0
  228. data/lib/webhookdb/postgres/maintenance.rb +166 -0
  229. data/lib/webhookdb/postgres/model.rb +82 -0
  230. data/lib/webhookdb/postgres/model_utilities.rb +382 -0
  231. data/lib/webhookdb/postgres/testing_pixie.rb +16 -0
  232. data/lib/webhookdb/postgres/validations.rb +46 -0
  233. data/lib/webhookdb/postgres.rb +176 -0
  234. data/lib/webhookdb/postmark.rb +20 -0
  235. data/lib/webhookdb/redis.rb +35 -0
  236. data/lib/webhookdb/replicator/atom_single_feed_v1.rb +116 -0
  237. data/lib/webhookdb/replicator/aws_pricing_v1.rb +488 -0
  238. data/lib/webhookdb/replicator/base.rb +1185 -0
  239. data/lib/webhookdb/replicator/column.rb +482 -0
  240. data/lib/webhookdb/replicator/convertkit_broadcast_v1.rb +69 -0
  241. data/lib/webhookdb/replicator/convertkit_subscriber_v1.rb +200 -0
  242. data/lib/webhookdb/replicator/convertkit_tag_v1.rb +66 -0
  243. data/lib/webhookdb/replicator/convertkit_v1_mixin.rb +65 -0
  244. data/lib/webhookdb/replicator/docgen.rb +167 -0
  245. data/lib/webhookdb/replicator/email_octopus_campaign_v1.rb +84 -0
  246. data/lib/webhookdb/replicator/email_octopus_contact_v1.rb +159 -0
  247. data/lib/webhookdb/replicator/email_octopus_event_v1.rb +244 -0
  248. data/lib/webhookdb/replicator/email_octopus_list_v1.rb +101 -0
  249. data/lib/webhookdb/replicator/fake.rb +453 -0
  250. data/lib/webhookdb/replicator/front_conversation_v1.rb +45 -0
  251. data/lib/webhookdb/replicator/front_marketplace_root_v1.rb +55 -0
  252. data/lib/webhookdb/replicator/front_message_v1.rb +45 -0
  253. data/lib/webhookdb/replicator/front_v1_mixin.rb +22 -0
  254. data/lib/webhookdb/replicator/github_issue_comment_v1.rb +58 -0
  255. data/lib/webhookdb/replicator/github_issue_v1.rb +83 -0
  256. data/lib/webhookdb/replicator/github_pull_v1.rb +84 -0
  257. data/lib/webhookdb/replicator/github_release_v1.rb +47 -0
  258. data/lib/webhookdb/replicator/github_repo_v1_mixin.rb +250 -0
  259. data/lib/webhookdb/replicator/github_repository_event_v1.rb +45 -0
  260. data/lib/webhookdb/replicator/icalendar_calendar_v1.rb +465 -0
  261. data/lib/webhookdb/replicator/icalendar_event_v1.rb +334 -0
  262. data/lib/webhookdb/replicator/increase_account_number_v1.rb +77 -0
  263. data/lib/webhookdb/replicator/increase_account_transfer_v1.rb +61 -0
  264. data/lib/webhookdb/replicator/increase_account_v1.rb +63 -0
  265. data/lib/webhookdb/replicator/increase_ach_transfer_v1.rb +78 -0
  266. data/lib/webhookdb/replicator/increase_check_transfer_v1.rb +64 -0
  267. data/lib/webhookdb/replicator/increase_limit_v1.rb +78 -0
  268. data/lib/webhookdb/replicator/increase_transaction_v1.rb +74 -0
  269. data/lib/webhookdb/replicator/increase_v1_mixin.rb +121 -0
  270. data/lib/webhookdb/replicator/increase_wire_transfer_v1.rb +61 -0
  271. data/lib/webhookdb/replicator/intercom_contact_v1.rb +36 -0
  272. data/lib/webhookdb/replicator/intercom_conversation_v1.rb +38 -0
  273. data/lib/webhookdb/replicator/intercom_marketplace_root_v1.rb +69 -0
  274. data/lib/webhookdb/replicator/intercom_v1_mixin.rb +105 -0
  275. data/lib/webhookdb/replicator/oauth_refresh_access_token_mixin.rb +65 -0
  276. data/lib/webhookdb/replicator/plivo_sms_inbound_v1.rb +102 -0
  277. data/lib/webhookdb/replicator/postmark_inbound_message_v1.rb +94 -0
  278. data/lib/webhookdb/replicator/postmark_outbound_message_event_v1.rb +107 -0
  279. data/lib/webhookdb/replicator/schema_modification.rb +42 -0
  280. data/lib/webhookdb/replicator/shopify_customer_v1.rb +58 -0
  281. data/lib/webhookdb/replicator/shopify_order_v1.rb +64 -0
  282. data/lib/webhookdb/replicator/shopify_v1_mixin.rb +161 -0
  283. data/lib/webhookdb/replicator/signalwire_message_v1.rb +169 -0
  284. data/lib/webhookdb/replicator/sponsy_customer_v1.rb +54 -0
  285. data/lib/webhookdb/replicator/sponsy_placement_v1.rb +34 -0
  286. data/lib/webhookdb/replicator/sponsy_publication_v1.rb +125 -0
  287. data/lib/webhookdb/replicator/sponsy_slot_v1.rb +41 -0
  288. data/lib/webhookdb/replicator/sponsy_status_v1.rb +35 -0
  289. data/lib/webhookdb/replicator/sponsy_v1_mixin.rb +165 -0
  290. data/lib/webhookdb/replicator/state_machine_step.rb +69 -0
  291. data/lib/webhookdb/replicator/stripe_charge_v1.rb +77 -0
  292. data/lib/webhookdb/replicator/stripe_coupon_v1.rb +62 -0
  293. data/lib/webhookdb/replicator/stripe_customer_v1.rb +60 -0
  294. data/lib/webhookdb/replicator/stripe_dispute_v1.rb +77 -0
  295. data/lib/webhookdb/replicator/stripe_invoice_item_v1.rb +82 -0
  296. data/lib/webhookdb/replicator/stripe_invoice_v1.rb +116 -0
  297. data/lib/webhookdb/replicator/stripe_payout_v1.rb +67 -0
  298. data/lib/webhookdb/replicator/stripe_price_v1.rb +60 -0
  299. data/lib/webhookdb/replicator/stripe_product_v1.rb +60 -0
  300. data/lib/webhookdb/replicator/stripe_refund_v1.rb +101 -0
  301. data/lib/webhookdb/replicator/stripe_subscription_item_v1.rb +56 -0
  302. data/lib/webhookdb/replicator/stripe_subscription_v1.rb +75 -0
  303. data/lib/webhookdb/replicator/stripe_v1_mixin.rb +116 -0
  304. data/lib/webhookdb/replicator/transistor_episode_stats_v1.rb +141 -0
  305. data/lib/webhookdb/replicator/transistor_episode_v1.rb +169 -0
  306. data/lib/webhookdb/replicator/transistor_show_v1.rb +68 -0
  307. data/lib/webhookdb/replicator/transistor_v1_mixin.rb +65 -0
  308. data/lib/webhookdb/replicator/twilio_sms_v1.rb +156 -0
  309. data/lib/webhookdb/replicator/webhook_request.rb +5 -0
  310. data/lib/webhookdb/replicator/webhookdb_customer_v1.rb +74 -0
  311. data/lib/webhookdb/replicator.rb +224 -0
  312. data/lib/webhookdb/role.rb +42 -0
  313. data/lib/webhookdb/sentry.rb +35 -0
  314. data/lib/webhookdb/service/auth.rb +138 -0
  315. data/lib/webhookdb/service/collection.rb +91 -0
  316. data/lib/webhookdb/service/entities.rb +97 -0
  317. data/lib/webhookdb/service/helpers.rb +270 -0
  318. data/lib/webhookdb/service/middleware.rb +124 -0
  319. data/lib/webhookdb/service/types.rb +30 -0
  320. data/lib/webhookdb/service/validators.rb +32 -0
  321. data/lib/webhookdb/service/view_api.rb +63 -0
  322. data/lib/webhookdb/service.rb +219 -0
  323. data/lib/webhookdb/service_integration.rb +332 -0
  324. data/lib/webhookdb/shopify.rb +35 -0
  325. data/lib/webhookdb/signalwire.rb +13 -0
  326. data/lib/webhookdb/slack.rb +68 -0
  327. data/lib/webhookdb/snowflake.rb +90 -0
  328. data/lib/webhookdb/spec_helpers/async.rb +122 -0
  329. data/lib/webhookdb/spec_helpers/citest.rb +88 -0
  330. data/lib/webhookdb/spec_helpers/integration.rb +121 -0
  331. data/lib/webhookdb/spec_helpers/message.rb +41 -0
  332. data/lib/webhookdb/spec_helpers/postgres.rb +220 -0
  333. data/lib/webhookdb/spec_helpers/service.rb +432 -0
  334. data/lib/webhookdb/spec_helpers/shared_examples_for_columns.rb +56 -0
  335. data/lib/webhookdb/spec_helpers/shared_examples_for_replicators.rb +915 -0
  336. data/lib/webhookdb/spec_helpers/whdb.rb +139 -0
  337. data/lib/webhookdb/spec_helpers.rb +63 -0
  338. data/lib/webhookdb/sponsy.rb +14 -0
  339. data/lib/webhookdb/stripe.rb +37 -0
  340. data/lib/webhookdb/subscription.rb +203 -0
  341. data/lib/webhookdb/sync_target.rb +491 -0
  342. data/lib/webhookdb/tasks/admin.rb +49 -0
  343. data/lib/webhookdb/tasks/annotate.rb +36 -0
  344. data/lib/webhookdb/tasks/db.rb +82 -0
  345. data/lib/webhookdb/tasks/docs.rb +42 -0
  346. data/lib/webhookdb/tasks/fixture.rb +35 -0
  347. data/lib/webhookdb/tasks/message.rb +50 -0
  348. data/lib/webhookdb/tasks/regress.rb +87 -0
  349. data/lib/webhookdb/tasks/release.rb +27 -0
  350. data/lib/webhookdb/tasks/sidekiq.rb +23 -0
  351. data/lib/webhookdb/tasks/specs.rb +64 -0
  352. data/lib/webhookdb/theranest.rb +15 -0
  353. data/lib/webhookdb/transistor.rb +13 -0
  354. data/lib/webhookdb/twilio.rb +13 -0
  355. data/lib/webhookdb/typed_struct.rb +44 -0
  356. data/lib/webhookdb/version.rb +5 -0
  357. data/lib/webhookdb/webhook_response.rb +50 -0
  358. data/lib/webhookdb/webhook_subscription/delivery.rb +82 -0
  359. data/lib/webhookdb/webhook_subscription.rb +226 -0
  360. data/lib/webhookdb/windows_tz.rb +32 -0
  361. data/lib/webhookdb/xml.rb +92 -0
  362. data/lib/webhookdb.rb +224 -0
  363. data/lib/webterm/apps.rb +45 -0
  364. metadata +1129 -0
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/slack"
4
+ require "webhookdb/spec_helpers"
5
+
6
+ module Webhookdb::SpecHelpers::Citest
7
+ def self.run_tests(folder)
8
+ out = StringIO.new
9
+ err = StringIO.new
10
+ RSpec::Core::Runner.run([folder + "/", "--format", "html"], err, out)
11
+
12
+ notifier = Webhookdb::Slack.new_notifier(
13
+ force_channel: "#webhookdb-notifications",
14
+ username: "CI Tests",
15
+ icon_emoji: ":female-detective:",
16
+ )
17
+ outstring = out.string
18
+ result = Webhookdb::SpecHelpers::Citest.parse_rspec_html(outstring)
19
+ unless result.ok?
20
+ msg = "Errored or unparseable output running #{folder} tests:\nerror: #{err.string}\nout: #{outstring}"
21
+ notifier.post text: msg
22
+ return
23
+ end
24
+
25
+ url = self.put_results(folder, result.html)
26
+ payload = self.result_to_payload(folder, result, url)
27
+ notifier.post(payload)
28
+ end
29
+
30
+ def self.parse_rspec_html(output)
31
+ result = RSpecResult.new
32
+ html = []
33
+ output.lines.each do |line|
34
+ next if line.strip.start_with?("Run options") || line.strip.starts_with?("All examples were")
35
+ html << line
36
+ captures = line.match(/innerHTML = "(\d+ examples?), (\d+ failures?)(, )?(\d+ pending)?/)&.captures
37
+ next unless captures
38
+ result.examples = captures[0].to_i
39
+ result.failures = captures[1].to_i
40
+ result.pending = captures[3].to_i
41
+ end
42
+ result.html = html.join
43
+ return result
44
+ end
45
+
46
+ def self.put_results(folder, html)
47
+ now = Time.now
48
+ key = "test-results/#{folder}/#{now.year}/#{now.month}/#{now.in_time_zone('UTC').iso8601}.html"
49
+ doc = Webhookdb::DatabaseDocument.create(
50
+ key:,
51
+ content: html,
52
+ content_type: "text/html",
53
+ )
54
+ url = doc.presigned_view_url(expire_at: 1.week.from_now)
55
+ return url
56
+ end
57
+
58
+ def self.result_to_payload(folder, result, html_url)
59
+ color = "good"
60
+ color = "warning" if result.pending.nonzero?
61
+ color = "danger" if result.failures.nonzero?
62
+
63
+ return {
64
+ text: "Tests for #{folder}: #{result.examples} examples, #{result.failures} failures, #{result.pending} pending",
65
+ attachments: [
66
+ {
67
+ color:,
68
+ fallback: "View results at #{html_url}",
69
+ actions: [
70
+ {
71
+ type: "button",
72
+ text: "View Results 🔎",
73
+ url: html_url,
74
+ },
75
+ ],
76
+ },
77
+ ],
78
+ }
79
+ end
80
+
81
+ class RSpecResult
82
+ attr_accessor :html, :examples, :failures, :pending
83
+
84
+ def ok?
85
+ return !self.examples.nil?
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "appydays/configurable"
4
+ require "httparty"
5
+ require "rspec"
6
+ require "rspec/eventually"
7
+
8
+ require "webhookdb"
9
+ require "webhookdb/async"
10
+
11
+ raise "integration tests not enabled, this file should not have been evaluated" unless
12
+ Webhookdb::INTEGRATION_TESTS_ENABLED
13
+
14
+ module Webhookdb::IntegrationSpecHelpers
15
+ include Appydays::Configurable
16
+ include Appydays::Loggable
17
+
18
+ def self.included(context)
19
+ # We run few workers on staging so need time to process things.
20
+ Rspec::Eventually.timeout = 60
21
+ # We're in no rush for integration tests.
22
+ Rspec::Eventually.pause = 1
23
+
24
+ context.before(:each) do |example|
25
+ raise "Unit tests should not be run during integration tests (or this test needs an :integration flag" unless
26
+ example.metadata[:integration]
27
+
28
+ @to_destroy = []
29
+ WebMock.allow_net_connect!
30
+ end
31
+
32
+ context.after(:each) do
33
+ @to_destroy.each(&:destroy)
34
+ WebMock.disable_net_connect!
35
+ end
36
+ super
37
+ end
38
+
39
+ module_function def with_async_publisher
40
+ Amigo.install_amigo_jobs
41
+ yield
42
+ ensure
43
+ Amigo.subscribers.clear
44
+ end
45
+
46
+ module_function def url(more)
47
+ return "#{Webhookdb.api_url}#{more}"
48
+ end
49
+
50
+ module_function def parse_cookie(resp)
51
+ cookie_hash = HTTParty::CookieHash.new
52
+ resp.get_fields("Set-Cookie")&.each { |c| cookie_hash.add_cookies(c) }
53
+ return cookie_hash
54
+ end
55
+
56
+ module_function def store_cookies
57
+ response = yield()
58
+ @stored_cookies = parse_cookie(response)
59
+ Webhookdb::IntegrationSpecHelpers.logger.debug "Got cookies: %p" % [stored_cookies]
60
+ return response
61
+ end
62
+
63
+ module_function def stored_cookies
64
+ return @stored_cookies
65
+ end
66
+
67
+ module_function def auth_customer(customer=nil)
68
+ if customer.nil?
69
+ customer = Webhookdb::Fixtures.customer.instance
70
+ resp = post("/v1/auth", body: {email: customer.email})
71
+ expect(resp).to party_status(202)
72
+ customer = Webhookdb::Customer[email: customer.email]
73
+ end
74
+
75
+ code = Webhookdb::Fixtures.reset_code(customer:).create
76
+ resp = post("/v1/auth", body: {email: customer.email, token: code.token})
77
+ expect(resp).to party_status(200)
78
+
79
+ return customer.refresh
80
+ end
81
+
82
+ [:get, :post, :put, :patch, :delete].each do |method|
83
+ define_method(method) do |url_, opts={}|
84
+ opts[:headers] ||= {}
85
+ store_cookies do
86
+ cookie_header = stored_cookies&.to_cookie_string
87
+ opts[:headers] = opts[:headers].merge("Cookie" => cookie_header) if cookie_header.present?
88
+ if opts.delete(:json)
89
+ opts[:headers]["Content-Type"] = "application/json"
90
+ opts[:body] = opts[:body].to_json unless opts[:body].is_a?(String)
91
+ end
92
+ Webhookdb::IntegrationSpecHelpers.logger.info "%s %s %s" % [method.upcase, url_, opts]
93
+ HTTParty.send(method, url(url_), opts)
94
+ end
95
+ end
96
+ module_function method
97
+ end
98
+ end
99
+
100
+ # Check that an HTTParty::Response code matches the expected.
101
+ RSpec::Matchers.define(:party_status) do |expected_status|
102
+ match do |response|
103
+ response.code == expected_status
104
+ end
105
+
106
+ failure_message do |response|
107
+ "expected response code %d, got a %d response instead\nBody: %s" %
108
+ [expected_status, response.code, response.parsed_response]
109
+ end
110
+ end
111
+
112
+ # Match a parsed Response hash (deep symbol keys) against an RSpec matcher.
113
+ RSpec::Matchers.define(:party_response) do |matcher|
114
+ match do |response|
115
+ matcher.matches?(response.parsed_response.deep_symbolize_keys)
116
+ end
117
+
118
+ failure_message do
119
+ matcher.failure_message
120
+ end
121
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/spec_helpers"
4
+
5
+ module Webhookdb::SpecHelpers::Message
6
+ def self.included(context)
7
+ context.before(:each) do |example|
8
+ if example.metadata[:messaging]
9
+ Webhookdb::Message::Transport.override = :fake
10
+ Webhookdb::Message::FakeTransport.reset!
11
+ end
12
+ end
13
+
14
+ context.after(:each) do |example|
15
+ if example.metadata[:messaging]
16
+ Webhookdb::Message::Transport.override = nil
17
+ Webhookdb::Message::FakeTransport.reset!
18
+ end
19
+ end
20
+
21
+ super
22
+ end
23
+
24
+ # Retrieve the last sent email from the local mailpit service.
25
+ module_function def fetch_last_email
26
+ old = WebMock::Config.instance.allow
27
+ mpurl = Webhookdb::Message::EmailTransport.mailpit_url
28
+ getopts = {timeout: 5, logger: nil}
29
+ WebMock::Config.instance.allow = mpurl
30
+ begin
31
+ list_resp = Webhookdb::Http.get("#{mpurl}/api/v1/messages", {limit: 1}, **getopts)
32
+ msg = list_resp.parsed_response.fetch("messages").first
33
+ msgid = msg.fetch("ID")
34
+ headers_resp = Webhookdb::Http.get("#{mpurl}/api/v1/message/#{msgid}/headers", **getopts)
35
+ msg["Headers"] = headers_resp.parsed_response
36
+ return msg
37
+ ensure
38
+ WebMock::Config.instance.allow = old
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/postgres"
4
+ require "webhookdb/spec_helpers"
5
+
6
+ # Some helper functions for testing. Usage:
7
+ #
8
+ # # in spec/spec_helper.rb
9
+ # RSpec.configure do |c|
10
+ # c.include( Webhookdb::SpecHelpers::Postgres )
11
+ # end
12
+ #
13
+ # # in my_class_spec.rb; mark an example as needing database setup
14
+ # describe MyClass, db: true do
15
+ # end
16
+ #
17
+ module Webhookdb::SpecHelpers::Postgres
18
+ extend Webhookdb::MethodUtilities
19
+
20
+ # Pathname constants
21
+ BASEDIR = Pathname(__FILE__).dirname.parent
22
+ SPECDIR = BASEDIR + "spec"
23
+ DATADIR = SPECDIR + "data"
24
+
25
+ SNIFF_LEAKY_TESTS = false
26
+
27
+ Webhookdb::Postgres.register_model("webhookdb/postgres/testing_pixie")
28
+
29
+ ### Inclusion callback -- install some hooks
30
+ def self.included(context)
31
+ context.around(:each) do |example|
32
+ Webhookdb::Postgres.unsafe_skip_transaction_check = true if example.metadata[:no_transaction_check]
33
+
34
+ setting = example.metadata[:db]
35
+ if setting && setting != :no_transaction
36
+ Webhookdb::SpecHelpers::Postgres.wrap_example_in_transactions(example)
37
+ else
38
+ Webhookdb::Postgres.logger.debug "Running spec without a transaction"
39
+ example.run
40
+ end
41
+ end
42
+
43
+ context.after(:each) do |example|
44
+ Webhookdb::Postgres.unsafe_skip_transaction_check = false if example.metadata[:no_transaction_check]
45
+
46
+ truncate_all if example.metadata[:db] == :no_transaction
47
+ end
48
+
49
+ super
50
+ end
51
+
52
+ ### Run the specified +example+ in the context of a transaction for each loaded
53
+ ### model superclass. Raises if any of the loaded superclasses aren't
54
+ ### configured.
55
+ def self.wrap_example_in_transactions(example)
56
+ txn_classes = Webhookdb::Postgres.model_superclasses
57
+ Webhookdb::Postgres.logger.debug "Wrapping example for model superclasses: %p" %
58
+ [txn_classes]
59
+
60
+ wrapped_proc = txn_classes.inject(example.method(:run)) do |callback, txn_class|
61
+ if (db = txn_class.db)
62
+ Webhookdb::Postgres.logger.debug "DB: Running with an outer transaction"
63
+ proc { db.transaction(auto_savepoint: :only, rollback: :always, &callback) }
64
+ else
65
+ raise "No database connection for %p configured! Add a %s section to the test config." %
66
+ [txn_class, txn_class.config_key]
67
+ end
68
+ end
69
+
70
+ wrapped_proc.call
71
+ return if !SNIFF_LEAKY_TESTS || (Webhookdb::Customer.empty? && Webhookdb::Organization.empty?)
72
+ puts "Customer is not cleaned up, failing for diagnosis."
73
+ puts "Check the spec that ran before: #{example.metadata[:full_description]}"
74
+ exit
75
+ end
76
+
77
+ singleton_attr_accessor :current_test_model_uid
78
+ self.current_test_model_uid = 0
79
+
80
+ module Models; end
81
+
82
+ # Create an anonymous model with the given table name.
83
+ # Can be a symbol, string, or [:schema, :table] array.
84
+ module_function def create_model(name, &)
85
+ Webhookdb::SpecHelpers::Postgres.current_test_model_uid += 1
86
+
87
+ qualifier = Sequel
88
+ prefix = name
89
+ if name.is_a?(Array)
90
+ qualifier = Sequel[name[0]]
91
+ Webhookdb::Postgres::Model.create_schema!(qualifier)
92
+ prefix = name[1]
93
+ end
94
+ table_name = :"testtable_#{prefix}_#{Webhookdb::SpecHelpers::Postgres.current_test_model_uid}"
95
+ qualified_name = qualifier[table_name]
96
+
97
+ Webhookdb::Postgres.logger.info "Creating table: %p" % [qualified_name]
98
+ Webhookdb::Postgres::Model.db.create_table!(qualified_name, &)
99
+ clsname = table_name.to_s.classify
100
+ clsfqn = "#{Webhookdb::SpecHelpers::Postgres::Models}::#{clsname}"
101
+ cls = Class.new(Webhookdb::Postgres::Model(qualified_name)) do
102
+ define_singleton_method(:name) { clsfqn }
103
+ end
104
+ Webhookdb::SpecHelpers::Postgres::Models.const_set(clsname, cls)
105
+ # Object.const_get(clsfqn)
106
+ return cls
107
+ end
108
+
109
+ module_function def truncate_all
110
+ # We can delete items from 'leaf' to 'trunk' in association terms
111
+ # by using the TSort API (so Address and Customer, for example, are very early,
112
+ # while 'StripeAttributes', which nothing has an FK into, is very late).
113
+ # This is much faster than truncating with cascade.
114
+ # Though in some cases, it doesn't work, so we need to cascade.
115
+ Webhookdb::Postgres.each_model_superclass do |sc|
116
+ sc.tsort.reverse_each do |m|
117
+ m.dataset.delete
118
+ rescue Sequel::ForeignKeyConstraintViolation
119
+ m.truncate(cascade: true)
120
+ rescue Sequel::DatabaseError
121
+ # The table may not exist, maybe because the type was created in a test
122
+ # and now no longer exists but it still a subclass.
123
+ nil
124
+ end
125
+ end
126
+ end
127
+
128
+ #
129
+ # Custom matchers
130
+ #
131
+
132
+ RSpec::Matchers.define(:be_saved) do
133
+ match do |model_object|
134
+ !model_object.new?
135
+ end
136
+ end
137
+
138
+ class HaveRowMatcher
139
+ include RSpec::Matchers
140
+
141
+ def initialize(criteria)
142
+ @criteria = criteria
143
+ end
144
+
145
+ def matches?(model)
146
+ @model = model
147
+ @instance = @model[@criteria]
148
+ return false if @instance.nil?
149
+
150
+ return @matcher.matches?(@instance) if @matcher
151
+
152
+ return true
153
+ end
154
+
155
+ def failure_message
156
+ return "Expected %s to have a row matching criteria %p but did not" % [@model.name, @criteria] unless @instance
157
+ return "Row found but matcher failed with: %s" % [@matcher.failure_message] if @matcher
158
+ return "invalid message"
159
+ end
160
+
161
+ def failure_message_when_negated
162
+ return "Expected %s to not have a row matching criteria %p but did" % [@model.name, @criteria] if @instance
163
+ return "invalid message"
164
+ end
165
+
166
+ def with_attributes(attrs)
167
+ @matcher = RSpec::Matchers::BuiltIn::HaveAttributes.new(attrs)
168
+ return self
169
+ end
170
+ end
171
+
172
+ module_function def have_row(criteria)
173
+ return HaveRowMatcher.new(criteria)
174
+ end
175
+
176
+ # Matcher that checks that hashes have the same id as objects.
177
+ #
178
+ # expect( last_response_json_body ).to have_same_ids_as( dataset.all )
179
+ #
180
+ RSpec::Matchers.define(:have_same_ids_as) do |*expected|
181
+ match do |actual|
182
+ @pk ||= :id
183
+ self.ids(actual) == self.ids(expected.flatten)
184
+ end
185
+
186
+ failure_message do |actual|
187
+ "expected ids %s to equal ids %s" % [self.ids(actual), self.ids(expected.flatten)]
188
+ end
189
+
190
+ chain :ordered do
191
+ @ordered = true
192
+ end
193
+
194
+ chain :pk_field do |pk|
195
+ @pk = pk
196
+ end
197
+
198
+ def ids(arr)
199
+ res = arr.map { |o| self.id(o) }
200
+ res = res.sort unless @ordered
201
+ return res
202
+ end
203
+
204
+ def id(o)
205
+ return o if o.is_a?(Numeric)
206
+ return o.send(@pk) if o.respond_to?(@pk)
207
+ return o[@pk] || o[@pk.to_s]
208
+ end
209
+ end
210
+
211
+ RSpec::Matchers.define(:be_destroyed) do
212
+ match do |actual|
213
+ actual.class.where(id: actual.id).empty?
214
+ end
215
+
216
+ failure_message do |actual|
217
+ "did not expect to find item with id %s in %s" % [actual.id, actual.class.where(id: actual.id).all]
218
+ end
219
+ end
220
+ end