hackatime/test/jobs/heartbeat_import_source_sync_job_test.rb
Mahad Kalam 7317cc45e7
Imports + mirrors :DD (#993)
* Imports + mirrors :DD

* Stuff and things

* Fixes

* Fixes x2

* Tests!

* Hmm
2026-02-23 15:00:43 +00:00

187 lines
5.5 KiB
Ruby

require "test_helper"
require "webmock/minitest"
class HeartbeatImportSourceSyncJobTest < ActiveJob::TestCase
setup do
Flipper.enable(:wakatime_imports_mirrors)
end
teardown do
Flipper.disable(:wakatime_imports_mirrors)
end
def create_source(user:, **attrs)
user.create_heartbeat_import_source!(
{
provider: :wakatime_compatible,
endpoint_url: "https://wakatime.com/api/v1",
encrypted_api_key: "import-key",
sync_enabled: true,
status: :idle
}.merge(attrs)
)
end
def queued_jobs_for(job_class)
GoodJob::Job.where(job_class: job_class)
end
test "full-history default schedules backfill windows and re-enqueues coordinator" do
GoodJob::Job.delete_all
user = User.create!(timezone: "UTC")
source = create_source(user: user)
stub_request(:get, "https://wakatime.com/api/v1/users/current/all_time_since_today")
.to_return(
status: 200,
body: {
data: {
range: {
start_date: (Date.current - 10.days).iso8601
}
}
}.to_json,
headers: { "Content-Type" => "application/json" }
)
HeartbeatImportSourceSyncJob.perform_now(source.id)
day_jobs = queued_jobs_for("HeartbeatImportSourceSyncDayJob")
sync_jobs = queued_jobs_for("HeartbeatImportSourceSyncJob")
assert_equal 5, day_jobs.count
assert_equal 1, sync_jobs.count
source.reload
assert source.backfilling?
assert_equal(Date.current - 5.days, source.backfill_cursor_date)
end
test "range override limits scheduled days" do
GoodJob::Job.delete_all
user = User.create!(timezone: "UTC")
start_date = Date.current - 2.days
end_date = Date.current - 1.day
source = create_source(
user: user,
initial_backfill_start_date: start_date,
initial_backfill_end_date: end_date
)
HeartbeatImportSourceSyncJob.perform_now(source.id)
day_jobs = queued_jobs_for("HeartbeatImportSourceSyncDayJob")
day_args = day_jobs.map { |job| job.serialized_params.fetch("arguments").last }
assert_equal 2, day_jobs.count
assert_includes day_args, start_date.iso8601
assert_includes day_args, end_date.iso8601
end
test "ongoing sync enqueues today and yesterday" do
GoodJob::Job.delete_all
user = User.create!(timezone: "UTC")
source = create_source(
user: user,
status: :syncing,
initial_backfill_start_date: Date.current - 7.days,
initial_backfill_end_date: Date.current,
backfill_cursor_date: nil,
last_synced_at: Time.current
)
HeartbeatImportSourceSyncJob.perform_now(source.id)
day_jobs = queued_jobs_for("HeartbeatImportSourceSyncDayJob")
scheduled_dates = day_jobs.map { |job| Date.iso8601(job.serialized_params.fetch("arguments").last) }
assert_equal 2, day_jobs.count
assert_includes scheduled_dates, Date.current
assert_includes scheduled_dates, Date.yesterday
end
test "day job imports and dedupes by fields_hash" do
user = User.create!(timezone: "UTC")
source = create_source(user: user, status: :syncing)
timestamp = Time.current.to_f
payload = [
{
entity: "src/a.rb",
type: "file",
category: "coding",
project: "alpha",
language: "Ruby",
editor: "VS Code",
time: timestamp
},
{
entity: "src/a.rb",
type: "file",
category: "coding",
project: "alpha",
language: "Ruby",
editor: "VS Code",
time: timestamp
}
]
stub_request(:get, "https://wakatime.com/api/v1/users/current/heartbeats")
.with(query: { "date" => Date.current.iso8601 })
.to_return(
status: 200,
body: { data: payload }.to_json,
headers: { "Content-Type" => "application/json" }
)
HeartbeatImportSourceSyncDayJob.perform_now(source.id, Date.current.iso8601)
assert_equal 1, user.heartbeats.where(source_type: :wakapi_import).count
assert source.reload.last_synced_at.present?
end
test "day job pauses source on auth errors" do
user = User.create!(timezone: "UTC")
source = create_source(user: user, status: :syncing)
stub_request(:get, "https://wakatime.com/api/v1/users/current/heartbeats")
.with(query: { "date" => Date.current.iso8601 })
.to_return(status: 401, body: "{}")
HeartbeatImportSourceSyncDayJob.perform_now(source.id, Date.current.iso8601)
source.reload
assert source.paused?
assert_not source.sync_enabled
assert_includes source.last_error_message, "Authentication failed"
end
test "day job marks transient errors for retry" do
user = User.create!(timezone: "UTC")
source = create_source(user: user, status: :syncing)
stub_request(:get, "https://wakatime.com/api/v1/users/current/heartbeats")
.with(query: { "date" => Date.current.iso8601 })
.to_return(status: 500, body: "{}")
assert_raises(WakatimeCompatibleClient::TransientError) do
HeartbeatImportSourceSyncDayJob.new.perform(source.id, Date.current.iso8601)
end
source.reload
assert source.failed?
assert_equal 1, source.consecutive_failures
end
test "coordinator does nothing when imports and mirrors are disabled" do
GoodJob::Job.delete_all
user = User.create!(timezone: "UTC")
source = create_source(user: user)
Flipper.disable(:wakatime_imports_mirrors)
HeartbeatImportSourceSyncJob.perform_now(source.id)
assert_equal 0, queued_jobs_for("HeartbeatImportSourceSyncDayJob").count
assert_equal "idle", source.reload.status
end
end