app/workers/snapshot_comparer_worker.rb
require 'open-uri'
# Worker that takes care of comparing the snapshot image against the baseline.
# This worker is responsible for updating the snapshot instance with the result
# of the snapshot comparison.
class SnapshotComparerWorker < SnapshotWorker
  def perform(snapshot_id)
    return unless set_snapshot(snapshot_id)
    return unless @snapshot.compare?

    url          = @snapshot.url
    viewport     = @snapshot.viewport
    compare_with = @snapshot.compared_with || url.baseline(viewport)

    Rails.logger.info "Comparing snapshot of #{url} @ #{viewport} " +
                      'against baseline'
    comparison = Diffux::SnapshotComparer.new(to_chunky_png(compare_with),
                                              to_chunky_png(@snapshot)).compare!
    diff = @snapshot.build_snapshot_diff(comparison.slice(:diff_in_percent))
    diff.before_snapshot = compare_with
    diff_image = comparison[:diff_image]
    if diff_image
      diff.image_height = diff_image.height
      diff.image_width  = diff_image.width
      FileUtil.with_tempfile do |tempfile|
        diff_image.save(tempfile)
        diff.image = File.open(tempfile)
      end
    end
    @snapshot.accept if diff.diff_in_percent == 0

    @snapshot.transaction do
      diff.save!
      comparison[:diff_clusters].each do |cluster|
        diff.snapshot_diff_clusters.create!(cluster)
      end
      @snapshot.compared_with = compare_with
      @snapshot.save!
    end
  end

  private

  # @param snapshot [Snapshot]
  # @return [ChunkyPNG::Image]
  def to_chunky_png(snapshot)
    case snapshot.image.options[:storage]
    when :s3
      ChunkyPNG::Image.from_io(open(snapshot.image.url))
    when :filesystem
      ChunkyPNG::Image.from_file(snapshot.image.path)
    end
  end
end
