# frozen_string_literal: true

require "sidekiq_long_running_job_logger"

RSpec.describe SidekiqLongRunningJobLogger do
  let(:fake_logger) { FakeLogger.new }

  before { Rails.logger.broadcast_to(fake_logger) }

  after { Rails.logger.stop_broadcasting_to(fake_logger) }

  it "logs long-running jobs" do
    hostname = Discourse.os_hostname
    stuck_sidekiq_job_minutes = 10

    Sidekiq::Workers
      .expects(:new)
      .returns(
        [
          [
            "#{hostname}:1234",
            "some_sidekiq_id",
            Sidekiq::Work.new(
              "#{hostname}:1234",
              "some_sidekiq_id",
              {
                "run_at" => (Time.now - (60 * (stuck_sidekiq_job_minutes + 1))).to_i,
                "payload" => Sidekiq.dump_json({ "jid" => "job_1", "class" => "TestWorker" }),
              },
            ),
          ],
          [
            "#{hostname}:1234",
            "some_other_sidekiq_id",
            Sidekiq::Work.new(
              "#{hostname}:1234",
              "some_other_sidekiq_id",
              {
                "run_at" => Time.now.to_i,
                "payload" => Sidekiq.dump_json({ "jid" => "job_2", "class" => "AnotherWorker" }),
              },
            ),
          ],
        ],
      )
      .twice

    thread = mock("Thread")
    thread.expects(:[]).with("sidekiq_tid").returns("some_sidekiq_id").once
    thread.expects(:backtrace).returns(%w[line lines]).once
    Thread.expects(:list).returns([thread]).once

    begin
      checker = described_class.new(stuck_sidekiq_job_minutes:)

      loops = 0

      checker.start { loops += 1 }

      wait_for { loops == 1 }

      expect(fake_logger.warnings.size).to eq(1)

      expect(fake_logger.warnings).to include(
        "Sidekiq job `TestWorker` has been running for more than 10 minutes\nline\nlines\n",
      )

      checker.thread.wakeup # Force the thread to run the next loop

      wait_for { loops == 2 }

      expect(fake_logger.warnings.size).to eq(1)

      expect(fake_logger.warnings).to include(
        "Sidekiq job `TestWorker` has been running for more than 10 minutes\nline\nlines\n",
      )
    ensure
      checker.stop
    end
  end
end
