# frozen_string_literal: true

require_relative "helper"
require "sidekiq/api"
require "sidekiq/rails"
require "sidekiq/transaction_aware_client"

require_relative "./dummy/config/environment"

class Schema < ActiveRecord::Migration["6.1"]
  def change
    create_table :posts do |t|
      t.string :title
      t.date :published_date
    end
  end
end

class PostJob
  include Sidekiq::Job
  def perform
  end
end

class AlwaysDeferredJob
  include Sidekiq::Job
  sidekiq_options client_class: Sidekiq::TransactionAwareClient

  def perform
  end
end

class AlwaysPushedJob
  include Sidekiq::Job
  sidekiq_options client_class: Sidekiq::Client

  def perform
  end
end

class Post < ActiveRecord::Base
  after_create :do_thing

  def do_thing
    PostJob.perform_async
  end
end

unless Post.connection.tables.include? "posts"
  Schema.new.change
end

describe Sidekiq::TransactionAwareClient do
  before do
    Sidekiq.redis { |c| c.flushdb }
    @app = Dummy::Application.new
    Post.delete_all
  end

  after do
    Sidekiq.default_job_options.delete("client_class")
  end

  describe ActiveRecord do
    it "pushes immediately by default" do
      q = Sidekiq::Queue.new
      assert_equal 0, q.size

      @app.executor.wrap do
        ActiveRecord::Base.transaction do
          Post.create!(title: "Hello", published_date: Date.today)
        end
      end
      assert_equal 1, q.size
      assert_equal 1, Post.count

      @app.executor.wrap do
        ActiveRecord::Base.transaction do
          Post.create!(title: "Hello", published_date: Date.today)
          raise ActiveRecord::Rollback
        end
      end
      assert_equal 2, q.size
      assert_equal 1, Post.count
    end

    it "can defer push within active transactions" do
      Sidekiq.transactional_push!
      q = Sidekiq::Queue.new
      assert_equal 0, q.size

      @app.executor.wrap do
        ActiveRecord::Base.transaction do
          Post.create!(title: "Hello", published_date: Date.today)
        end
      end
      assert_equal 1, q.size
      assert_equal 1, Post.count

      @app.executor.wrap do
        ActiveRecord::Base.transaction do
          Post.create!(title: "Hello", published_date: Date.today)
          raise ActiveRecord::Rollback
        end
      end
      assert_equal 1, q.size
      assert_equal 1, Post.count
    end

    it "defers push when enabled on a per job basis" do
      q = Sidekiq::Queue.new
      assert_equal 0, q.size

      @app.executor.wrap do
        ActiveRecord::Base.transaction do
          AlwaysDeferredJob.perform_async
          raise ActiveRecord::Rollback
        end
      end
      assert_equal 0, q.size
    end

    it "pushes immediately when disabled on a per job basis" do
      Sidekiq.transactional_push!
      q = Sidekiq::Queue.new
      assert_equal 0, q.size

      @app.executor.wrap do
        ActiveRecord::Base.transaction do
          AlwaysPushedJob.perform_async
          raise ActiveRecord::Rollback
        end
      end
      assert_equal 1, q.size
    end
  end
end