xcb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
File without changes
data/bin/xcb ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ gem 'xcb'
4
+
5
+
6
+ require 'xcb_command'
7
+
8
+ config = StackingConfig.load(".xcb.yaml") <<
9
+ StackingConfig.load("config/xcb.yaml") <<
10
+ StackingConfig.load(ENV["HOME"] + "/.xcb.conf") <<
11
+ StackingConfig.load("/etc/xcb.conf")
12
+
13
+ xcb = XCB.new(config)
14
+
15
+ case ARGV.shift
16
+ when nil, "", "build"
17
+ status = xcb.build
18
+ puts status.inspect
19
+ exit (status == :succesful)
20
+ when "clean"
21
+ xcb.clean
22
+ when "start"
23
+ xcb.start_building
24
+ when "stop"
25
+ xcb.stop_building
26
+ when "growltest"
27
+ ExtremeContinuousBuilder::GrowlNotifier.setup config
28
+ ExtremeContinuousBuilder::GrowlNotifier.instance.notify :succesful, "Test OK"
29
+ puts "You should see a notification"
30
+
31
+ else
32
+ puts "Commands:"
33
+ puts "\tbuild:\tPerforms one build"
34
+ puts "\tstart:\tStarts building the the background"
35
+ puts "\tstop:\tStops building in the background"
36
+ puts "\tclean:\tClears out PIDs and logs"
37
+ puts
38
+ exit 1
39
+ end
@@ -0,0 +1,30 @@
1
+ class DirectoryMonitor
2
+ def initialize(dir, ops = {})
3
+ @base_dir = dir
4
+ @mtimes = nil
5
+ @ignore = [ops[:ignore]].flatten.compact
6
+ update! if ops[:update]
7
+ end
8
+
9
+ def has_changes?
10
+ old_mtimes = @mtimes
11
+ @last_result = old_mtimes != update!
12
+ had_changes?
13
+ end
14
+
15
+ def had_changes?
16
+ @last_result
17
+ end
18
+
19
+ def update!
20
+ ignore_list = @ignore.map{|ig| Dir.glob(ig)}.flatten.map{|f|File.expand_path f}
21
+ files = Dir.glob(File.join(@base_dir, "**/*")).map{|f|File.expand_path f}
22
+ @mtimes = files.inject({}) do |result, file|
23
+ if ignore_list.include? file
24
+ result
25
+ else
26
+ result.merge( { file => File.mtime(file) } )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,108 @@
1
+ require File.dirname(__FILE__) + '/notifiers'
2
+ require "timeout"
3
+
4
+ module ExtremeContinuousBuilder
5
+ class Build
6
+ attr_reader :output, :success, :status
7
+
8
+ def initialize(options = {})
9
+ @options = options
10
+ @log_file_path = options[:log_file_path]
11
+ @lock_file_path = options[:lock_file_path]
12
+ @status = Status.new(log_file_path)
13
+ end
14
+
15
+ # Runs the tests, returns one of the fiollowing:
16
+ # ::failed: The test started failing
17
+ # ::broken: The test is still failing
18
+ # ::succesful: The test is still working
19
+ # ::revived: The test started working, you fixed it
20
+ def run
21
+ under_lock do
22
+ previous_status = @status.recall
23
+
24
+ if status = make
25
+ @status.keep(:succesful)
26
+ (previous_status == :succesful or previous_status == false) ? :succesful : :revived
27
+ else
28
+ @status.keep(:failed)
29
+ previous_status == :failed ? :broken : :failed
30
+ end
31
+ end
32
+ end
33
+
34
+ def clean
35
+ File.delete log_file_path if File.exist? log_file_path
36
+ File.delete lock_file_path if File.exist? lock_file_path
37
+ end
38
+
39
+ private
40
+ def log_file_path
41
+ @log_file_path ||= File.join(@options[:application_root], ".last_build.log")
42
+ end
43
+
44
+ def lock_file_path
45
+ @lock_file_path ||= File.join(@options[:application_root], '.continuous_builder.pid')
46
+ end
47
+
48
+ def make
49
+ @output = `cd #{@options[:application_root]} && #{@options[:bin_path]}rake #{@options[:task_name]} 2>&1`
50
+ make_successful?
51
+ end
52
+
53
+ def make_successful?
54
+ $?.exitstatus == 0
55
+ end
56
+
57
+ def under_lock
58
+ wait_for_lock
59
+
60
+ begin
61
+ grab_lock
62
+ yield
63
+ ensure
64
+ release_lock
65
+ end
66
+ end
67
+
68
+ def wait_for_lock
69
+ begin
70
+ Timeout::timeout(600) do # timeout after 10 minutes
71
+ while File.exists?(lock_file_path)
72
+ sleep(2) # check back after 10 seconds
73
+ end
74
+ end
75
+ rescue Timeout::Error
76
+ exit(1) # abort build
77
+ end
78
+ end
79
+
80
+ def grab_lock
81
+ File.open(lock_file_path, 'w') { |f| f << $$ }
82
+ end
83
+
84
+ def release_lock
85
+ File.delete(lock_file_path)
86
+ end
87
+ end
88
+
89
+ class Status
90
+ def initialize(path)
91
+ @path = path
92
+ end
93
+
94
+ def keep(status)
95
+ File.open(@path, "w+", 0777) { |file| file.write(status.to_s) }
96
+ end
97
+
98
+ def recall
99
+ if File.exists?(@path)
100
+ value = File.read(@path)
101
+ value.empty? ? false : value.to_sym
102
+ else
103
+ false
104
+ end
105
+ end
106
+ end
107
+ end
108
+
@@ -0,0 +1,111 @@
1
+ require 'rubygems'
2
+ gem 'ruby-growl'
3
+ require 'ruby-growl'
4
+ require 'singleton'
5
+
6
+ module ExtremeContinuousBuilder
7
+ def self.notifiers
8
+ constants.select{|c|c =~ /.+Notifier$/}.map{|name| const_get(name).instance}
9
+ end
10
+
11
+
12
+ class Notifier
13
+ include Singleton
14
+ def setup(settings)
15
+ end
16
+
17
+ def self.setup(settings)
18
+ instance.setup(settings) if instance.respond_to? :setup
19
+ end
20
+
21
+ BUILD_RESULT_TYPES = [:failed, :broken, :succesful, :revived]
22
+
23
+ #declare noop methods
24
+ BUILD_RESULT_TYPES.each do |name|
25
+ code = lambda{|build|}
26
+ define_method name, code
27
+ end
28
+ end
29
+
30
+ class GrowlNotifier < Notifier
31
+ def setup(settings)
32
+ @application_name = settings[:application_name]
33
+ growl_host = settings[:growl_host] || "localhost"
34
+ growl_password = settings[:growl_password]
35
+ @has_been_setup = true
36
+
37
+ @growl_notifier = Growl.new(growl_host, "XCB",
38
+ BUILD_RESULT_TYPES.map{|sym| sym.to_s}, nil, growl_password)
39
+ nil
40
+ end
41
+
42
+ BUILD_RESULT_TYPES.each do |name|
43
+ code = lambda do |build|
44
+ notify name, build.output
45
+ end
46
+ define_method name, code
47
+ end
48
+
49
+ def notify(type, text)
50
+ notifier.notify type.to_s, format_title(type), build_summary(text)
51
+ end
52
+
53
+ private
54
+ LINE_TO_LOOK_FOR = /[0-9]+ tests, [0-9]+ assertions, [0-9]+ failures, [0-9]+ errors/
55
+ def build_summary(text)
56
+ text.split("\n").select{|l| l =~ LINE_TO_LOOK_FOR }.join("\n")
57
+ end
58
+
59
+ def format_title(type)
60
+ "[#{@application_name}] Build #{type.to_s}"
61
+ end
62
+
63
+ def notifier=(n)
64
+ @growl_notifier = n
65
+ end
66
+
67
+ def notifier
68
+ @growl_notifier
69
+ end
70
+ end
71
+
72
+
73
+ class TextFileNotifier < Notifier
74
+ def setup(options)
75
+ @application_name = options[:application_name]
76
+ @text_file_path = options[:text_file_path]
77
+ @has_been_setup = true
78
+ end
79
+
80
+ def failed(build)
81
+ update_file "[#{@application_name}] Build failed", build.output
82
+ end
83
+
84
+ def broken(build)
85
+ update_file "[#{@application_name}] Build still broken", build.output
86
+ end
87
+
88
+ def revived(build)
89
+ clear_file
90
+ end
91
+
92
+ private
93
+ def file_name
94
+ @text_file_path
95
+ end
96
+
97
+ def clear_file
98
+ File.delete(file_name) if File.exists? file_name
99
+ end
100
+
101
+ def update_file(status, text)
102
+ File.open(file_name, "w", 0777) do |file|
103
+ file.write(status.to_s)
104
+ file.write("\n")
105
+ file.write("="*80)
106
+ file.write("\n")
107
+ file.write(text)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,40 @@
1
+ require 'yaml'
2
+
3
+ class StackingConfig
4
+ def initialize(ops = {})
5
+ @parents = []
6
+ @data = {}
7
+ @location = ops.delete(:location)
8
+ end
9
+
10
+ def << (other)
11
+ @parents = [other] + @parents
12
+ self
13
+ end
14
+
15
+ def [](key)
16
+ raise ArgumentError, "Expected key to be a symbol, or string" unless key.respond_to? :to_sym
17
+ @data[key.to_sym] || get_first_parent_result(key.to_sym)
18
+ end
19
+
20
+ def []=(key, value)
21
+ raise ArgumentError, "Expected key to be a symbol, or string" unless key.respond_to? :to_sym
22
+ @data[key.to_sym] = value
23
+ end
24
+
25
+ def self.load(file)
26
+ config = new(:location => file)
27
+ if File.exist? file
28
+ data = YAML.load_file(file)
29
+ data.each {|k,v| config[k] = v }
30
+ end
31
+ config
32
+ end
33
+
34
+ def get_first_parent_result(k)
35
+ @parents.each do |p|
36
+ return p[k] if p[k]
37
+ end
38
+ nil
39
+ end
40
+ end
@@ -0,0 +1,109 @@
1
+ require File.dirname(__FILE__) + '/extreme_continuous_builder'
2
+ require File.dirname(__FILE__) + '/stacking_config'
3
+ require File.dirname(__FILE__) + '/directory_monitor'
4
+
5
+ class XCB
6
+ def initialize(config)
7
+ @app_root = config[:app_root] || "."
8
+ @poller_pid_file = config[:task] || ".xcb_poller.pid"
9
+
10
+ @build = ExtremeContinuousBuilder::Build.new(
11
+ :task_name => config[:task] || 'test',
12
+ :application_root => @app_root
13
+ )
14
+
15
+ @project_name = config[:app_name] ||
16
+ if File.basename(Dir.pwd) == "trunk"
17
+ File.basename(File.dirname(Dir.pwd))
18
+ else
19
+ File.basename(Dir.pwd)
20
+ end
21
+
22
+ @text_output_path = config[:text_file_path] || "build_result.txt"
23
+
24
+ notifier_options = {
25
+ :application_name => @project_name,
26
+ :growl_host => config[:growl_host] || "localhost",
27
+ :growl_password => config[:growl_password],
28
+ :text_file_path => @text_output_path,
29
+ }
30
+
31
+ ExtremeContinuousBuilder.notifiers.each do |notifier|
32
+ notifier.setup(notifier_options)
33
+ end
34
+ end
35
+
36
+ def start_building
37
+ @monitor = DirectoryMonitor.new(@app_root, :ignore => @text_output_path)
38
+
39
+ daemonize!
40
+
41
+ File.open(@poller_pid_file, "w") {|f| f.write Process.pid }
42
+
43
+ while pid_file_is_me?
44
+ if @monitor.has_changes?
45
+ build
46
+ sleep 10
47
+ else
48
+ sleep 1
49
+ end
50
+ end
51
+ end
52
+
53
+ def stop_building
54
+ if read_pid_file.nil?
55
+ :not_running
56
+ else
57
+ pid = read_pid_file
58
+ Process.kill("TERM", pid) if pid
59
+ delete_pid_file
60
+ :stopped
61
+ end
62
+ end
63
+
64
+ def build
65
+ status = @build.run
66
+
67
+ if [:failed, :revived, :broken, :succesful].include? status
68
+ ExtremeContinuousBuilder.notifiers.each do |notifier|
69
+ notifier.send(status, @build) if notifier.respond_to? status
70
+ end
71
+ status
72
+ else
73
+ raise "Unexpected build result: #{status.inspect}"
74
+ end
75
+ end
76
+
77
+ def clean
78
+ @build.clean
79
+ end
80
+
81
+
82
+ protected
83
+ # Checks that the PID file that eas created still represents this proccess
84
+ def pid_file_is_me?
85
+ read_pid_file == Process.pid
86
+ end
87
+
88
+ def write_pid_file!
89
+ File.open(@poller_pid_file, "w") {|f| f.write Process.pid }
90
+ end
91
+
92
+ def read_pid_file
93
+ File.read(@poller_pid_file).to_i if File.exist? @poller_pid_file
94
+ end
95
+
96
+ def delete_pid_file
97
+ File.delete @poller_pid_file if File.exist? @poller_pid_file
98
+ end
99
+
100
+ def daemonize!
101
+ exit!(0) if fork
102
+ Process::setsid
103
+ exit!(0) if fork
104
+ STDIN.reopen("/dev/null")
105
+ STDERR.reopen("/dev/null", "w")
106
+ STDOUT.reopen("/dev/null", "w")
107
+ yield if block_given?
108
+ end
109
+ end
@@ -0,0 +1,61 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+ class BuilderTest < Test::Unit::TestCase
5
+ def test_ok_with_clean
6
+ clean_logs
7
+ builder = ExtremeContinuousBuilder::Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=6"}))
8
+ assert_equal(:succesful, builder.run)
9
+ assert_equal(:succesful, status.recall)
10
+ end
11
+
12
+ def test_ok_with_succesful
13
+ clean_logs
14
+ set_last_result(:succesful)
15
+ builder = ExtremeContinuousBuilder::Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=6"}))
16
+ assert_equal(:succesful, builder.run)
17
+ assert_equal(:succesful, status.recall)
18
+ end
19
+
20
+ def test_ok_with_failed
21
+ clean_logs
22
+ set_last_result(:failed)
23
+ builder = ExtremeContinuousBuilder::Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=6"}))
24
+ assert_equal(:revived, builder.run)
25
+ assert_equal(:succesful, status.recall)
26
+ end
27
+
28
+
29
+ def test_locking
30
+ build = ExtremeContinuousBuilder::Build.new XCB_OPS
31
+ build.send :grab_lock
32
+ Thread.new(build) {|b| sleep 1; b.send :release_lock}
33
+ started_time = Time.now
34
+ build.send :wait_for_lock
35
+ assert((Time.now - started_time).to_i > 1, "It all happened too fast")
36
+ assert((Time.now - started_time).to_i < 3, "It all happened too slow")
37
+ end
38
+
39
+ def test_bad_with_clean
40
+ clean_logs
41
+ builder = ExtremeContinuousBuilder::Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=3"}))
42
+ assert_equal(:failed, builder.run)
43
+ assert_equal(:failed, status.recall)
44
+ end
45
+
46
+ def test_bad_with_succesful
47
+ clean_logs
48
+ set_last_result(:succesful)
49
+ builder = ExtremeContinuousBuilder::Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=3"}))
50
+ assert_equal(:failed, builder.run)
51
+ assert_equal(:failed, status.recall)
52
+ end
53
+
54
+ def test_bad_with_failed
55
+ clean_logs
56
+ set_last_result(:failed)
57
+ builder = ExtremeContinuousBuilder::Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=3"}))
58
+ assert_equal(:broken, builder.run)
59
+ assert_equal(:failed, status.recall)
60
+ end
61
+ end
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ class DirectoryMonitorTest < Test::Unit::TestCase
3
+ BASE_TEST_DIR = "/tmp/DirectoryMonitorTest"
4
+ TEST_DIRS = ["#{BASE_TEST_DIR}/dir1", "#{BASE_TEST_DIR}/dir2", "#{BASE_TEST_DIR}/dir1/dir3", "#{BASE_TEST_DIR}/dir1/dir4"]
5
+ DIRS_TO_KILL = TEST_DIRS.reverse + [BASE_TEST_DIR]
6
+
7
+ def setup
8
+ teardown if File.exist? BASE_TEST_DIR
9
+ Dir.mkdir BASE_TEST_DIR
10
+ TEST_DIRS.each do |d|
11
+ Dir.mkdir d
12
+ end
13
+ end
14
+
15
+ def teardown
16
+ DIRS_TO_KILL.each do |d|
17
+ Dir.glob(d + "/*.tmp", File::FNM_DOTMATCH).each do |file|
18
+ File.delete file if File.file? file
19
+ end
20
+ Dir.delete d if File.exist? d
21
+ end
22
+ end
23
+
24
+ def test_initial_usage
25
+ monitor = DirectoryMonitor.new(BASE_TEST_DIR)
26
+ assert_equal(nil, monitor.had_changes?)
27
+ assert_equal(true, monitor.has_changes?)
28
+ assert_equal(true, monitor.had_changes?)
29
+ assert_equal(false, monitor.has_changes?)
30
+ assert_equal(false, monitor.had_changes?)
31
+ assert_equal(false, monitor.has_changes?)
32
+ end
33
+
34
+ def test_initial_usage_with_update
35
+ monitor = DirectoryMonitor.new(BASE_TEST_DIR, :update => true)
36
+ assert_equal(nil, monitor.had_changes?)
37
+ assert_equal(false, monitor.has_changes?)
38
+ assert_equal(false, monitor.had_changes?)
39
+
40
+ monitor = DirectoryMonitor.new(BASE_TEST_DIR, :update => true)
41
+ assert_equal(nil, monitor.had_changes?)
42
+ assert_equal(false, monitor.has_changes?)
43
+ assert_equal(false, monitor.had_changes?)
44
+ end
45
+
46
+ def test_simple_change
47
+ monitor = DirectoryMonitor.new(BASE_TEST_DIR, :update => true)
48
+ assert_equal(false, monitor.has_changes?)
49
+ assert_equal(false, monitor.has_changes?)
50
+
51
+ touch BASE_TEST_DIR, "test_file_one.tmp"
52
+ assert_equal(true, monitor.has_changes?)
53
+ assert_equal(false, monitor.has_changes?)
54
+ end
55
+
56
+ def test_ignore_dotfiles
57
+ monitor = DirectoryMonitor.new(BASE_TEST_DIR, :update => true)
58
+
59
+ touch BASE_TEST_DIR, ".test_file_one.tmp"
60
+
61
+ assert_equal(false, monitor.has_changes?)
62
+ assert_equal(false, monitor.has_changes?)
63
+ end
64
+
65
+
66
+ def test_ignore_ignore_files
67
+ monitor = DirectoryMonitor.new(BASE_TEST_DIR, :update => true,
68
+ :ignore => File.join(BASE_TEST_DIR, "test_file_ignore.tmp"))
69
+
70
+ touch BASE_TEST_DIR, "test_file_ignore.tmp"
71
+ assert_equal(false, monitor.has_changes?)
72
+ touch BASE_TEST_DIR, "test_file_one.tmp"
73
+ assert_equal(true, monitor.has_changes?)
74
+
75
+ sleep 1 # Must sleep between changes, otherwise the files mtimes will be
76
+ # the same despite being touched again.
77
+ monitor = DirectoryMonitor.new(BASE_TEST_DIR, :update => true,
78
+ :ignore => [File.join(BASE_TEST_DIR, "test_file_ignore.tmp")])
79
+
80
+ touch BASE_TEST_DIR, "test_file_ignore.tmp"
81
+ assert_equal(false, monitor.has_changes?)
82
+ touch BASE_TEST_DIR, "test_file_one.tmp"
83
+ assert_equal(true, monitor.has_changes?)
84
+ end
85
+
86
+ def touch(*file_name_parts)
87
+ file_name = File.join(file_name_parts)
88
+ File.open(file_name, "w+") {|f| f.write ""}
89
+ end
90
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+
5
+ class ExecTest < Test::Unit::TestCase
6
+ def test_syntax
7
+ assert true
8
+ end
9
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+ class GrowlNotifierTest < Test::Unit::TestCase
5
+ include ExtremeContinuousBuilder
6
+ def test_growl_notifier_revived
7
+ clean_logs
8
+ builder = Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=6"}))
9
+ assert_equal(:succesful, builder.run)
10
+
11
+ GrowlNotifier.instance.send :notifier=, nil
12
+ GrowlNotifier.setup(XCB_OPS)
13
+
14
+ GrowlNotifier.instance.revived builder
15
+
16
+ my_growler = GrowlNotifier.instance.send(:notifier)
17
+
18
+ assert_equal(1, my_growler.notifys.size)
19
+ assert_equal({
20
+ :type => "revived",
21
+ :title => "[fake_project] Build revived",
22
+ :text => "6 tests, 6 assertions, 0 failures, 0 errors",
23
+ }, my_growler.notifys[0])
24
+ end
25
+
26
+
27
+ def test_growl_notifier_broken
28
+ clean_logs
29
+ builder = Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=3"}))
30
+ assert_equal(:failed, builder.run)
31
+
32
+ GrowlNotifier.instance.send :notifier=, nil
33
+ GrowlNotifier.setup(XCB_OPS)
34
+ GrowlNotifier.instance.failed builder
35
+ my_growler = GrowlNotifier.instance.send(:notifier)
36
+
37
+ assert_equal(1, my_growler.notifys.size)
38
+ assert_equal({
39
+ :type => "failed",
40
+ :title => "[fake_project] Build failed",
41
+ :text => "6 tests, 6 assertions, 3 failures, 0 errors",
42
+ }, my_growler.notifys[0])
43
+ end
44
+
45
+ # def test_flunk
46
+ # flunk
47
+ # end
48
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+ class NotifiersTest < Test::Unit::TestCase
5
+ include ExtremeContinuousBuilder
6
+ NOTIFIERS = [GrowlNotifier.instance, TextFileNotifier.instance]
7
+ def test_notifiers_list
8
+ assert_equal(NOTIFIERS, ExtremeContinuousBuilder.notifiers.sort_by{|m| m.to_s})
9
+ end
10
+ end
@@ -0,0 +1,47 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class StackingConfigTest < Test::Unit::TestCase
4
+ def setup
5
+ @one = StackingConfig.load(File.dirname(__FILE__) + "/fixtures/stacking_config/one.yaml")
6
+ @two = StackingConfig.load(File.dirname(__FILE__) + "/fixtures/stacking_config/two.yaml")
7
+ @three = StackingConfig.load(File.dirname(__FILE__) + "/fixtures/stacking_config/three.yaml")
8
+ end
9
+
10
+
11
+ def test_basic_loding
12
+ assert_equal(1, @one[:one_only])
13
+ assert_equal(1, @two[:two_only])
14
+
15
+ assert_nil(@two[:one_only])
16
+ assert_nil(@one[:two_only])
17
+ end
18
+
19
+ def test_simple_stack
20
+ stack = StackingConfig.new() << @one << @two
21
+ assert_equal(1, stack[:one_only])
22
+ assert_equal(1, stack[:two_only])
23
+ assert_equal(3, stack[:two_overides_to_3])
24
+
25
+ assert_equal(1, @one[:one_only])
26
+ assert_equal(nil, @one[:two_only])
27
+ assert_equal(2, @one[:two_overides_to_3])
28
+
29
+ assert_equal(nil, @two[:one_only])
30
+ assert_equal(1, @two[:two_only])
31
+ assert_equal(3, @two[:two_overides_to_3])
32
+ end
33
+
34
+ def test_larger_stack
35
+ stack = StackingConfig.new() << @one << @two << @three
36
+ assert_equal(1, stack[:one_only])
37
+ assert_equal(1, stack[:two_only])
38
+ assert_equal(1, stack[:three_only])
39
+ assert_equal(3, stack[:three_overides_to_3])
40
+
41
+ assert_equal(1, @one[:one_only])
42
+ assert_equal(nil, @one[:two_only])
43
+
44
+ assert_equal(nil, @two[:one_only])
45
+ assert_equal(1, @two[:two_only])
46
+ end
47
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+ class TestNotifierTest < Test::Unit::TestCase
5
+ include ExtremeContinuousBuilder
6
+ def test_text_notifier_failed
7
+ clean_logs
8
+ builder = ExtremeContinuousBuilder::Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=3"}))
9
+ assert_equal(:failed, builder.run)
10
+ path = XCB_OPS[:text_file_path]
11
+
12
+ TextFileNotifier.setup XCB_OPS
13
+ TextFileNotifier.instance.failed builder
14
+
15
+ assert(File.exist?(path), "File should exist.")
16
+ assert_equal("[fake_project] Build failed\n" + ("="*80) + "\n" + builder.output, File.read(path))
17
+ end
18
+
19
+ def test_text_notifier_broken
20
+ clean_logs
21
+ builder = Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=3"}))
22
+ assert_equal(:failed, builder.run)
23
+ path = XCB_OPS[:text_file_path]
24
+
25
+ TextFileNotifier.setup XCB_OPS
26
+ TextFileNotifier.instance.broken builder
27
+
28
+ assert(File.exist?(path), "File should exist.")
29
+ assert_equal("[fake_project] Build still broken\n" + ("="*80) + "\n" + builder.output, File.read(path))
30
+ end
31
+
32
+ def test_text_notifier_revived
33
+ clean_logs
34
+ builder = Build.new(XCB_OPS.merge({:task_name => "test PASS_COUNT=6"}))
35
+ assert_equal(:succesful, builder.run)
36
+ path = XCB_OPS[:text_file_path]
37
+
38
+ File.open(path, "w") {|f| f.write "Hello World"}
39
+ TextFileNotifier.setup XCB_OPS
40
+ TextFileNotifier.instance.revived builder
41
+ assert(!File.exist?(path), "File should exist.")
42
+ end
43
+
44
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xcb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tom Lea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-01 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ruby-growl
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description: XCB provides the xcb command to continuously build a project in the background.
25
+ email: xcb@clockworkninja.co.uk
26
+ executables:
27
+ - xcb
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - README
34
+ - bin/xcb
35
+ - lib/directory_monitor.rb
36
+ - lib/extreme_continuous_builder.rb
37
+ - lib/notifiers.rb
38
+ - lib/stacking_config.rb
39
+ - lib/xcb_command.rb
40
+ has_rdoc: true
41
+ homepage: http://clockworkninja.co.uk/
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements:
60
+ - Growl with network access enabled
61
+ rubyforge_project: xconbuild
62
+ rubygems_version: 1.0.1
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: XCB provides the xcb command to continuously build a project in the background.
66
+ test_files:
67
+ - test/builder_test.rb
68
+ - test/directory_monitor_test.rb
69
+ - test/exec_test.rb
70
+ - test/growl_notifier_test.rb
71
+ - test/notifiers_test.rb
72
+ - test/stacking_config_test.rb
73
+ - test/text_notifier_test.rb