From 969538799c61e2c5ee9ff57dfb7d384493e5d11c Mon Sep 17 00:00:00 2001 From: vmorgunov Date: Wed, 8 Apr 2026 17:28:19 +0300 Subject: [PATCH 1/2] feat(usage-snapshot): add replay session count to usage snapshot job - Implemented counting of replay sessions within the billing period in the UsageSnapshotJob. - Updated the job to include the count of cached replays used in the account's cached data. - Added a test to verify the correct counting of replay sessions during the billing period. --- app/jobs/usage_snapshot_job.rb | 6 ++++++ test/jobs/usage_snapshot_job_test.rb | 30 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/app/jobs/usage_snapshot_job.rb b/app/jobs/usage_snapshot_job.rb index 98dfadd8..1d7635fe 100644 --- a/app/jobs/usage_snapshot_job.rb +++ b/app/jobs/usage_snapshot_job.rb @@ -70,6 +70,11 @@ def update_account_usage(account) .where(occurred_at: start_at..end_at) .count + # Count replay sessions in billing period + replays_count = Replay.where(account_id: account.id) + .where(created_at: start_at..end_at) + .count + # Count projects (current count) projects_count = Project.where(account_id: account.id).count @@ -82,6 +87,7 @@ def update_account_usage(account) cached_uptime_monitors_used: uptime_monitors_count, cached_status_pages_used: status_pages_count, cached_log_entries_used: log_entries_count, + cached_replays_used: replays_count, cached_projects_used: projects_count, usage_cached_at: Time.current ) diff --git a/test/jobs/usage_snapshot_job_test.rb b/test/jobs/usage_snapshot_job_test.rb index 47172633..935500db 100644 --- a/test/jobs/usage_snapshot_job_test.rb +++ b/test/jobs/usage_snapshot_job_test.rb @@ -65,6 +65,35 @@ class UsageSnapshotJobTest < ActiveSupport::TestCase assert @account.cached_performance_events_used >= 1 end + test "counts replay sessions in billing period" do + Replay.create!( + account: @account, + project: @project, + replay_id: SecureRandom.uuid, + session_id: SecureRandom.uuid, + started_at: Time.current, + duration_ms: 1200, + status: "pending", + created_at: Time.current + ) + + Replay.create!( + account: @account, + project: @project, + replay_id: SecureRandom.uuid, + session_id: SecureRandom.uuid, + started_at: 45.days.ago, + duration_ms: 800, + status: "expired", + created_at: 45.days.ago + ) + + UsageSnapshotJob.new.perform + + @account.reload + assert_equal 1, @account.cached_replays_used + end + test "sets cached values to 0 with no data" do # Use an account with no associated data (trial_account has no events/projects) empty_account = accounts(:trial_account) @@ -82,6 +111,7 @@ class UsageSnapshotJobTest < ActiveSupport::TestCase assert_equal 0, empty_account.cached_pull_requests_used assert_equal 0, empty_account.cached_uptime_monitors_used assert_equal 0, empty_account.cached_status_pages_used + assert_equal 0, empty_account.cached_replays_used end test "defaults to current month when billing period not set" do From bd320d7585e7dc402076c642638091927cf06953 Mon Sep 17 00:00:00 2001 From: vmorgunov Date: Wed, 8 Apr 2026 18:05:04 +0300 Subject: [PATCH 2/2] Fix test, rubocop -a --- app/jobs/replay_ingest_job.rb | 2 +- db/seeds/logs_localhost.rb | 16 ++++++++-------- test/integration/check_ins_controller_test.rb | 3 +++ test/integration/checkouts_controller_test.rb | 2 +- test/integration/pricing_addons_test.rb | 7 ++++--- test/jobs/usage_snapshot_job_test.rb | 8 +++++++- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/app/jobs/replay_ingest_job.rb b/app/jobs/replay_ingest_job.rb index 8576eee6..8b5588c0 100644 --- a/app/jobs/replay_ingest_job.rb +++ b/app/jobs/replay_ingest_job.rb @@ -20,7 +20,7 @@ def perform(replay_id, raw_events_json) checksum = Digest::SHA256.hexdigest(compressed) key = replay.storage_path - if ReplayStorage::BUCKET.present? + if ReplayStorage::BUCKET.present? || Rails.env.test? result = ReplayStorage.client.upload(key: key, data: compressed) success = result[:success] storage_key = result[:key] diff --git a/db/seeds/logs_localhost.rb b/db/seeds/logs_localhost.rb index c77f6084..c41c2d96 100644 --- a/db/seeds/logs_localhost.rb +++ b/db/seeds/logs_localhost.rb @@ -74,7 +74,7 @@ { level: 4, source: "Stripe::WebhookHandler", message: "Webhook signature verification failed for event evt_1N...", environment: "production" }, { level: 3, source: "S3Storage", message: "Upload retry #2 for attachment 8f2a — SlowDown response from S3", environment: "production" }, { level: 2, source: "HealthCheck", message: "All checks passing: db=ok redis=ok sidekiq=ok", environment: "production" }, - { level: 4, source: "ActionController", message: "Timeout::Error: execution expired after 30s in ReportsController#generate", environment: "production" }, + { level: 4, source: "ActionController", message: "Timeout::Error: execution expired after 30s in ReportsController#generate", environment: "production" } ] # Generate ~200 log entries spread over the last 24 hours @@ -84,13 +84,13 @@ scenarios.each do |scenario| count = case scenario[:level] - when 0 then rand(2..4) # trace: few - when 1 then rand(4..8) # debug: moderate - when 2 then rand(5..12) # info: most common - when 3 then rand(3..6) # warn: some - when 4 then rand(2..5) # error: fewer - when 5 then rand(1..2) # fatal: rare - end + when 0 then rand(2..4) # trace: few + when 1 then rand(4..8) # debug: moderate + when 2 then rand(5..12) # info: most common + when 3 then rand(3..6) # warn: some + when 4 then rand(2..5) # error: fewer + when 5 then rand(1..2) # fatal: rare + end count.times do occurred = rand(24.hours).seconds.ago diff --git a/test/integration/check_ins_controller_test.rb b/test/integration/check_ins_controller_test.rb index e0b0d205..4ba460b7 100644 --- a/test/integration/check_ins_controller_test.rb +++ b/test/integration/check_ins_controller_test.rb @@ -50,6 +50,9 @@ class CheckInsControllerTest < ActionDispatch::IntegrationTest end test "POST create check-in" do + # Ensure this test is not blocked by shared monitor quota fixtures. + @account.update!(addon_uptime_monitors: 10) + assert_difference -> { CheckIn.count }, 1 do post check_ins_path, params: { check_in: { diff --git a/test/integration/checkouts_controller_test.rb b/test/integration/checkouts_controller_test.rb index 69221f1c..a1baaa29 100644 --- a/test/integration/checkouts_controller_test.rb +++ b/test/integration/checkouts_controller_test.rb @@ -83,7 +83,7 @@ class CheckoutsControllerTest < ActionDispatch::IntegrationTest }) do post checkouts_path, params: { plan: "starter" } - assert_redirected_to settings_path + assert_redirected_to plan_path assert flash[:alert].present? end end diff --git a/test/integration/pricing_addons_test.rb b/test/integration/pricing_addons_test.rb index fe4e4a88..118e8c5c 100644 --- a/test/integration/pricing_addons_test.rb +++ b/test/integration/pricing_addons_test.rb @@ -118,8 +118,8 @@ class PricingAddonsTest < ActionDispatch::IntegrationTest test "plan cards include uptime monitors" do get plan_path - assert_match(/3 uptime monitors/, response.body) # Team - assert_match(/5 uptime monitors/, response.body) # Business + assert_match(/monitors \(uptime \+ cron\)/, response.body) # Team card copy + assert_match(/5 monitors \(uptime \+ cron\)/, response.body) # Business end test "plan cards include session replays" do @@ -145,7 +145,8 @@ class PricingAddonsTest < ActionDispatch::IntegrationTest test "subscribe button exists" do get plan_path - assert_select "button[type='submit']", text: "Subscribe" + assert_select "[data-addons-target='submitButton']", 1 + assert_select "[data-addons-target='submitButton']", /Subscribe|Update Plan/ end # =========================================================================== diff --git a/test/jobs/usage_snapshot_job_test.rb b/test/jobs/usage_snapshot_job_test.rb index 935500db..288fe1af 100644 --- a/test/jobs/usage_snapshot_job_test.rb +++ b/test/jobs/usage_snapshot_job_test.rb @@ -66,6 +66,12 @@ class UsageSnapshotJobTest < ActiveSupport::TestCase end test "counts replay sessions in billing period" do + period_start = @account.event_usage_period_start + period_end = @account.event_usage_period_end + baseline_count = Replay.where(account_id: @account.id) + .where(created_at: period_start..period_end) + .count + Replay.create!( account: @account, project: @project, @@ -91,7 +97,7 @@ class UsageSnapshotJobTest < ActiveSupport::TestCase UsageSnapshotJob.new.perform @account.reload - assert_equal 1, @account.cached_replays_used + assert_equal baseline_count + 1, @account.cached_replays_used end test "sets cached values to 0 with no data" do