ampel_extase 0.1.0 → 0.3.0

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.
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