require 'test_helper'

class JobTest < Test::Unit::TestCase

  context "A CloudCrowd Job" do
        
    setup do
      @job = Job.make!
      @unit = @job.work_units.first
    end
    
    subject { @job }
    
    should have_many(:work_units)
    
    [:status, :inputs, :action, :options].each do |field|
      should validate_presence_of(field)
    end
    
    should "create all of its work units as soon as the job is created" do
      assert @job.work_units.count >= 1
      assert @job.percent_complete == 0
      assert @job.processing?
      assert @unit.processing?
      assert !@job.all_work_units_complete?
    end
    
    should "know its completion status" do
      assert !@job.all_work_units_complete?
      @unit.update_attributes(:status => SUCCEEDED, :output => '{"output":"hello"}')
      @job.check_for_completion
      assert @job.reload.all_work_units_complete?
      assert @job.percent_complete == 100
      assert @job.outputs == "[\"hello\"]"
    end

    should "not throw a FloatDomainError, even when WorkUnits have vanished" do
      @job.work_units.destroy_all
      assert @job.percent_complete == 100
    end
    
    should "be able to create a job from a JSON request" do
      job = Job.create_from_request(JSON.parse(<<-EOS
      { "inputs"       : ["one", "two", "three"],
        "action"       : "graphics_magick",
        "email"        : "bob@example.com",
        "callback_url" : "http://example.com/callback" }
      EOS
      ))
      assert job.work_units.count == 3
      assert job.action == 'graphics_magick'
      assert job.action_class == GraphicsMagick
      assert job.callback_url == "http://example.com/callback"
    end
    
    should "be able to return a comprehensive JSON representation" do
      json = JSON.parse(@job.to_json)
      assert json['email'] == 'noone@example.com'
      assert json['percent_complete'] == 0
      assert json['work_units'] == 1
      assert json['time_taken'] > 0
    end
    
    should "create jobs with a SPLITTING status for actions that have a split method defined" do
      job = Job.create_from_request({'inputs' => ['1'], 'action' => 'process_pdfs'})
      assert job.splittable?
      assert job.splitting?
    end
    
    should "not accidentally flatten array inputs" do
      job = Job.create_from_request({'inputs' => [[1,2], [3,4]], 'action' => 'process_pdfs'})
      assert JSON.parse(job.work_units.first.input) == [1,2]
    end
    
    should "fire a callback when a job has finished, successfully or not" do
      @job.update_attribute(:callback_url, 'http://example.com/callback')
      Job.any_instance.stubs(:fire_callback).returns(true)
      Job.any_instance.expects(:fire_callback)
      @job.work_units.first.finish('{"output":"output"}', 10)
      assert @job.all_work_units_complete?
    end
    
    should "have a 'pretty' display of the Job's status" do
      assert @job.display_status == 'processing'
      @job.update_attribute(:status, FAILED)
      assert @job.display_status == 'failed'
      @job.update_attribute(:status, MERGING)
      assert @job.display_status == 'merging'
    end
    
    should "be able to clean up jobs that have aged beyond their use" do
      Job.cleanup_all
      count = Job.count
      @job.update_attributes({:status => SUCCEEDED, :updated_at => 10.days.ago })
      assert @job.status == SUCCEEDED
      Job.cleanup_all
      assert count > Job.count
      assert !Job.find_by_id(@job.id)
    end
            
  end
  
end