xcb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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