puppet-herald 0.1.1 → 0.2.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.
Files changed (65) hide show
  1. checksums.yaml +15 -7
  2. data/.rubocop.yml +31 -0
  3. data/.rubocop_todo.yml +6 -0
  4. data/.travis.yml +7 -7
  5. data/Gemfile +5 -9
  6. data/README.md +152 -16
  7. data/Rakefile +67 -6
  8. data/bin/puppet-herald +1 -1
  9. data/config.ru +2 -2
  10. data/db/migrate/20141211165540_create_nodes.rb +5 -3
  11. data/db/migrate/20141211171305_create_reports.rb +12 -10
  12. data/db/migrate/20141211171326_create_log_entries.rb +9 -7
  13. data/db/schema.rb +24 -26
  14. data/lib/puppet-herald.rb +59 -21
  15. data/lib/puppet-herald/app/api.rb +111 -0
  16. data/lib/puppet-herald/app/configuration.rb +70 -0
  17. data/lib/puppet-herald/app/frontend.rb +61 -0
  18. data/lib/puppet-herald/{views → app/views}/app.erb +5 -8
  19. data/lib/puppet-herald/{views → app/views}/err500.erb +1 -4
  20. data/lib/puppet-herald/application.rb +27 -0
  21. data/lib/puppet-herald/cli.rb +66 -45
  22. data/lib/puppet-herald/client.rb +33 -0
  23. data/lib/puppet-herald/database.rb +84 -40
  24. data/lib/puppet-herald/javascript.rb +23 -17
  25. data/lib/puppet-herald/models/log-entry.rb +10 -3
  26. data/lib/puppet-herald/models/node.rb +15 -5
  27. data/lib/puppet-herald/models/report.rb +70 -63
  28. data/lib/puppet-herald/public/app.js +9 -8
  29. data/lib/puppet-herald/public/components/directives/status-button.html +1 -1
  30. data/lib/puppet-herald/public/components/directives/status-button.js +5 -3
  31. data/lib/puppet-herald/public/components/filters/filters.js +9 -4
  32. data/lib/puppet-herald/public/components/page.js +34 -0
  33. data/lib/puppet-herald/public/node/node.html +3 -1
  34. data/lib/puppet-herald/public/node/node.js +7 -4
  35. data/lib/puppet-herald/public/nodes/nodes.js +3 -2
  36. data/lib/puppet-herald/public/report/report.html +4 -1
  37. data/lib/puppet-herald/public/report/report.js +5 -3
  38. data/lib/puppet-herald/stubs/puppet.rb +20 -9
  39. data/lib/puppet-herald/version.rb +17 -7
  40. data/package.json +8 -3
  41. data/puppet-herald.gemspec +3 -6
  42. data/spec/integration/application_spec.rb +175 -0
  43. data/spec/integration/models/node_spec.rb +4 -4
  44. data/spec/integration/models/report_spec.rb +7 -7
  45. data/spec/spec_helper.rb +12 -7
  46. data/spec/support/active_record.rb +6 -10
  47. data/spec/support/reconnectdb.rb +13 -0
  48. data/spec/unit/puppet-herald/cli_spec.rb +45 -13
  49. data/spec/unit/puppet-herald/client_spec.rb +23 -0
  50. data/spec/unit/puppet-herald/database_spec.rb +8 -9
  51. data/spec/unit/puppet-herald/javascript_spec.rb +8 -13
  52. data/spec/unit/puppet-herald_spec.rb +4 -4
  53. data/test/javascript/karma.conf.js +43 -5
  54. data/test/javascript/src/app_test.js +90 -0
  55. data/test/javascript/src/components/artifact/artifact-directive_test.js +36 -0
  56. data/test/javascript/src/components/artifact/artifact_test.js +64 -0
  57. data/test/javascript/src/components/directives/status-button_test.js +159 -0
  58. data/test/javascript/src/components/filters/filters_test.js +35 -0
  59. data/test/javascript/src/node/node_test.js +87 -0
  60. data/test/javascript/src/nodes/nodes_test.js +56 -0
  61. data/test/javascript/src/report/report_test.js +94 -0
  62. metadata +98 -68
  63. data/lib/puppet-herald/app.rb +0 -103
  64. data/lib/puppet-herald/public/components/artifact/artifact-directive_test.js +0 -17
  65. data/spec/integration/app_spec.rb +0 -21
data/package.json CHANGED
@@ -9,15 +9,20 @@
9
9
  "dependencies": {
10
10
  "angular": "1.3.x",
11
11
  "angular-route": "1.3.x",
12
- "angular-loader": "1.3.x",
13
- "angular-mocks": "1.3.x"
12
+ "moment": "~2.8",
13
+ "angular-moment": "~0.8"
14
14
  },
15
15
  "devDependencies": {
16
+ "angular-loader": "1.3.x",
17
+ "angular-mocks": "1.3.x",
16
18
  "jasmine-core": "~2.1.0",
17
19
  "karma-jasmine": "~0.3.0",
18
20
  "karma": "~0.12.0",
19
21
  "phantomjs": "~1.9.0",
20
- "karma-phantomjs-launcher": "~0.1"
22
+ "karma-story-reporter": "~0.2",
23
+ "karma-coverage": "~0.1",
24
+ "karma-phantomjs-launcher": "~0.1",
25
+ "karma-ng-html2js-preprocessor": "~0.1"
21
26
  },
22
27
  "scripts": {
23
28
  "test": "test/javascript/karma.conf.js"
@@ -12,10 +12,10 @@ Gem::Specification.new do |gem|
12
12
  gem.summary = PuppetHerald::SUMMARY
13
13
  gem.description = PuppetHerald::DESCRIPTION
14
14
 
15
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
16
16
  gem.files = `git ls-files`.split("\n")
17
17
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- gem.require_paths = ["lib"]
18
+ gem.require_paths = ['lib']
19
19
 
20
20
  # Dependencies
21
21
  gem.required_ruby_version = '>= 1.9.2'
@@ -26,9 +26,6 @@ Gem::Specification.new do |gem|
26
26
  gem.add_runtime_dependency 'sinatra-activerecord', '~> 2.0'
27
27
  gem.add_runtime_dependency 'micro-optparse', '~> 1.2'
28
28
  gem.add_runtime_dependency 'uglifier', '~> 2.6'
29
-
30
- # Development and test dependencies specified in Gemfile
31
-
32
29
  end
33
30
 
34
- # vim:ft=ruby
31
+ # vim:ft=ruby
@@ -0,0 +1,175 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'support/reconnectdb'
4
+ require 'spec_helper'
5
+ require 'rspec'
6
+ require 'rack/test'
7
+
8
+ shared_examples 'a redirect to app.html' do
9
+ it { expect(subject).not_to be_successful }
10
+ it { expect(subject).to be_redirection }
11
+ it { expect(subject.status).to eq(301) }
12
+ it { expect(subject.header['Location']).to eq('http://example.org/app.html') }
13
+ end
14
+
15
+ shared_examples 'a proper 2xx - success' do
16
+ it { expect(subject).to be_successful }
17
+ it { expect(subject.status).to be >= 200 }
18
+ it { expect(subject.status).to be < 300 }
19
+ it { expect(subject.body).not_to be_empty }
20
+ end
21
+
22
+ shared_examples '500 - error' do
23
+ it { expect(subject).not_to be_successful }
24
+ it { expect(subject).to be_server_error }
25
+ it { expect(subject.status).to eq 500 }
26
+ it { expect(subject.body).not_to be_empty }
27
+ end
28
+
29
+ shared_examples '404 - not found' do
30
+ it { expect(subject).not_to be_successful }
31
+ it { expect(subject).to be_client_error }
32
+ it { expect(subject.status).to eq 404 }
33
+ it { expect(subject.body).not_to be_empty }
34
+ end
35
+
36
+ shared_examples "working API - success" do
37
+ it { expect(subject.content_type).to eq 'application/json' }
38
+ it_behaves_like 'a proper 2xx - success'
39
+ end
40
+
41
+ shared_examples "working API - not found" do
42
+ it { expect(subject.content_type).to eq 'application/json' }
43
+ it_behaves_like '404 - not found'
44
+ end
45
+
46
+ shared_examples "working API - error" do
47
+ it { expect(subject.content_type).to eq 'application/json' }
48
+ it_behaves_like '500 - error'
49
+ end
50
+
51
+ describe 'The Herald App' do
52
+ include Rack::Test::Methods
53
+
54
+ before(:all) { reconnectdb }
55
+
56
+ def app
57
+ require 'puppet-herald/application'
58
+ PuppetHerald::Application
59
+ end
60
+
61
+ describe "on '/' redirects to '/app.html'" do
62
+ it_behaves_like 'a redirect to app.html' do
63
+ subject { get '/' }
64
+ end
65
+ end
66
+
67
+ describe "on '/index.html' redirects to '/app.html'" do
68
+ it_behaves_like 'a redirect to app.html' do
69
+ subject { get '/index.html' }
70
+ end
71
+ end
72
+
73
+ describe "on main page '/app.html'" do
74
+ subject { get '/app.html' }
75
+ context 'in production' do
76
+ before { expect(PuppetHerald).to receive(:in_prod?).at_least(:once).and_return true }
77
+ it { expect(subject.body).to include 'app.min.js' }
78
+ end
79
+ context 'in dev' do
80
+ before { expect(PuppetHerald).to receive(:in_prod?).at_least(:once).and_return false }
81
+ it { expect(subject.body).not_to include 'app.min.js' }
82
+ it { expect(subject.body).to include 'report.js' }
83
+ it { expect(subject.body).to include 'nodes.js' }
84
+ it { expect(subject.body).to include 'node.js' }
85
+ it { expect(subject.body).to include 'artifact.js' }
86
+ end
87
+ it_behaves_like 'a proper 2xx - success'
88
+ end
89
+
90
+ describe "on '/version.json'" do
91
+ subject { get '/version.json' }
92
+ it_behaves_like 'a proper 2xx - success'
93
+ it { expect(subject.content_type).to eq 'application/json' }
94
+ it { expect(subject.body).to include PuppetHerald::VERSION }
95
+ end
96
+
97
+ describe "on '/app.min.js'" do
98
+ subject { get '/app.min.js' }
99
+ it_behaves_like 'a proper 2xx - success'
100
+ it { expect(subject.content_type).to eq 'application/javascript;charset=utf-8' }
101
+ end
102
+
103
+ describe "on '/app.min.js.map'" do
104
+ subject { get '/app.min.js.map' }
105
+ it_behaves_like 'a proper 2xx - success'
106
+ it { expect(subject.content_type).to eq 'application/javascript;charset=utf-8' }
107
+ end
108
+
109
+ describe "that is received a fatal error" do
110
+ after :each do
111
+ Dir.glob(Dir.tmpdir + '/puppet-herald-bug*.log') { |file| Pathname.new(file).unlink }
112
+ PuppetHerald.environment = :test
113
+ end
114
+ context 'while inside json API' do
115
+ before :each do
116
+ expect_any_instance_of(PuppetHerald::App::ApiImplV1).to receive(:version_json).and_raise :expected
117
+ end
118
+ subject { get '/version.json' }
119
+ context 'in production environment' do
120
+ before :each do
121
+ PuppetHerald.environment = :production
122
+ end
123
+ it_behaves_like 'working API - error'
124
+ end
125
+ context 'in dev environment' do
126
+ before :each do
127
+ PuppetHerald.environment = :development
128
+ end
129
+ it_behaves_like 'working API - error'
130
+ end
131
+ end
132
+ context 'while in standard WWW' do
133
+ before :each do
134
+ expect_any_instance_of(PuppetHerald::App::LogicImpl).to receive(:app_html).and_raise :expected
135
+ end
136
+ subject { get '/app.html' }
137
+ context 'in production environment' do
138
+ before { PuppetHerald.environment = :production }
139
+ it_behaves_like '500 - error'
140
+ it { expect(subject.content_type).to include 'text/html' }
141
+ end
142
+
143
+ context 'in dev environment' do
144
+ before { PuppetHerald.environment = :development }
145
+ it_behaves_like '500 - error'
146
+ it { expect(subject.content_type).to include 'text/html' }
147
+ end
148
+ end
149
+ end
150
+
151
+ context 'API call' do
152
+
153
+ before :each do
154
+ reconnectdb
155
+ end
156
+ describe "post '/api/v1/reports'" do
157
+ let(:yaml) { File.read(File.expand_path("../fixtures/changed-notify.yaml", __FILE__)) }
158
+ subject { post '/api/v1/reports', yaml }
159
+ it_behaves_like 'working API - success'
160
+ end
161
+ describe "get '/api/v1/nodes'" do
162
+ subject { get '/api/v1/nodes' }
163
+ it_behaves_like 'working API - success'
164
+ end
165
+ describe "get '/api/v1/nodes/1'" do
166
+ subject { get '/api/v1/nodes/1' }
167
+ it_behaves_like 'working API - not found'
168
+ end
169
+ describe "get '/api/v1/reports/1'" do
170
+ subject { get '/api/v1/reports/1' }
171
+ it_behaves_like 'working API - not found'
172
+ end
173
+ end
174
+
175
+ end
@@ -3,18 +3,18 @@ require 'puppet-herald/models/report'
3
3
  require 'puppet-herald/models/log-entry'
4
4
  require 'puppet-herald/models/node'
5
5
 
6
- describe Node, '.get_with_reports', :rollback => true do
6
+ describe PuppetHerald::Models::Node, '.get_with_reports', :rollback => true do
7
7
  let(:yaml) { File.read(File.expand_path("../../fixtures/changed-notify.yaml", __FILE__)) }
8
- let(:id) { Report.create_from_yaml(yaml).node_id }
8
+ let(:id) { PuppetHerald::Models::Report.create_from_yaml(yaml).node_id }
9
9
 
10
10
  context 'fetching an existing node' do
11
- subject { Node.get_with_reports id }
11
+ subject { PuppetHerald::Models::Node.get_with_reports id }
12
12
 
13
13
  it "should return value that isn't nil" do
14
14
  subject.should_not be_nil
15
15
  end
16
16
  it "should return a report object" do
17
- subject.class.should eq(Node)
17
+ subject.class.should eq(PuppetHerald::Models::Node)
18
18
  end
19
19
  it "should return persisted node" do
20
20
  subject.persisted?.should be_truthy
@@ -2,19 +2,19 @@ require 'model_helper'
2
2
  require 'puppet-herald/models/report'
3
3
  require 'puppet-herald/models/log-entry'
4
4
 
5
- describe Report, ".create_from_yaml", :rollback => true do
5
+ describe PuppetHerald::Models::Report, ".create_from_yaml", :rollback => true do
6
6
  context 'for valid YAML' do
7
7
  let(:yaml) { File.read(File.expand_path("../../fixtures/changed-notify.yaml", __FILE__)) }
8
8
  it 'that is really not empty' do
9
9
  yaml.should_not be_empty
10
10
  end
11
11
  context 'running on real sqlite3 db' do
12
- subject { Report.create_from_yaml yaml }
12
+ subject { PuppetHerald::Models::Report.create_from_yaml yaml }
13
13
  it "should return value that isn't nil" do
14
14
  subject.should_not be_nil
15
15
  end
16
16
  it "should return a report object" do
17
- subject.class.should eq(Report)
17
+ subject.class.should eq(PuppetHerald::Models::Report)
18
18
  end
19
19
  it "should return persisted report" do
20
20
  subject.persisted?.should be_truthy
@@ -37,18 +37,18 @@ describe Report, ".create_from_yaml", :rollback => true do
37
37
  end
38
38
  end
39
39
 
40
- describe Report, '.get_with_log_entries', :rollback => true do
40
+ describe PuppetHerald::Models::Report, '.get_with_log_entries', :rollback => true do
41
41
  let(:yaml) { File.read(File.expand_path("../../fixtures/changed-notify.yaml", __FILE__)) }
42
- let(:id) { Report.create_from_yaml(yaml).id }
42
+ let(:id) { PuppetHerald::Models::Report.create_from_yaml(yaml).id }
43
43
 
44
44
  context 'fetching an existing report' do
45
- subject { Report.get_with_log_entries id }
45
+ subject { PuppetHerald::Models::Report.get_with_log_entries id }
46
46
 
47
47
  it "should return value that isn't nil" do
48
48
  subject.should_not be_nil
49
49
  end
50
50
  it "should return a report object" do
51
- subject.class.should eq(Report)
51
+ subject.class.should eq(PuppetHerald::Models::Report)
52
52
  end
53
53
  it "should return persisted report" do
54
54
  subject.persisted?.should be_truthy
data/spec/spec_helper.rb CHANGED
@@ -4,13 +4,18 @@ begin
4
4
  gem 'simplecov'
5
5
  require 'simplecov'
6
6
  SimpleCov.start do
7
- add_filter "/test/"
8
- add_filter "/spec/"
9
- add_filter "/.vendor/"
10
- add_filter "/vendor/"
11
- add_filter "/gems/"
12
- add_filter "/node_modules/"
13
- add_filter "/coverage/"
7
+ add_filter '/test/'
8
+ add_filter '/spec/'
9
+ add_filter '/.vendor/'
10
+ add_filter '/vendor/'
11
+ add_filter '/gems/'
12
+ add_filter '/node_modules/'
13
+ add_filter '/coverage/'
14
+ add_group 'Models', 'lib/puppet-herald/models'
15
+ add_group 'App', 'lib/puppet-herald/app'
16
+ minimum_coverage 95
17
+ maximum_coverage_drop 3
18
+ coverage_dir 'coverage/ruby'
14
19
  end
15
20
  rescue Gem::LoadError
16
21
  # do nothing
@@ -1,19 +1,15 @@
1
- require 'puppet-herald/database'
2
- require 'active_record'
3
- require 'stringio' # silence the output
4
- $stdout = StringIO.new # from migrator
1
+ require 'support/reconnectdb'
5
2
 
6
- PuppetHerald::Database.dbconn = 'sqlite3://:memory:'
7
- ActiveRecord::Base.establish_connection(PuppetHerald::Database.spec)
8
- ActiveRecord::Migrator.up "db/migrate"
9
-
10
- $stdout = STDOUT
3
+ reconnectdb
11
4
 
12
5
  RSpec.configure do |config|
13
6
  config.around(:example, {:rollback => true}) do |example|
7
+ ActiveRecord::Base.logger.level = 2 unless ActiveRecord::Base.logger.nil?
14
8
  ActiveRecord::Base.transaction do
15
9
  example.run
16
- raise ActiveRecord::Rollback
10
+ if ActiveRecord::Base.connection.open_transactions > 0
11
+ raise ActiveRecord::Rollback
12
+ end
17
13
  end
18
14
  end
19
15
  end
@@ -0,0 +1,13 @@
1
+ def reconnectdb
2
+ require 'puppet-herald'
3
+ require 'active_record'
4
+ require 'stringio' # silence the output
5
+ $stdout = StringIO.new # from migrator
6
+
7
+ PuppetHerald::database.dbconn = 'sqlite3://:memory:'
8
+ ActiveRecord::Base.establish_connection(PuppetHerald::database.spec)
9
+ ActiveRecord::Base.logger.level = 2 unless ActiveRecord::Base.logger.nil?
10
+ ActiveRecord::Migrator.up "db/migrate"
11
+
12
+ $stdout = STDOUT
13
+ end
@@ -1,18 +1,28 @@
1
1
  require 'spec_helper'
2
2
  require 'puppet-herald'
3
3
  require 'puppet-herald/cli'
4
+ require 'sinatra/base'
5
+
6
+ class TestCLI < PuppetHerald::CLI
7
+ def test_parse(argv)
8
+ self.parse(argv)
9
+ end
10
+ end
4
11
 
5
12
  context 'With silenced loggers' do
6
13
 
14
+ let(:cli) { TestCLI.new }
15
+
7
16
  before :each do
8
- PuppetHerald::CLI::logger.level = 100
9
- PuppetHerald::CLI::errlogger.level = 100
10
- PuppetHerald::Database::logger.level = 100
11
- PuppetHerald::Database::dbconn = nil
17
+ cli.logger.level = 100
18
+ cli.errlogger.level = 100
19
+ PuppetHerald::database::logger.level = 100
20
+ PuppetHerald::database::dbconn = nil
21
+ allow(FileUtils).to receive(:touch)
12
22
  end
13
23
 
14
- describe PuppetHerald::CLI, '.parse_options' do
15
- subject { PuppetHerald::CLI::parse_options argv }
24
+ describe PuppetHerald::CLI, '.parse' do
25
+ subject { cli.test_parse argv }
16
26
 
17
27
  context 'on defaults' do
18
28
  let(:argv) { [] }
@@ -20,7 +30,7 @@ context 'With silenced loggers' do
20
30
  it { subject[:port].should eq 11303 }
21
31
  end
22
32
 
23
- context 'on with invalid DB' do
33
+ context 'with invalid DB configuration given' do
24
34
  let(:argv) { ['--dbconn', '/non-exist/db.sqlite'] }
25
35
 
26
36
  it { expect { subject }.to raise_error(RuntimeError, /Invalid database connection string given/) }
@@ -28,26 +38,48 @@ context 'With silenced loggers' do
28
38
  end
29
39
 
30
40
  describe PuppetHerald::CLI, '.run!' do
31
- subject { PuppetHerald::CLI::run! argv }
41
+ subject { cli.run! argv }
32
42
 
33
43
  context 'on defaults' do
34
44
  let(:argv) { [] }
35
45
  before :each do
36
- require 'puppet-herald/app'
46
+ expect(PuppetHerald).to receive(:in_dev?).at_least(:once).and_return(false)
37
47
  expect(Kernel).to receive(:exit).with(0)
38
- expect(PuppetHerald::App).to receive(:run!).and_return :none
48
+ expect(Sinatra::Application).to receive(:run!).and_return :none
49
+ dbconn = { :adapter => 'sqlite3', :database => ':memory:' }
50
+ expect(PuppetHerald::database).to receive(:spec).at_least(:once).and_return dbconn
51
+ require 'stringio' # silence the output
52
+ $stdout = StringIO.new # from migrator
53
+ end
54
+ after :each do
55
+ $stdout = STDOUT
39
56
  end
40
57
 
41
58
  it { expect(subject).to be_nil }
42
59
  end
43
60
 
44
- context 'on with invalid DB' do
61
+ context 'with exception from within starting application' do
62
+ let(:argv) { [] }
63
+ before :each do
64
+ expect(Kernel).to receive(:exit).with(1).and_raise :excpected1
65
+ expect(ActiveRecord::Base).to receive(:establish_connection).and_raise :expected2
66
+ dbconn = { :adapter => 'sqlite3', :database => ':memory:' }
67
+ expect(PuppetHerald::database).to receive(:spec).at_least(:once).and_return dbconn
68
+ end
69
+ after :each do
70
+ Dir.glob(Dir.tmpdir + '/puppet-herald-bug*.log') { |file| Pathname.new(file).unlink }
71
+ end
72
+
73
+ it { expect { subject }.to raise_error }
74
+ end
75
+
76
+ context 'with invalid DB configuration given' do
45
77
  let(:argv) { ['--dbconn', '/non-exist/db.sqlite'] }
46
78
  before :each do
47
- expect(Kernel).to receive(:exit).with(2)
79
+ expect(Kernel).to receive(:exit).with(2).and_raise :excpected
48
80
  end
49
81
 
50
- it { expect(subject).to be_nil }
82
+ it { expect { subject }.to raise_error }
51
83
  end
52
84
  end
53
85