ampel_extase 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa656566f184d93b15926cec998ebdafbfda9818
4
- data.tar.gz: 85e86d33c060fa95f5160c0fefcd195df190bedf
3
+ metadata.gz: 185c3c458af6b31e6b267f17af22fbceefef5447
4
+ data.tar.gz: 279c80d9fa98fb8878d9a0299789903fd607f810
5
5
  SHA512:
6
- metadata.gz: e63cb5d8603d5dc1fbf0da83d7f2fe6011971976f893ff0826f14ae4d724ad37798989783aecc534bf6d038814e188b25392246d5a3ca130ae1aaee0ea57fba0
7
- data.tar.gz: f4258d55ae89298bea4db1dfdd42fc22284af742de0c3cdf0573ca7bfd39c06c03f55d5b952dcb72f24ece1631a64ccf9b6c6d7670e28076ea767c14b4119f70
6
+ metadata.gz: 8ac46db41479a33a543bf87735d633a9efa49952cceaf6a8bcf9b5c6b0fd33b32485b4be2615ea422d56406d5f0fc5884882ceec8daa4c3350d5beb6c9c5331c
7
+ data.tar.gz: efe0863f59b6af56b2e4d4eb792fa4d34af22cf1328af1dc77bd543f1781de8f5723e96bd3fc30474dab704990dd9a4e00adb5f6a1f2ce2a17815931d7fa1897
data/.gitignore CHANGED
@@ -5,5 +5,6 @@
5
5
  .rvmrc
6
6
  Gemfile.lock
7
7
  coverage
8
+ errors.lst
8
9
  pkg
9
10
  tags
@@ -0,0 +1,21 @@
1
+ # vim: set ft=ruby:
2
+
3
+ search do
4
+ prune_dirs /\A(\.svn|\.git|CVS|tmp|tags|coverage)\z/
5
+ skip_files /(\A\.|\.sw[pon]\z|\.(log|fnm|jpg|jpeg|png|pdf|svg)\z|tags|brakeman.ignore|errors\.lst|~\z)/i
6
+ end
7
+
8
+ discover do
9
+ prune_dirs /\A(\.svn|\.git|CVS|tmp|tags|coverage)\z/
10
+ skip_files /(\A\.|\.sw[pon]\z|\.log\z|~\z)/
11
+ binary false
12
+ end
13
+
14
+ strip_spaces do
15
+ prune_dirs /\A(\..*|CVS)\z/
16
+ skip_files /(\A\.|\.sw[pon]\z|\.log\z|~\z)/
17
+ end
18
+
19
+ probe do
20
+ test_framework :'rspec'
21
+ end
data/Rakefile CHANGED
@@ -12,15 +12,16 @@ GemHadar do
12
12
  licenses << 'GPL-2'
13
13
  test_dir 'spec'
14
14
  ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.rvmrc', 'coverage',
15
- 'tags', '.bundle', '.DS_Store', '.build'
15
+ 'tags', '.bundle', '.DS_Store', '.build', 'errors.lst'
16
16
 
17
17
  readme 'README.md'
18
18
  executables.merge Dir['bin/*'].map { |x| File.basename(x) }
19
19
 
20
- dependency 'tins', '~>1.0'
20
+ dependency 'tins', '~>1.0'
21
+ dependency 'term-ansicolor', '~>1.0'
21
22
  dependency 'socket_switcher'
22
- development_dependency 'simplecov', '~>0.9'
23
- development_dependency 'rspec', '~>3.0'
23
+ development_dependency 'simplecov', '~>0.9'
24
+ development_dependency 'rspec', '~>3.0'
24
25
  development_dependency 'byebug'
25
26
 
26
27
  default_task_dependencies :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.3.0
@@ -1,50 +1,53 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ampel_extase 0.1.0 ruby lib
2
+ # stub: ampel_extase 0.3.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ampel_extase"
6
- s.version = "0.1.0"
6
+ s.version = "0.3.0"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib"]
10
10
  s.authors = ["Florian Frank"]
11
- s.date = "2015-01-02"
11
+ s.date = "2015-08-25"
12
12
  s.description = "Library to control the build traffic light. Yes, we can\u{2026}"
13
13
  s.email = "flori@ping.de"
14
14
  s.executables = ["ampel_control"]
15
- s.extra_rdoc_files = ["README.md", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb"]
16
- s.files = [".gitignore", "Gemfile", "README.md", "Rakefile", "VERSION", "ampel_extase.gemspec", "bin/ampel_control", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb", "spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
15
+ s.extra_rdoc_files = ["README.md", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/jenkins_state_observer.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb"]
16
+ s.files = [".gitignore", ".utilsrc", "Gemfile", "README.md", "Rakefile", "VERSION", "ampel_extase.gemspec", "bin/ampel_control", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/jenkins_state_observer.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb", "spec/ampel_extase/build_state_spec.rb", "spec/ampel_extase/controller_spec.rb", "spec/ampel_extase/jekins_state_observer_spec.rb", "spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
17
17
  s.homepage = "http://github.com/flori/ampel_extase"
18
18
  s.licenses = ["GPL-2"]
19
19
  s.rdoc_options = ["--title", "AmpelExtase - Library to control the build traffic light", "--main", "README.md"]
20
- s.rubygems_version = "2.2.2"
20
+ s.rubygems_version = "2.4.5.1"
21
21
  s.summary = "Library to control the build traffic light"
22
- s.test_files = ["spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
22
+ s.test_files = ["spec/ampel_extase/build_state_spec.rb", "spec/ampel_extase/controller_spec.rb", "spec/ampel_extase/jekins_state_observer_spec.rb", "spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
23
23
 
24
24
  if s.respond_to? :specification_version then
25
25
  s.specification_version = 4
26
26
 
27
27
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
28
- s.add_development_dependency(%q<gem_hadar>, ["~> 1.0.0"])
28
+ s.add_development_dependency(%q<gem_hadar>, ["~> 1.3.1"])
29
29
  s.add_development_dependency(%q<simplecov>, ["~> 0.9"])
30
30
  s.add_development_dependency(%q<rspec>, ["~> 3.0"])
31
31
  s.add_development_dependency(%q<byebug>, [">= 0"])
32
32
  s.add_runtime_dependency(%q<tins>, ["~> 1.0"])
33
+ s.add_runtime_dependency(%q<term-ansicolor>, ["~> 1.0"])
33
34
  s.add_runtime_dependency(%q<socket_switcher>, [">= 0"])
34
35
  else
35
- s.add_dependency(%q<gem_hadar>, ["~> 1.0.0"])
36
+ s.add_dependency(%q<gem_hadar>, ["~> 1.3.1"])
36
37
  s.add_dependency(%q<simplecov>, ["~> 0.9"])
37
38
  s.add_dependency(%q<rspec>, ["~> 3.0"])
38
39
  s.add_dependency(%q<byebug>, [">= 0"])
39
40
  s.add_dependency(%q<tins>, ["~> 1.0"])
41
+ s.add_dependency(%q<term-ansicolor>, ["~> 1.0"])
40
42
  s.add_dependency(%q<socket_switcher>, [">= 0"])
41
43
  end
42
44
  else
43
- s.add_dependency(%q<gem_hadar>, ["~> 1.0.0"])
45
+ s.add_dependency(%q<gem_hadar>, ["~> 1.3.1"])
44
46
  s.add_dependency(%q<simplecov>, ["~> 0.9"])
45
47
  s.add_dependency(%q<rspec>, ["~> 3.0"])
46
48
  s.add_dependency(%q<byebug>, [">= 0"])
47
49
  s.add_dependency(%q<tins>, ["~> 1.0"])
50
+ s.add_dependency(%q<term-ansicolor>, ["~> 1.0"])
48
51
  s.add_dependency(%q<socket_switcher>, [">= 0"])
49
52
  end
50
53
  end
@@ -2,15 +2,16 @@
2
2
 
3
3
  require 'ampel_extase'
4
4
 
5
- serial = ENV['SERIAL'] or
5
+ serial = ENV['SERIAL'].full? or
6
6
  fail 'need env var SERIAL for path to serial port'
7
- jenkins_url = ENV['JENKINS_URL'] or
7
+ jenkins_url = ENV['JENKINS_URL'].full? or
8
8
  fail 'need env var JENKINS_URL of the form http://test2.local:8080/job/foo'
9
+ warning_jenkins_url = ENV['WARNING_JENKINS_URL'].full?
9
10
  sleep_duration = (ENV['SLEEP'] || 10).to_i
10
11
 
11
- AmpelExtase::Controller.new(
12
- serial,
13
- jenkins_url,
14
- debug: true,
15
- sleep: sleep_duration,
12
+ AmpelExtase::Controller.for(
13
+ serial: serial,
14
+ jenkins_url: jenkins_url,
15
+ warning_jenkins_url: warning_jenkins_url,
16
+ sleep: sleep_duration
16
17
  ).start
@@ -1,17 +1,33 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'ampel_extase/jenkins_client'
3
+ require 'term/ansicolor'
4
4
  require 'ampel_extase/light_switcher'
5
- require 'ampel_extase/build_state'
5
+ require 'ampel_extase/jenkins_state_observer'
6
6
 
7
7
  class AmpelExtase::Controller
8
- def initialize(serial, jenkins_url, debug: false, sleep: 10)
9
- @jenkins = AmpelExtase::JenkinsClient.new(jenkins_url, debug: debug)
10
- check_jenkins
11
- @lights = AmpelExtase::LightSwitcher.new(serial, debug: debug)
8
+ include Term::ANSIColor
9
+
10
+ def self.for(
11
+ serial:,
12
+ jenkins_url:,
13
+ warning_jenkins_url: nil,
14
+ sleep: 10
15
+ )
16
+ ampel_jenkins = AmpelExtase::JenkinsStateObserver.for_url(jenkins_url)
17
+ warning_jenkins = AmpelExtase::JenkinsStateObserver.for_url(warning_jenkins_url)
18
+ lights = AmpelExtase::LightSwitcher.for(serial: serial)
19
+ new(ampel_jenkins, warning_jenkins, lights, sleep: sleep)
20
+ end
21
+
22
+ def initialize(
23
+ ampel_jenkins,
24
+ warning_jenkins,
25
+ lights,
26
+ sleep: 10
27
+ )
28
+ @ampel_jenkins, @warning_jenkins, @lights, @sleep =
29
+ ampel_jenkins, warning_jenkins, lights, sleep
12
30
  check_lights
13
- @sleep = sleep
14
- @build_state = AmpelExtase::BuildState.for
15
31
  end
16
32
 
17
33
  def start
@@ -41,50 +57,65 @@ class AmpelExtase::Controller
41
57
 
42
58
  def perform
43
59
  @crashed = false
44
- on_state_change do |state|
45
- perform_switch state
60
+ @ampel_jenkins.on_state_change do |state|
61
+ perform_lights_switch state
62
+ end
63
+ @warning_jenkins.on_state_change do |state|
64
+ perform_warning state
46
65
  end
47
66
  end
48
67
 
49
- def perform_switch(state)
68
+ def perform_lights_switch(state)
50
69
  case state.last_result
51
70
  when 'SUCCESS'
52
71
  @lights.green.on
53
72
  @lights.red.off
73
+ puts success('LIGHTS SUCCESS')
54
74
  when 'FAILURE', 'ABORTED'
55
75
  @lights.red.on
56
76
  if state.building?
57
77
  @lights.green.on
78
+ puts failure_building('LIGHTS FAILURE BUILDING')
58
79
  else
59
80
  @lights.green.off
81
+ puts failure('LIGHTS FAILURE')
60
82
  end
61
83
  end
62
84
  end
63
85
 
64
- def on_state_change
65
- new_state = AmpelExtase::BuildState.for [ last_result, building? ]
66
- if new_state == @build_state
67
- puts "state did not change, is still #@build_state => do nothing"
68
- else
69
- puts "state changed from #@build_state to #{new_state} => taking action"
70
- yield new_state
86
+ def perform_warning(state)
87
+ case state.last_result
88
+ when 'SUCCESS'
89
+ @lights.aux.off
90
+ puts success('WARNING SUCCESS')
91
+ when 'FAILURE', 'ABORTED'
92
+ if state.building?
93
+ puts failure_building('WARNING FAILURE BUILDING')
94
+ else
95
+ @lights.aux.on
96
+ puts failure('WARNING FAILURE')
97
+ end
71
98
  end
72
- ensure
73
- @build_state = new_state
74
99
  end
75
100
 
76
- def last_result
77
- @jenkins.fetch_build(:last_completed_build)['result']
101
+ def success(message)
102
+ green message
78
103
  end
79
104
 
80
- def building?
81
- @jenkins.fetch_build(:last_build)['building']
105
+ def failure(message)
106
+ red message
107
+ end
108
+
109
+ def failure_building(message)
110
+ green on_red message
82
111
  end
83
112
 
84
113
  def switch_all_lights_off
85
- for light in @lights
86
- light.off
87
- end
114
+ @lights.each(&:off)
115
+ end
116
+
117
+ def switch_all_lights_on
118
+ @lights.each(&:on)
88
119
  end
89
120
 
90
121
  def handle_crash(exception)
@@ -98,19 +129,10 @@ class AmpelExtase::Controller
98
129
 
99
130
  def check_lights
100
131
  puts "checking lights configuration"
101
- for light in @lights
102
- light.on
103
- end
132
+ switch_all_lights_on
104
133
  sleep 1
105
- for light in @lights
106
- light.off
107
- end
134
+ switch_all_lights_off
108
135
  sleep 1
109
136
  puts "OK"
110
137
  end
111
-
112
- def check_jenkins
113
- puts "checking jenkins configuration"
114
- @jenkins.fetch and puts "OK"
115
- end
116
138
  end
@@ -5,21 +5,19 @@ require 'uri'
5
5
 
6
6
  module AmpelExtase
7
7
  class JenkinsClient
8
- def initialize(url, debug: false)
8
+ def initialize(url)
9
9
  url = URI.parse(url.to_s) unless URI::HTTP === url
10
- @url, @debug = url, debug
10
+ @url = url
11
11
  end
12
12
 
13
+ attr_reader :url
14
+
13
15
  def api_url(*path)
14
16
  [ @url, *path, 'api', 'json' ].compact * '/'
15
17
  end
16
18
 
17
- def console_url(number)
18
- [ @url, number, 'consoleText' ] * '/'
19
- end
20
-
21
19
  def fetch(url = api_url)
22
- @debug and STDERR.puts "Fetching #{url.to_s.inspect}."
20
+ puts "Fetching #{url.to_s.inspect}."
23
21
  JSON open(url).read
24
22
  rescue => e
25
23
  e.message << " for #{url.inspect}"
@@ -36,17 +34,5 @@ module AmpelExtase
36
34
  end
37
35
  fetch url
38
36
  end
39
-
40
- def fetch_build_revision(type)
41
- data = fetch_build(type)
42
- data['actions'].find { |x| x.keys.include?('lastBuiltRevision') }['lastBuiltRevision']['SHA1']
43
- rescue
44
- nil
45
- end
46
-
47
- def fetch_console_text(type)
48
- build = fetch_build(type)
49
- open(console_url(build['number'])).read
50
- end
51
37
  end
52
38
  end
@@ -0,0 +1,48 @@
1
+ require 'ampel_extase/build_state'
2
+ require 'ampel_extase/jenkins_client'
3
+
4
+ class AmpelExtase::JenkinsStateObserver
5
+ def self.for_url(jenkins_url)
6
+ if jenkins_url
7
+ jenkins = AmpelExtase::JenkinsClient.new(jenkins_url)
8
+ new(jenkins)
9
+ else
10
+ Tins::NULL
11
+ end
12
+ end
13
+
14
+ def initialize(jenkins)
15
+ @jenkins = jenkins
16
+ @build_state = AmpelExtase::BuildState.for
17
+ check
18
+ end
19
+
20
+ def check
21
+ puts "checking jenkins configuration for #{@jenkins.url.to_s.inspect}"
22
+ @jenkins.fetch and puts "OK"
23
+ end
24
+
25
+ def last_result
26
+ @jenkins.fetch_build(:last_completed_build)['result']
27
+ end
28
+
29
+ def building?
30
+ @jenkins.fetch_build(:last_build)['building']
31
+ end
32
+
33
+ def state_changed?(new_state)
34
+ new_state != @build_state
35
+ end
36
+
37
+ def on_state_change
38
+ new_state = AmpelExtase::BuildState.for [ last_result, building? ]
39
+ if state_changed?(new_state)
40
+ puts "state changed from #@build_state to #{new_state} => taking action"
41
+ yield new_state
42
+ else
43
+ puts "state did not change, is still #@build_state => do nothing"
44
+ end
45
+ ensure
46
+ @build_state = new_state
47
+ end
48
+ end
@@ -2,8 +2,16 @@ require 'socket_switcher'
2
2
 
3
3
  module AmpelExtase
4
4
  class LightSwitcher
5
- def initialize(serial, debug: false)
6
- @port = SocketSwitcher::Port.new(serial, debug: debug)
5
+ def self.for(serial:)
6
+ if serial
7
+ new SocketSwitcher::Port.new(serial)
8
+ else
9
+ Tins::NULL
10
+ end
11
+ end
12
+
13
+ def initialize(port)
14
+ @port = port
7
15
  end
8
16
 
9
17
  attr_reader :port
@@ -24,9 +32,8 @@ module AmpelExtase
24
32
  [
25
33
  :green,
26
34
  :red,
27
- # not in use for now :aux,
35
+ :aux,
28
36
  ].map { |color| __send__(color) }.each(&block)
29
37
  end
30
38
  end
31
39
  end
32
-
@@ -1,6 +1,6 @@
1
1
  module AmpelExtase
2
2
  # AmpelExtase version
3
- VERSION = '0.1.0'
3
+ VERSION = '0.3.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe AmpelExtase::BuildState do
4
+ describe 'initial state' do
5
+ let :bs do
6
+ described_class.for
7
+ end
8
+
9
+ it 'has a to_a' do
10
+ expect(bs.to_a).to eq [ 'N/A', nil ]
11
+ end
12
+
13
+ it 'has N/A as the last result' do
14
+ expect(bs.last_result).to eq 'N/A'
15
+ end
16
+
17
+ it 'does not build atm' do
18
+ expect(bs.building?).to eq false
19
+ end
20
+
21
+ it 'reads N/A as a string' do
22
+ expect(bs.to_s).to eq 'N/A'
23
+ end
24
+ end
25
+
26
+ describe 'an intermediate state' do
27
+ let :bs do
28
+ described_class.for [ 'SUCCESS', true ]
29
+ end
30
+
31
+
32
+ it 'has SUCCESS as the last result' do
33
+ expect(bs.last_result).to eq 'SUCCESS'
34
+ end
35
+
36
+ describe 'building' do
37
+ it 'has a to_a' do
38
+ expect(bs.to_a).to eq [ 'SUCCESS', true ]
39
+ end
40
+
41
+ it 'can be building' do
42
+ expect(bs.building?).to eq true
43
+ end
44
+
45
+ it 'reads SUCCESS (building) as a string' do
46
+ expect(bs.to_s).to eq 'SUCCESS (building)'
47
+ end
48
+ end
49
+
50
+ describe 'not building' do
51
+ let :bs do
52
+ described_class.for [ 'SUCCESS', false ]
53
+ end
54
+
55
+ it 'has a to_a' do
56
+ expect(bs.to_a).to eq [ 'SUCCESS', false ]
57
+ end
58
+
59
+ it 'can not be building' do
60
+ expect(bs.building?).to eq false
61
+ end
62
+
63
+ it 'reads SUCCESS (building) as a string' do
64
+ expect(bs.to_s).to eq 'SUCCESS'
65
+ end
66
+ end
67
+ end
68
+
69
+ describe 'equality' do
70
+ it 'can be equal or unequal' do
71
+ foo_true = described_class.for([ 'FOO', true ])
72
+ foo_false = described_class.for([ 'FOO', false ])
73
+ bar_true = described_class.for([ 'BAR', true ])
74
+ expect(foo_true).to eq described_class.for([ 'FOO', true ])
75
+ expect(foo_true).not_to eq foo_false
76
+ expect(foo_true).not_to eq bar_true
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,226 @@
1
+ require 'spec_helper'
2
+
3
+ describe AmpelExtase::Controller do
4
+ before do
5
+ allow_any_instance_of(AmpelExtase::JenkinsClient).to receive(:puts)
6
+ allow_any_instance_of(AmpelExtase::Controller).to receive(:puts)
7
+ allow_any_instance_of(AmpelExtase::JenkinsStateObserver).to receive(:puts)
8
+ allow_any_instance_of(described_class).to receive(:sleep)
9
+ end
10
+
11
+ let :ampel_client do
12
+ double('AmpelExtase::JenkinsClient', url: 'http://foo/bar')
13
+ end
14
+
15
+ let :warning_client do
16
+ double('AmpelExtase::JenkinsClient', url: 'http://foo/bar')
17
+ end
18
+
19
+ let :ampel_jenkins do
20
+ AmpelExtase::JenkinsStateObserver.new ampel_client
21
+ end
22
+
23
+ let :warning_jenkins do
24
+ AmpelExtase::JenkinsStateObserver.new warning_client
25
+ end
26
+
27
+ let :lights do
28
+ double('AmpelExtase::LightSwitcher')
29
+ end
30
+
31
+ let :controller do
32
+ described_class.new(
33
+ ampel_jenkins,
34
+ warning_jenkins,
35
+ lights
36
+ )
37
+ end
38
+
39
+ before do
40
+ for client in [ ampel_client, warning_client ]
41
+ allow(client).to receive(:fetch).and_return true
42
+ allow(client).to receive(:fetch_build).and_return('result' => 'N/A')
43
+ end
44
+ end
45
+
46
+ before do
47
+ allow(lights).to receive(:each)
48
+ end
49
+
50
+ describe '.for' do
51
+ it 'can create a demo object that does not really do anything' do
52
+ demo_object = described_class.for(
53
+ serial: nil,
54
+ jenkins_url: nil
55
+ )
56
+ expect(demo_object.instance_eval { @ampel_jenkins }).to be_nil
57
+ expect(demo_object.instance_eval { @warning_jenkins }).to be_nil
58
+ expect(demo_object.instance_eval { @lights }).to be_nil
59
+ end
60
+ end
61
+
62
+ describe '#start' do
63
+ it 'performs and then sleeps' do
64
+ allow(controller).to receive(:sleep).and_raise(
65
+ sleep_error = StandardError.new
66
+ )
67
+ allow(controller).to receive(:at_exit)
68
+ expect(controller).to receive(:perform)
69
+ expect { controller.start }.to raise_error sleep_error
70
+ end
71
+
72
+ it 'can handle crashes' do
73
+ allow(controller).to receive(:sleep).and_raise(
74
+ sleep_error = StandardError.new
75
+ )
76
+ allow(controller).to receive(:at_exit)
77
+ expect(controller).to receive(:perform).and_raise(e = StandardError.new)
78
+ expect(controller).to receive(:handle_crash).with(e)
79
+ expect { controller.start }.to raise_error sleep_error
80
+ end
81
+
82
+ end
83
+
84
+ describe '#stop' do
85
+ before do
86
+ controller
87
+ end
88
+
89
+ it 'iterates over all lights' do
90
+ expect(lights).to receive(:each).once
91
+ controller.stop
92
+ end
93
+ end
94
+
95
+ describe '#perform' do
96
+ let :perform do
97
+ controller.instance_eval { perform }
98
+ end
99
+
100
+ it 'reacts to state changes' do
101
+ state = AmpelExtase::BuildState.for
102
+ allow(ampel_jenkins).to receive(:state_changed?).and_return true
103
+ expect { |b| ampel_jenkins.on_state_change(&b) }.to yield_with_args(state)
104
+ allow(warning_jenkins).to receive(:state_changed?).and_return true
105
+ expect { |b| warning_jenkins.on_state_change(&b) }.to yield_with_args(state)
106
+ perform
107
+ end
108
+ end
109
+
110
+
111
+ describe '#handle_crash' do
112
+ let :exception do
113
+ raise StandardError rescue $!
114
+ end
115
+
116
+ let :handle_crash do
117
+ my_exception = exception
118
+ controller.instance_eval { handle_crash(my_exception) }
119
+ end
120
+
121
+ before do
122
+ controller
123
+ allow(controller).to receive(:warn)
124
+ end
125
+
126
+ it 'warns on crash' do
127
+ expect(controller).to receive(:warn).with(/^Caught/)
128
+ handle_crash
129
+ end
130
+
131
+ it 'switches the lights of once' do
132
+ expect(controller).to receive(:switch_all_lights_off)
133
+ handle_crash
134
+ expect(controller).not_to receive(:switch_all_lights_off)
135
+ handle_crash
136
+ end
137
+ end
138
+
139
+ describe '#perform_lights_switch' do
140
+ before do
141
+ controller.instance_variable_set :@lights, Tins::NULL
142
+ end
143
+
144
+ let :perform_lights_switch do
145
+ my_state = state
146
+ controller.instance_eval { perform_lights_switch(my_state) }
147
+ end
148
+
149
+ context 'success' do
150
+ let :state do
151
+ AmpelExtase::BuildState.for [ 'SUCCESS', false ]
152
+ end
153
+
154
+ it 'goes green on success' do
155
+ expect(controller).to receive(:success).and_call_original
156
+ perform_lights_switch
157
+ end
158
+ end
159
+
160
+ context 'failure' do
161
+ let :state do
162
+ AmpelExtase::BuildState.for [ 'FAILURE', false ]
163
+ end
164
+
165
+ it 'goes red on failure' do
166
+ expect(controller).to receive(:failure).and_call_original
167
+ perform_lights_switch
168
+ end
169
+ end
170
+
171
+ context 'failure building' do
172
+ let :state do
173
+ AmpelExtase::BuildState.for [ 'FAILURE', true ]
174
+ end
175
+
176
+ it 'goes green on red on failure and building' do
177
+ expect(controller).to receive(:failure_building).and_call_original
178
+ perform_lights_switch
179
+ end
180
+ end
181
+ end
182
+
183
+ describe '#perform_warning' do
184
+ before do
185
+ controller.instance_variable_set :@lights, Tins::NULL
186
+ end
187
+
188
+ let :perform_warning do
189
+ my_state = state
190
+ controller.instance_eval { perform_warning(my_state) }
191
+ end
192
+
193
+ context 'success' do
194
+ let :state do
195
+ AmpelExtase::BuildState.for [ 'SUCCESS', false ]
196
+ end
197
+
198
+ it 'goes green on success' do
199
+ expect(controller).to receive(:success).and_call_original
200
+ perform_warning
201
+ end
202
+ end
203
+
204
+ context 'failure' do
205
+ let :state do
206
+ AmpelExtase::BuildState.for [ 'FAILURE', false ]
207
+ end
208
+
209
+ it 'goes red on failure' do
210
+ expect(controller).to receive(:failure).and_call_original
211
+ perform_warning
212
+ end
213
+ end
214
+
215
+ context 'failure building' do
216
+ let :state do
217
+ AmpelExtase::BuildState.for [ 'FAILURE', true ]
218
+ end
219
+
220
+ it 'goes green on red on failure and building' do
221
+ expect(controller).to receive(:failure_building).and_call_original
222
+ perform_warning
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+
3
+ describe AmpelExtase::JenkinsStateObserver do
4
+ let :client do
5
+ double('AmpelExtase::JenkinsClient', url: 'http://foo/bar')
6
+ end
7
+
8
+ before do
9
+ allow(client).to receive(:fetch).and_return true
10
+ end
11
+
12
+ let :jso do
13
+ described_class.new client
14
+ end
15
+
16
+ describe '.for_url' do
17
+ it 'creates a state observer for an URL' do
18
+ url = 'http://foo/bar'
19
+ expect(AmpelExtase::JenkinsClient).to\
20
+ receive(:new).with(url).and_return client
21
+ expect(described_class).to\
22
+ receive(:new).with(client)
23
+ described_class.for_url url
24
+ end
25
+
26
+ it 'returns a null object if url was nil' do
27
+ expect(described_class.for_url(nil)).to be_nil
28
+ end
29
+ end
30
+
31
+ describe '#check' do
32
+ it 'outputs "OK" if it can fetch data from CI' do
33
+ allow(jso).to receive(:puts)
34
+ expect(jso).to receive(:puts).with('OK')
35
+ jso.check
36
+ end
37
+
38
+ it 'lets an exception pass if raised by the client' do
39
+ allow(client).to receive(:fetch).and_raise e = StandardError.new
40
+ expect { jso.check }.to raise_error e
41
+ end
42
+ end
43
+
44
+ describe '#last_result' do
45
+ it 'uses client to fetch last_completed_build' do
46
+ allow(client).to receive(:fetch_build).with(:last_completed_build).
47
+ and_return('result' => :foo)
48
+ expect(jso.last_result).to eq :foo
49
+ end
50
+ end
51
+
52
+ describe '#building?' do
53
+ it 'uses client to fetch last_build' do
54
+ allow(client).to receive(:fetch_build).with(:last_build).
55
+ and_return('building' => :foo)
56
+ expect(jso.building?).to eq :foo
57
+ end
58
+ end
59
+
60
+ describe '#on_state_change' do
61
+ let :bs_initial do
62
+ AmpelExtase::BuildState.for [ 'N/A', nil ]
63
+ end
64
+
65
+ let :bs_success do
66
+ AmpelExtase::BuildState.for [ 'SUCCESS', true ]
67
+ end
68
+
69
+ let :bs_failure do
70
+ AmpelExtase::BuildState.for [ 'FAILURE', true ]
71
+ end
72
+
73
+ it 'tracks changes in build state' do
74
+ expect(jso.instance_variable_get(:@build_state)).to eq bs_initial
75
+ allow(client).to receive(:fetch_build).with(:last_completed_build).
76
+ and_return('result' => 'SUCCESS')
77
+ allow(client).to receive(:fetch_build).with(:last_build).
78
+ and_return('building' => true)
79
+ expect(jso).to receive(:puts).with(
80
+ "state changed from N/A to SUCCESS (building) => "\
81
+ "taking action"
82
+ )
83
+ expect { |b| jso.on_state_change(&b) }.to yield_with_args(bs_success)
84
+ expect(jso.instance_variable_get(:@build_state)).to eq bs_success
85
+ allow(client).to receive(:fetch_build).with(:last_completed_build).
86
+ and_return('result' => 'FAILURE')
87
+ allow(client).to receive(:fetch_build).with(:last_build).
88
+ and_return('building' => true)
89
+ expect(jso).to receive(:puts).with(
90
+ "state changed from SUCCESS (building) to FAILURE (building) => "\
91
+ "taking action"
92
+ )
93
+ expect { |b| jso.on_state_change(&b) }.to yield_with_args(bs_failure)
94
+ expect(jso.instance_variable_get(:@build_state)).to eq bs_failure
95
+ end
96
+
97
+ it 'notices if nothing has changed' do
98
+ allow(client).to receive(:fetch_build).twice.with(:last_completed_build).
99
+ and_return('result' => 'SUCCESS')
100
+ allow(client).to receive(:fetch_build).twice.with(:last_build).
101
+ and_return('building' => true)
102
+ expect(jso).to receive(:puts).with(
103
+ "state changed from N/A to SUCCESS (building) => "\
104
+ "taking action"
105
+ )
106
+ expect { |b| jso.on_state_change(&b) }.to yield_with_args(bs_success)
107
+ expect(jso.instance_variable_get(:@build_state)).to eq bs_success
108
+ expect(jso).to receive(:puts).with(
109
+ "state did not change, is still SUCCESS (building) => do nothing"
110
+ )
111
+ expect(jso.instance_variable_get(:@build_state)).to eq bs_success
112
+ expect { |b| jso.on_state_change(&b) }.not_to yield_with_args(bs_success)
113
+ end
114
+ end
115
+ end
@@ -1,5 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe AmpelExtase::JenkinsClient do
4
- pending
4
+ let :client do
5
+ AmpelExtase::JenkinsClient.new 'http://foo/bar'
6
+ end
7
+
8
+ let :opened_uri do
9
+ double('URI', read: '{"hello":"world"}')
10
+ end
11
+
12
+ describe '#fetch' do
13
+ let :api_url do
14
+ 'http://foo/bar/api/json'
15
+ end
16
+
17
+ it 'can fetch JSON data from CI' do
18
+ expect(client).to receive(:open).with(api_url).
19
+ and_return opened_uri
20
+ expect(client.fetch).to eq("hello" => "world")
21
+ end
22
+
23
+ it 'modifies exception messages and reraises' do
24
+ expect(client).to receive(:open).with(api_url).
25
+ and_raise e = StandardError.new('foo')
26
+ expect { client.fetch }.to raise_error(
27
+ StandardError, /for #{api_url.inspect}/
28
+ )
29
+ end
30
+ end
31
+
32
+ describe '#fetch_build' do
33
+ let :api_url do
34
+ 'http://foo/bar/buildType/api/json'
35
+ end
36
+
37
+ it 'can can fetch a build type responding to #to_s' do
38
+ expect(client).to receive(:open).with(api_url).and_return opened_uri
39
+ client.fetch_build double(to_s: 'buildType')
40
+ end
41
+
42
+ it 'can interpret a build type symbol correctly' do
43
+ expect(client).to receive(:open).with(api_url).and_return opened_uri
44
+ client.fetch_build :build_type
45
+ end
46
+ end
5
47
  end
@@ -1,5 +1,40 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe AmpelExtase::LightSwitcher do
4
- pending
4
+ let :port do
5
+ double('SocketSwitcher::Port')
6
+ end
7
+
8
+ let :switcher do
9
+ allow(SocketSwitcher::Port).to receive(:new).and_return port
10
+ described_class.for serial: 'foo/bar'
11
+ end
12
+
13
+ describe '#green' do
14
+ it 'returns device 0' do
15
+ expect(port).to receive(:device).with(0)
16
+ switcher.green
17
+ end
18
+ end
19
+
20
+ describe '#red' do
21
+ it 'returns device 1' do
22
+ expect(port).to receive(:device).with(1)
23
+ switcher.red
24
+ end
25
+ end
26
+
27
+ describe '#aux' do
28
+ it 'returns device 3' do
29
+ expect(port).to receive(:device).with(2)
30
+ switcher.aux
31
+ end
32
+ end
33
+
34
+ describe '#each' do
35
+ it 'iterates over all port devices' do
36
+ expect(port).to receive(:device).thrice.and_return :ok
37
+ expect(switcher.each.to_a).to eq %i[ ok ] * 3
38
+ end
39
+ end
5
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ampel_extase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-02 00:00:00.000000000 Z
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.0.0
19
+ version: 1.3.1
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.0.0
26
+ version: 1.3.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: simplecov
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: term-ansicolor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: socket_switcher
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -105,10 +119,12 @@ extra_rdoc_files:
105
119
  - lib/ampel_extase/build_state.rb
106
120
  - lib/ampel_extase/controller.rb
107
121
  - lib/ampel_extase/jenkins_client.rb
122
+ - lib/ampel_extase/jenkins_state_observer.rb
108
123
  - lib/ampel_extase/light_switcher.rb
109
124
  - lib/ampel_extase/version.rb
110
125
  files:
111
126
  - ".gitignore"
127
+ - ".utilsrc"
112
128
  - Gemfile
113
129
  - README.md
114
130
  - Rakefile
@@ -119,8 +135,12 @@ files:
119
135
  - lib/ampel_extase/build_state.rb
120
136
  - lib/ampel_extase/controller.rb
121
137
  - lib/ampel_extase/jenkins_client.rb
138
+ - lib/ampel_extase/jenkins_state_observer.rb
122
139
  - lib/ampel_extase/light_switcher.rb
123
140
  - lib/ampel_extase/version.rb
141
+ - spec/ampel_extase/build_state_spec.rb
142
+ - spec/ampel_extase/controller_spec.rb
143
+ - spec/ampel_extase/jekins_state_observer_spec.rb
124
144
  - spec/ampel_extase/jenkins_client_spec.rb
125
145
  - spec/ampel_extase/light_switcher_spec.rb
126
146
  - spec/spec_helper.rb
@@ -148,11 +168,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
168
  version: '0'
149
169
  requirements: []
150
170
  rubyforge_project:
151
- rubygems_version: 2.2.2
171
+ rubygems_version: 2.4.5.1
152
172
  signing_key:
153
173
  specification_version: 4
154
174
  summary: Library to control the build traffic light
155
175
  test_files:
176
+ - spec/ampel_extase/build_state_spec.rb
177
+ - spec/ampel_extase/controller_spec.rb
178
+ - spec/ampel_extase/jekins_state_observer_spec.rb
156
179
  - spec/ampel_extase/jenkins_client_spec.rb
157
180
  - spec/ampel_extase/light_switcher_spec.rb
158
181
  - spec/spec_helper.rb