mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-19 16:38:23 +00:00
195 lines
6.1 KiB
Ruby
195 lines
6.1 KiB
Ruby
require "test_helper"
|
|
|
|
class HeartbeatImportRunnerTest < ActiveSupport::TestCase
|
|
include ActiveJob::TestHelper
|
|
|
|
setup do
|
|
ActionMailer::Base.deliveries.clear
|
|
@original_queue_adapter = ActiveJob::Base.queue_adapter
|
|
ActiveJob::Base.queue_adapter = :test
|
|
end
|
|
|
|
teardown do
|
|
ActionMailer::Base.deliveries.clear
|
|
clear_enqueued_jobs
|
|
ActiveJob::Base.queue_adapter = @original_queue_adapter
|
|
end
|
|
|
|
test "run_import emails the user when a wakatime import succeeds" do
|
|
user = User.create!(timezone: "UTC")
|
|
user.email_addresses.create!(email: "success-#{SecureRandom.hex(4)}@example.com", source: :signing_in)
|
|
run = user.heartbeat_import_runs.create!(
|
|
source_kind: :wakatime_dump,
|
|
state: :queued,
|
|
encrypted_api_key: "secret"
|
|
)
|
|
|
|
file = Tempfile.new([ "heartbeats", ".json" ])
|
|
file.write(
|
|
{
|
|
heartbeats: [
|
|
{
|
|
entity: "/tmp/test.rb",
|
|
type: "file",
|
|
time: 1_700_000_000.0,
|
|
project: "hackatime",
|
|
language: "Ruby",
|
|
is_write: true
|
|
}
|
|
]
|
|
}.to_json
|
|
)
|
|
file.close
|
|
|
|
HeartbeatImportRunner.run_import(import_run_id: run.id, file_path: file.path)
|
|
|
|
run.reload
|
|
assert_equal "completed", run.state
|
|
assert_nil run.encrypted_api_key
|
|
assert_enqueued_jobs 1, only: ActionMailer::MailDeliveryJob
|
|
ensure
|
|
file&.unlink
|
|
end
|
|
|
|
test "run_import does not overwrite a completed run if completion follow-up fails" do
|
|
user = User.create!(timezone: "UTC")
|
|
user.email_addresses.create!(email: "post-complete-#{SecureRandom.hex(4)}@example.com", source: :signing_in)
|
|
run = user.heartbeat_import_runs.create!(
|
|
source_kind: :wakatime_dump,
|
|
state: :queued,
|
|
encrypted_api_key: "secret"
|
|
)
|
|
|
|
file = Tempfile.new([ "heartbeats", ".json" ])
|
|
file.write(
|
|
{
|
|
heartbeats: [
|
|
{
|
|
entity: "/tmp/test.rb",
|
|
type: "file",
|
|
time: 1_700_000_000.0,
|
|
project: "hackatime",
|
|
language: "Ruby",
|
|
is_write: true
|
|
}
|
|
]
|
|
}.to_json
|
|
)
|
|
file.close
|
|
|
|
singleton_class = HeartbeatImportRunner.singleton_class
|
|
singleton_class.alias_method :__original_send_completion_email_for_test, :send_completion_email
|
|
singleton_class.define_method(:send_completion_email) do |_completed_run|
|
|
raise "mail transport failed"
|
|
end
|
|
|
|
begin
|
|
HeartbeatImportRunner.run_import(import_run_id: run.id, file_path: file.path)
|
|
ensure
|
|
singleton_class.alias_method :send_completion_email, :__original_send_completion_email_for_test
|
|
singleton_class.remove_method :__original_send_completion_email_for_test
|
|
file&.unlink
|
|
end
|
|
|
|
run.reload
|
|
assert_equal "completed", run.state
|
|
assert_nil run.error_message
|
|
assert_nil run.encrypted_api_key
|
|
assert_empty ActionMailer::Base.deliveries
|
|
end
|
|
|
|
test "fail_run_for_error! emails the user about invalid api keys" do
|
|
user = User.create!(timezone: "UTC")
|
|
user.email_addresses.create!(email: "invalid-key-#{SecureRandom.hex(4)}@example.com", source: :signing_in)
|
|
run = user.heartbeat_import_runs.create!(
|
|
source_kind: :wakatime_dump,
|
|
state: :queued,
|
|
encrypted_api_key: "secret"
|
|
)
|
|
|
|
HeartbeatImportRunner.fail_run_for_error!(
|
|
import_run_id: run.id,
|
|
error: HeartbeatImportDumpClient::AuthenticationError.new("Authentication failed (401)", status: 401)
|
|
)
|
|
|
|
run.reload
|
|
assert_equal "failed", run.state
|
|
assert_equal "WakaTime rejected the import because the API key is invalid.", run.error_message
|
|
assert_nil run.encrypted_api_key
|
|
assert_enqueued_jobs 1, only: ActionMailer::MailDeliveryJob
|
|
end
|
|
|
|
test "fail_run_for_error! includes slack guidance for hackatime v1 provider errors" do
|
|
user = User.create!(timezone: "UTC")
|
|
user.email_addresses.create!(email: "provider-error-#{SecureRandom.hex(4)}@example.com", source: :signing_in)
|
|
run = user.heartbeat_import_runs.create!(
|
|
source_kind: :hackatime_v1_dump,
|
|
state: :queued,
|
|
encrypted_api_key: "secret"
|
|
)
|
|
|
|
HeartbeatImportRunner.fail_run_for_error!(
|
|
import_run_id: run.id,
|
|
error: HeartbeatImportDumpClient::TransientError.new("Request failed with status 500", status: 500)
|
|
)
|
|
|
|
run.reload
|
|
assert_equal "failed", run.state
|
|
assert_equal "Hackatime v1 ran into an error while processing the import. Please reach out to #hackatime-help on Slack.", run.error_message
|
|
assert_nil run.encrypted_api_key
|
|
assert_enqueued_jobs 1, only: ActionMailer::MailDeliveryJob
|
|
end
|
|
|
|
test "start_remote_import bypasses cooldown for superadmins" do
|
|
user = User.create!(timezone: "UTC", admin_level: :superadmin)
|
|
Flipper.enable_actor(:imports, user)
|
|
|
|
user.heartbeat_import_runs.create!(
|
|
source_kind: :wakatime_dump,
|
|
state: :completed,
|
|
encrypted_api_key: "old-secret",
|
|
remote_requested_at: 1.minute.ago
|
|
)
|
|
|
|
assert_difference -> { user.heartbeat_import_runs.count }, +1 do
|
|
run = HeartbeatImportRunner.start_remote_import(
|
|
user: user,
|
|
provider: "wakatime_dump",
|
|
api_key: "new-secret"
|
|
)
|
|
|
|
assert_equal "wakatime_dump", run.source_kind
|
|
assert_equal "queued", run.state
|
|
end
|
|
end
|
|
|
|
test "serialize omits cooldown for superadmins" do
|
|
user = User.create!(timezone: "UTC", admin_level: :superadmin)
|
|
run = user.heartbeat_import_runs.create!(
|
|
source_kind: :wakatime_dump,
|
|
state: :completed,
|
|
encrypted_api_key: "secret",
|
|
remote_requested_at: 1.minute.ago
|
|
)
|
|
|
|
payload = HeartbeatImportRunner.serialize(run)
|
|
|
|
assert_nil payload[:cooldown_until]
|
|
end
|
|
|
|
test "refreshable_remote_run? stops once a remote import is downloading or importing" do
|
|
%i[downloading_dump importing].each do |state|
|
|
user = User.create!(timezone: "UTC")
|
|
Flipper.enable_actor(:imports, user)
|
|
|
|
run = user.heartbeat_import_runs.create!(
|
|
source_kind: :wakatime_dump,
|
|
state: state,
|
|
encrypted_api_key: "secret"
|
|
)
|
|
run.update_column(:updated_at, 10.seconds.ago)
|
|
|
|
assert_not HeartbeatImportRunner.refreshable_remote_run?(run)
|
|
end
|
|
end
|
|
end
|