/test/unit/project_test.rb
Ruby | 661 lines | 513 code | 144 blank | 4 comment | 0 complexity | f952f6bc48b0f26c269f83100a94e75f MD5 | raw file
Possible License(s): Apache-2.0
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
- require 'date'
- require 'ostruct'
- require 'email_notifier'
- require 'fileutils'
- class ProjectTest < Test::Unit::TestCase
- include FileSandbox
- def setup
- @svn = FakeSourceControl.new
- @project = Project.new("lemmings")
- @project.source_control = @svn
- end
- def test_default_scheduler
- assert_equal PollingScheduler, @project.scheduler.class
- end
- def test_builds
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :directory => "build-1-success.in1s/"
- sandbox.new :directory => "build-10-success.in1s/"
- sandbox.new :directory => "build-3-failure.in1s/"
- sandbox.new :directory => "build-5-success.in1s/"
- sandbox.new :directory => "build-5.2-success.in1s/"
- sandbox.new :directory => "build-5.12-success.in1s/"
- assert_equal("1 - success - 1, 3 - failure - 3, 5 - success - 5, 5.2 - success - 5, 5.12 - success - 5, 10 - success - 10",
- @project.builds.collect {|b| "#{b.label} - #{b.status} - #{b.revision}"}.join(", "))
- assert_equal('10', @project.last_build.label)
- end
- end
-
- def test_project_should_know_last_complete_build
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :directory => "build-1-success.in1s/"
- sandbox.new :directory => "build-2-failure.in1s/"
- sandbox.new :directory => "build-3/"
- assert_equal '2', @project.last_complete_build.label
- end
- end
- def test_last_complete_build_should_return_nil_when_there_are_no_complete_builds
- in_sandbox do |sandbox|
- sandbox.new :directory => "build-3/"
- assert_nil @project.last_complete_build
- end
- end
- def test_builds_should_return_empty_array_when_project_has_no_builds
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- assert_equal [], @project.builds
- end
- end
-
- def test_should_build_with_no_logs
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- revision = new_revision(5)
- build = new_mock_build('5')
- build.stubs(:artifacts_directory).returns(sandbox.root)
-
- @project.stubs(:builds).returns([])
- @project.stubs(:config_modified?).returns(false)
- @svn.stubs(:latest_revision).returns(revision)
- @svn.expects(:update).with(revision)
- build.expects(:run)
- @project.build_if_necessary
- end
- end
- def test_build_if_necessary_should_generate_events
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- revision = new_revision(5)
- build = new_mock_build('5')
- build.stubs(:artifacts_directory).returns(sandbox.root)
- build.stubs(:successful?).returns(false)
- build.stubs(:failed?).returns(false)
- @project.stubs(:builds).returns([OpenStruct.new(:successful? => false, :failed? => false)])
- @project.stubs(:config_modified?).returns(false)
- @svn.stubs(:up_to_date?).with{|reasons| reasons << [revision]}.returns(false)
- @svn.stubs(:latest_revision).returns(revision)
- @svn.expects(:update).with(revision)
- build.expects(:run)
- # event expectations
- listener = Object.new
- listener.expects(:polling_source_control)
- listener.expects(:new_revisions_detected).with([revision])
- listener.expects(:build_started).with(build)
- listener.expects(:build_finished).with(build)
- listener.expects(:sleeping)
- @project.add_plugin listener
- @project.build_if_necessary
- end
- end
- def test_build_should_generate_event_when_build_loop_crashes
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- @project.expects(:builds).returns([])
- error = StandardError.new
- @svn.expects(:latest_revision).raises(error)
- # event expectations
- listener = Object.new
- listener.expects(:build_loop_failed).with(error)
- @project.add_plugin listener
- assert_raises(error) { @project.build_if_necessary }
- end
- end
-
- def test_build_should_fail_if_subversion_error
- in_sandbox do
- @project.path = sandbox.root
- error = StandardError.new("something bad happened")
- @project.expects(:update_project_to_revision).raises(error)
- assert_raises(error) { @project.build(new_revision(5)) }
-
- build = @project.builds.first
- assert build.failed?
- assert_equal "something bad happened", build.error
- end
- end
-
- def test_build_should_generate_event_when_build_is_broken
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- successful_build = stub_build(1)
- successful_build.stubs(:successful?).returns(true)
- successful_build.stubs(:failed?).returns(false)
- new_build = new_mock_build('2')
- new_build.stubs(:successful?).returns(false)
- new_build.stubs(:failed?).returns(true)
- new_build.expects(:run)
-
- @project.expects(:last_build).returns(successful_build)
- @project.stubs(:builds).returns([successful_build])
- @project.stubs(:log_changeset)
- @project.stubs(:new_revisions).returns(nil)
- @svn.stubs(:update)
- # event expectations
- listener = Object.new
- listener.expects(:build_started)
- listener.expects(:build_finished)
- listener.expects(:build_broken)
- @project.add_plugin listener
- @project.build(new_revision(2))
- end
- end
- def test_build_should_detect_config_modifications
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- revision = new_revision(1)
- @svn.expects(:update).with(@project, revision) do |*args|
- sandbox.new :file => 'work/cruise_config.rb'
- true
- end
- FileUtils.mkdir_p 'build-1-success.in40s'
- mock_build = Object.new
- Build.stubs(:new).returns(mock_build)
- mock_build.stubs(:label).returns("1")
- mock_build.expects(:artifacts_directory).returns('build-1-success.in40s')
- mock_build.expects(:abort)
- @project.stubs(:new_revisions).returns(nil)
-
- listener = Object.new
- listener.expects(:configuration_modified)
- @project.add_plugin listener
- assert_throws(:reload_project) { @project.build(revision) }
- end
- end
- def test_notify_should_create_plugin_error_log_if_plugin_fails_and_notify_has_a_build
- in_sandbox do |sandbox|
- @project.path = sandbox.root
-
- mock_build = Object.new
- mock_build.stubs(:artifacts_directory).returns(sandbox.root)
- listener = Object.new
- listener.expects(:build_finished).with(mock_build).raises(StandardError.new("Listener failed"))
- @project.add_plugin listener
- assert_raises('Error in plugin Object: Listener failed') { @project.notify(:build_finished, mock_build) }
- assert_match /^Listener failed at/, File.read("#{mock_build.artifacts_directory}/plugin_errors.log")
- end
- end
- def test_notify_should_not_fail_if_plugin_fails_and_notify_has_no_build_or_no_arguments_at_all
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- listener = Object.new
- listener.expects(:sleeping).raises(StandardError.new("Listener failed"))
- listener.expects(:doing_something).with(:foo).raises(StandardError.new("Listener failed with :foo"))
- @project.add_plugin listener
- assert_raises('Error in plugin Object: Listener failed') { @project.notify(:sleeping) }
- assert_raises('Error in plugin Object: Listener failed with :foo') { @project.notify(:doing_something, :foo) }
- end
- end
- def test_build_should_generate_event_when_build_is_fixed
- in_sandbox do |sandbox|
- @project.path = sandbox.root
-
- failing_build = stub_build(1)
- failing_build.stubs(:successful?).returns(false)
- failing_build.stubs(:failed?).returns(true)
- new_build = new_mock_build('2')
- new_build.stubs(:successful?).returns(true)
- new_build.stubs(:failed?).returns(false)
- new_build.expects(:run)
- @project.expects(:last_build).returns(failing_build)
- @project.stubs(:builds).returns([failing_build])
- @project.stubs(:log_changeset)
- @project.stubs(:new_revisions).returns(nil)
- @svn.stubs(:update)
- # event expectations
- listener = Object.new
- listener.expects(:build_started)
- listener.expects(:build_finished)
- listener.expects(:build_fixed)
- @project.add_plugin listener
- @project.build(new_revision(2))
- end
- end
- def test_should_build_when_logs_are_not_current
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- @project.stubs(:builds).returns([Build.new(@project, 1)])
- @project.stubs(:config_modified?).returns(false)
- revision = new_revision(2)
- build = new_mock_build('2')
- @project.stubs(:last_build).returns(nil)
- build.stubs(:artifacts_directory).returns(sandbox.root)
- @svn.stubs(:up_to_date?).with([]).returns(false)
- @svn.expects(:update).with(revision)
- @svn.expects(:latest_revision).returns(revision)
- build.expects(:run)
- @project.build_if_necessary
- end
- end
- def test_should_not_build_when_logs_are_current
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- @project.stubs(:config_modified?).returns(false)
- @project.stubs(:builds).returns([Build.new(@project, 2)])
- @svn.stubs(:revisions_since).with(@project, 2).returns([])
- @project.expects(:build).never
- @project.build_if_necessary
- end
- end
-
- def test_either_rake_task_or_build_command_can_be_set_but_not_both
- @project.rake_task = 'foo'
- assert_raises("Cannot set build_command when rake_task is already defined") do
- @project.build_command = 'foo'
- end
- @project.rake_task = nil
- @project.build_command = 'foo'
- assert_raises("Cannot set rake_task when build_command is already defined") do
- @project.rake_task = 'foo'
- end
- end
- def test_notify_should_handle_plugin_error
- plugin = Object.new
-
- @project.plugins << plugin
-
- plugin.expects(:hey_you).raises("Plugin talking")
-
- assert_raises("Error in plugin Object: Plugin talking") { @project.notify(:hey_you) }
- end
- def test_notify_should_handle_multiple_plugin_errors
- plugin1 = Object.new
- plugin2 = Object.new
-
- @project.plugins << plugin1 << plugin2
-
- plugin1.expects(:hey_you).raises("Plugin 1 talking")
- plugin2.expects(:hey_you).raises("Plugin 2 talking")
- assert_raises("Errors in plugins:\n Object: Plugin 1 talking\n Object: Plugin 2 talking") { @project.notify(:hey_you) }
- end
- def test_request_build_should_start_builder_if_builder_was_down
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- @project.expects(:builder_state_and_activity).times(2).returns('builder_down', 'sleeping')
- BuilderStarter.expects(:begin_builder).with(@project.name)
- @project.request_build
- end
- end
- def test_request_build_should_generate_build_requested_file_and_notify_listeners
- @project.stubs(:builder_state_and_activity).returns('sleeping')
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- listener = Object.new
- listener.expects(:build_requested)
- @project.add_plugin listener
- @project.request_build
- assert File.file?(@project.build_requested_flag_file)
- end
- end
-
- def test_request_build_should_not_notify_listeners_when_a_build_requested_flag_is_already_set
- @project.stubs(:builder_state_and_activity).returns('building')
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :file => 'build_requested'
- listener = Object.new
- listener.expects(:build_requested).never
-
- @project.expects(:build_requested?).returns(true)
- @project.expects(:create_build_requested_flag_file).never
- @project.request_build
- end
- end
-
- def test_build_if_requested_should_build_if_build_requested_file_exists
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :file => 'build_requested'
- @project.expects(:remove_build_requested_flag_file)
- @project.expects(:build)
- @project.build_if_requested
- end
- end
-
- def test_build_requested
- @project.stubs(:path).returns("a_path")
- File.expects(:file?).with(@project.build_requested_flag_file).returns(true)
- assert @project.build_requested?
- end
-
- def test_build_should_generate_new_label_if_same_name_label_exists
- existing_build1 = stub_build('20')
- existing_build2 = stub_build('20.1')
- new_build = stub_build('20.2')
- new_build_with_interesting_number = stub_build('2')
-
- project = Project.new('project1', @svn)
- @svn.stubs(:update)
- project.stubs(:log_changeset)
- project.stubs(:builds).returns([existing_build1, existing_build2])
- project.stubs(:last_build).returns(nil)
- project.stubs(:new_revisions).returns(nil)
-
- Build.expects(:new).with(project, '20.2').returns(new_build)
- project.build(new_revision(20))
- Build.expects(:new).with(project, '2').returns(new_build)
- project.build(new_revision(2))
- end
-
- def test_should_load_configuration_from_work_directory_and_then_root_directory
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- begin
- sandbox.new :file => 'work/cruise_config.rb', :with_contents => '$foobar=42; $barfoo = 12345'
- sandbox.new :file => 'cruise_config.rb', :with_contents => '$barfoo = 54321'
- @project.load_config
- assert_equal 42, $foobar
- assert_equal 54321, $barfoo
- ensure
- $foobar = $barfoo = nil
- end
- end
- end
-
- def test_should_mark_config_invalid_if_exception_raised_during_load_config
- in_sandbox do |sandbox|
- invalid_ruby_code = 'class Invalid'
- @project.path = sandbox.root
- sandbox.new :file => 'work/cruise_config.rb', :with_contents => invalid_ruby_code
- @project.load_config
- assert @project.settings.empty?
- assert_equal invalid_ruby_code, @project.config_file_content.strip
- assert !@project.config_valid?
- assert_match /Could not load project configuration:/, @project.error_message
- end
- end
-
- def test_should_remember_settings
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :file => 'work/cruise_config.rb', :with_contents => 'good = 4'
- sandbox.new :file => 'cruise_config.rb', :with_contents => 'time = 5'
- @project.load_config
- assert_equal "good = 4\ntime = 5\n", @project.settings
- assert @project.config_valid?
- assert @project.error_message.empty?
- end
- end
-
- def test_last_complete_build_status_should_be_failed_if_builder_status_is_fatal
- builder_status = Object.new
- builder_status.expects(:"fatal?").returns(true)
- BuilderStatus.expects(:new).with(@project).returns(builder_status)
- assert_equal "failed", @project.last_complete_build_status
- end
-
-
- def test_should_be_able_to_get_previous_build
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :directory => "build-1-success/"
- sandbox.new :directory => "build-2-failure/"
- sandbox.new :directory => "build-3"
-
- build = @project.find_build('2')
- assert_equal('1', @project.previous_build(build).label)
-
- build = @project.find_build('1')
- assert_equal(nil, @project.previous_build(build))
- end
- end
-
- def test_should_be_able_to_get_next_build
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :directory => "build-1-success.in1s/"
- sandbox.new :directory => "build-2-failure.in1s/"
- sandbox.new :directory => "build-3/"
-
- build = @project.find_build('1')
- assert_equal('2', @project.next_build(build).label)
-
- build = @project.find_build('2')
- assert_equal('3', @project.next_build(build).label)
-
- build = @project.find_build('3')
- assert_equal(nil, @project.next_build(build))
- end
- end
-
- def test_should_be_able_to_get_last_n_builds
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- sandbox.new :directory => "build-1-success.in1s/"
- sandbox.new :directory => "build-2-failure.in1s/"
- sandbox.new :directory => "build-3/"
-
- assert_equal 2, @project.last_builds(2).length
- assert_equal 3, @project.last_builds(5).length
- end
- end
- def test_should_do_clean_checkout_if_flag_is_set
- in_sandbox do |sandbox|
- @project.do_clean_checkout :always
- @project.path = sandbox.root
- @svn.expects(:clean_checkout).with(Revision.new(5), anything)
- @project.build(new_revision(5))
- end
- end
-
- def test_build_when_no_revision_yet
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- @svn.stubs(:latest_revision).returns(nil)
- assert_nil @project.build
- end
- end
-
- def test_build_should_still_build_even_when_no_changes_were_made
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- @project.stubs(:builds).returns [stub_build(1), stub_build(2)]
- @svn.stubs(:revisions_since).returns([])
- @svn.stubs(:latest_revision).returns(new_revision(2))
- @svn.expects(:update)
- assert @project.build
- end
- end
- def test_do_clean_checkout_every_x_hours
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- marker = sandbox.root + '/last_clean_checkout_timestamp'
-
- now = Time.now
- Time.stubs(:now).returns(now)
- @project.do_clean_checkout :every => 1.hour
-
- assert @project.do_clean_checkout?
- assert !@project.do_clean_checkout?
- assert !@project.do_clean_checkout?
-
- now += 59.minutes
- Time.stubs(:now).returns(now)
- assert !@project.do_clean_checkout?
-
- now += 2.minutes
- Time.stubs(:now).returns(now)
- assert @project.do_clean_checkout?
- assert !@project.do_clean_checkout?
- @project.do_clean_checkout :every => 2.days
- now += 1.day + 23.hours
- Time.stubs(:now).returns(now)
- assert !@project.do_clean_checkout?
- now += 2.hours
- Time.stubs(:now).returns(now)
- assert @project.do_clean_checkout?
- end
- end
-
- def increment_time_by(seconds)
- now = Time.now
- Time.stubs(:now).returns(now + seconds)
- File.stubs(:mtime).returns(now + seconds)
- end
- def test_do_clean_checkout_always
- in_sandbox do |sandbox|
- @project.path = sandbox.root
- assert !@project.do_clean_checkout?, "by default should be off"
-
- @project.do_clean_checkout
-
- assert @project.do_clean_checkout?
- assert @project.do_clean_checkout?
- end
- end
- def test_new_project_should_have_source_control_triggers
- project = Project.new('foo')
- trigger_classes = project.triggered_by.map(&:class)
- assert_equal [ChangeInSourceControlTrigger], trigger_classes
- end
- def test_project_triggered_by
- project = Project.new('foo')
- project.triggered_by = []
- assert_equal [], project.triggered_by
- project.triggered_by 1
- assert_equal [1], project.triggered_by
- project.triggered_by 2, 3
- assert_equal [1, 2, 3], project.triggered_by
- end
- def test_project_triggered_by_should_convert_strings_and_symbols_to_successful_build_triggers
- project = Project.new('foo')
- project.triggered_by = ['foo', 123]
- project.triggered_by :bar
- project.triggered_by << :baz
- assert_equal [SuccessfulBuildTrigger.new(project, 'foo'), 123, SuccessfulBuildTrigger.new(project, 'bar'),
- SuccessfulBuildTrigger.new(project, 'baz')],
- project.triggered_by
- end
- def test_builds_are_serialized
- Configuration.stubs(:serialize_builds).returns(true)
- project = Project.new("test")
- BuildSerializer.expects(:serialize).yields
- project.expects(:build_without_serialization)
- project.build []
- end
-
- def test_keep_scm_and_path_in_sync
- assert_equal(@project.path + "/work", @svn.path)
- @project.path = "foo"
- assert_equal(File.expand_path("foo/work"), @svn.path)
- end
-
- private
-
- def stub_build(label)
- build = Object.new
- build.stubs(:label).returns(label)
- build.stubs(:artifacts_directory).returns("project1/build-#{label}")
- build.stubs(:run)
- build.stubs(:successful?).returns(true)
- build
- end
- def new_revision(number)
- Revision.new(number, 'alex', DateTime.new(2005, 1, 1), 'message', [])
- end
- def new_mock_build(label)
- build = Object.new
- Build.expects(:new).with(@project, label).returns(build)
- build.stubs(:artifacts_directory).returns("project1/build-#{label}")
- build.stubs(:last).returns(nil)
- build.stubs(:label).returns(label)
- build
- end
- end