puppet-herald 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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