testbeat 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a07df1c8d2decd193451ed6563c37ecf5d77e4e6
4
- data.tar.gz: efc84e08c072861996aca8d767fe7195da3e87d0
3
+ metadata.gz: 02cef2aff2396b4839c9bd7af2bd8c99d1abf7df
4
+ data.tar.gz: c1de2a32d44fd2875ae8f472c5b6c5171ce61d0b
5
5
  SHA512:
6
- metadata.gz: 90f7258973368c942e722f6b1be18804ca132da3e05d5da189ac339f49705b7cb191ceb2268cdb65567a131578e8f7204085ab73bc91727754724384abea11e7
7
- data.tar.gz: fc8a054528bedcbc506d183138d5414fdcd1d30dd69ef73dd900b6000f305e5fde425a04838d8b36dae9b1c68d169026638f601bdbc13905648637410959befb
6
+ metadata.gz: 44c1420a77283d2229cf547ed5d02cf3a28710e462b065ffbdbf2671caca746f4781bf65ddbd16b1441e3575c69579c7cdf3051c66139b617b566869ffa8155a
7
+ data.tar.gz: baa1fcd721c9febf81c6c989008b2462f63abcb6cae43d9b4ed473edfdc244979ff34f4108d45fe8726e06ed4998f7b42c0b9ad8c298664b002b0881ab2849e4
File without changes
data/lib/testbeat.rb CHANGED
@@ -1,9 +1,16 @@
1
1
 
2
- #require 'testbeat/rspec'
3
- #require 'testbeat/vagrant'
4
- require_relative './spec_helper.rb'
2
+ require 'rspec/spec_helper.rb' if defined? RSpec
5
3
 
6
- #module testbeat
4
+ #module Testbeat
5
+
6
+ # https://route.github.io/2013/11/05/ruby-loading-and-requiring-files-constant-name-resolution.html
7
+ #autoload :Noderunner, 'vagrant/noderunner.rb'
8
+
9
+ #end
10
+
11
+ require 'vagrant/noderunner.rb'
12
+
13
+ #module Testbeat
7
14
  #
8
15
  # autoload :RSpec, './spec_helper.rb'
9
16
  #
@@ -0,0 +1,73 @@
1
+
2
+ #!/usr/bin/ruby
3
+
4
+ require 'set'
5
+
6
+ $cookbooks_dir = config_path = File.join(Dir.pwd, "cookbooks")
7
+
8
+ def get_default_recipe(cookbook_name)
9
+ return File.open($cookbooks_dir + "/" + cookbook_name + "/recipes/default.rb","r")
10
+ end
11
+
12
+ def get_include_lines(file)
13
+ lines_with_include = []
14
+ file.each_line do |line|
15
+ if /include_recipe/.match(line)
16
+ lines_with_include.push(line)
17
+ end
18
+ end
19
+ return lines_with_include
20
+ end
21
+
22
+ def get_cookbook_name(line)
23
+ name_match = /include_recipe.?"([^"]*)"/.match(line)
24
+ if name_match
25
+ just_name = name_match[1].split("::")[0]
26
+ return just_name
27
+ else
28
+ raise "Line #{line} does not contain an include_recipe statement"
29
+ end
30
+ end
31
+
32
+ def remove_recipe_part(name)
33
+ return name.split("::")[0]
34
+ end
35
+
36
+ def get_included_cookbooks(cookbook_name)
37
+ just_name = remove_recipe_part(cookbook_name)
38
+ recipe_default = get_default_recipe(just_name)
39
+ lines = get_include_lines(recipe_default)
40
+ names = []
41
+ lines.each do |line|
42
+ name = get_cookbook_name(line)
43
+ names.push(name) unless names.include? name
44
+ end
45
+ return names
46
+ end
47
+
48
+ module CookbookDecompiler
49
+
50
+ def CookbookDecompiler.resolve_dependencies(cookbook_names)
51
+
52
+
53
+ # First level cookbooks are obviously included, so let's make them the starting set.
54
+ cookbooks_to_be_returned = Set.new(cookbook_names)
55
+
56
+ loop do
57
+ # Next, find the second level cookbooks.
58
+ second_set = Set.new()
59
+ cookbooks_to_be_returned.each do |name|
60
+ included_cookbooks = get_included_cookbooks(name)
61
+ second_set = second_set.merge(included_cookbooks)
62
+ end
63
+ if second_set.subset? cookbooks_to_be_returned
64
+ return cookbooks_to_be_returned
65
+ else
66
+ cookbooks_to_be_returned.merge(second_set)
67
+ end
68
+ end
69
+ # If all second level cookbooks are already in the set, we're done.
70
+ # otherwise we repeat, treating the second level cookbooks as first level.
71
+
72
+ end
73
+ end
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'optparse'
4
+ require 'json'
5
+ require 'pp'
6
+ require_relative './cookbook_decompiler.rb'
7
+ # dependencies for the lib running node tests, preferrably discovered here instead of in node loop
8
+ require 'rspec'
9
+ require 'set'
10
+
11
+ # Get first matching subgroup
12
+ # stripped of quotes and leading/trailing whitespace
13
+ def get_match(pattern, text)
14
+ matches = pattern.match(text)
15
+ the_match = matches[1]
16
+ the_match.delete("\"").strip()
17
+ end
18
+
19
+ # Prepared commands from run_tests are fed in here.
20
+ def run_integration_tests_bats(tests)
21
+ puts "Running bats tests for cookbooks."
22
+
23
+ tests.sort().each do |cmd|
24
+ #print "Running bats test #{cmd}"
25
+ system("cd #{ $vagrant_dir + $node }; vagrant ssh -c \"#{cmd}\"")
26
+ end
27
+ end
28
+
29
+ def run_integration_tests(recipes)
30
+ # Now its time for the bats tests.
31
+ integration_tests = []
32
+ repos_backup_testing = false
33
+ # Next we reduce recipes to cookbooks
34
+ if recipes.include?("repos-backup")
35
+ recipes.delete("repos-backup")
36
+ repos_backup_testing = true
37
+ end
38
+
39
+ integration_result_format = "--format RspecJunitFormatter"
40
+ node_path_to_cookbooks = ""
41
+ sync_data = File.read($vagrant_dir + $node + "/.vagrant/machines/default/virtualbox/synced_folders")
42
+ sync_info = JSON.parse(sync_data)
43
+ sync_info['virtualbox'].each do |key,value|
44
+ if /cookbooks/.match(value['hostpath'])
45
+ node_path_to_cookbooks = value['guestpath'].split("/")[0..-2].join("/")
46
+ break
47
+ end
48
+ end
49
+ recipes.each do |recipe|
50
+ # break off sub-recipe name from cookbook name
51
+ # repos-channel::haproxy -> repos-channel
52
+ puts "Recipe: #{recipe}"
53
+ cookbook_name = recipe.split("::")[0]
54
+ path_to_cookbook_integration_tests = "cookbooks/#{cookbook_name}/test/integration/default"
55
+ if Dir.exists?(path_to_cookbook_integration_tests)
56
+ puts "Found: #{path_to_cookbook_integration_tests}"
57
+ Dir.glob("#{path_to_cookbook_integration_tests}/*.rb").each do |path_to_file|
58
+ # /tmp/vagrant-chef-?/chef-solo-1/
59
+ # cd #{$vagrant_dir}#{node}; vagrant ssh -c
60
+ puts "node_path_to_cookbooks: #{node_path_to_cookbooks}. path_to_file: #{path_to_file}"
61
+ integration_tests.push("rspec #{integration_result_format} #{node_path_to_cookbooks}/#{path_to_file} > /vagrant/generated_integration_results_#{cookbook_name}.xml")
62
+ end
63
+ else
64
+ puts "Couldn't find #{path_to_cookbook_integration_tests}"
65
+ end
66
+ end
67
+ path_to_node_integration_tests = "#{$vagrant_dir}#{$node}/integration/default"
68
+ if Dir.exists?(path_to_node_integration_tests)
69
+ Dir.glob("#{path_to_node_integration_tests}/*.rb").each do |path_to_file|
70
+ just_filename = path_to_file.split("/")[-1]
71
+ integration_tests.push("rspec #{integration_result_format} /vagrant/integration/default/#{just_filename} > /vagrant/generated_integration_results_#{$node}.xml")
72
+ end
73
+ else
74
+ puts "No node-specific integration tests available for #{$node} in #{path_to_node_integration_tests}"
75
+ end
76
+
77
+ if integration_tests.empty?()
78
+ puts "No integration tests for node #{$node}"
79
+ else
80
+ run_integration_tests_bats(integration_tests)
81
+ end
82
+ if repos_backup_testing
83
+ system("cd #{ $vagrant_dir + $node }; vagrant ssh -c \"sudo chef-solo -j /tmp/vagrant-chef/dna.json -c /tmp/vagrant-chef/solo.rb -o 'recipe[cms-base],recipe[repos-backup]'\"")
84
+ end
85
+
86
+ #backup_test_cmd = "rspec -f j /tmp/vagrant-chef-?/chef-solo-1/cookbooks/repos-backup/test/integration/default/repos-backup_spec.rb > integration_repos-backup.txt"
87
+ #run_integration_tests_bats([backup_test_cmd])
88
+ end
89
+
90
+ def run_rspec(node, path, outf, verbose)
91
+ puts "Starting test: #{path}"
92
+ rspec_cmd = "NODE=#{node} rspec #{path} --format documentation --out #{outf}.txt --format html --out #{outf}.html --format RspecJunitFormatter --out #{outf}.xml --format progress"
93
+ IO.popen(rspec_cmd, :err=>[:child, :out], :external_encoding=>"UTF-8") do |io|
94
+ io.each_char do |c|
95
+ if verbose then
96
+ $stdout.print c
97
+ if c == '.' or c == 'F' or c == "\n" then $stdout.flush end
98
+ end
99
+ end
100
+ end
101
+ return $?.success?
102
+ end
103
+
104
+ def run_tests(recipes, out: "#{$vagrant_dir}#{$node}/generated/", testglob: "test/acceptance/*.rb", verbose: true)
105
+ [recipes, out, testglob, verbose]
106
+ rspec_ok = true # if no tests => no failure
107
+
108
+ if Dir.exists?(out)
109
+ puts "Using existing output directory #{out}"
110
+ Dir.glob("#{out}acceptance*").each do |previous|
111
+ File.delete(previous);
112
+ end
113
+ else
114
+ puts "Creating output directory #{out}"
115
+ end
116
+
117
+ run_history = Set.new()
118
+ recipes.each do |recipe|
119
+ # break off sub-recipe name from cookbook name
120
+ # repos-channel::haproxy -> repos-channel
121
+ #puts "Recipe: " + recipe
122
+ cookbook_name = recipe.split("::")[0]
123
+ cookbook_specs = Dir.glob("cookbooks/#{cookbook_name}/#{testglob}")
124
+ if cookbook_specs.length == 0
125
+ puts "No generic acceptance tests available for #{recipe} in #{$chef_dir}cookbooks/#{cookbook_name}/test/acceptance"
126
+ end
127
+ cookbook_specs.each do |path_to_file|
128
+ if not run_history.include?(path_to_file)
129
+ run_history.add(path_to_file)
130
+ just_filename = path_to_file.split("/")[-1]
131
+ rspec_ok = run_rspec($node, path_to_file, "#{out}acceptance_#{cookbook_name}_#{just_filename}", verbose) && rspec_ok
132
+ end
133
+ end
134
+ end
135
+
136
+ path_to_node_acceptance_tests = "#{$vagrant_dir}#{$node}/acceptance"
137
+ if Dir.exists?(path_to_node_acceptance_tests)
138
+ rspec_ok = run_rspec($node, "#{path_to_node_acceptance_tests}/*.rb", "#{out}acceptance_node", verbose) && rspec_ok
139
+ else
140
+ puts "No node-specific acceptance tests available for #{$node} in #{path_to_node_acceptance_tests}"
141
+ end
142
+
143
+ # Print a summary in the end
144
+ concat = File.open("#{out}acceptance.txt", "w")
145
+ Dir.glob("#{out}acceptance_*.txt").each do |generated_docs|
146
+ puts generated_docs
147
+ concat.write("#" + generated_docs)
148
+ File.readlines(generated_docs).each do |line|
149
+ concat.write(line)
150
+ results = /^\d+ examples, (\d+) failure.?/.match(line)
151
+ if results
152
+ puts line
153
+ end
154
+ end
155
+ end
156
+ concat.close unless concat.nil?
157
+
158
+ return rspec_ok
159
+ end
160
+
161
+ # guestint: run on-guest integration tests
162
+ def main(node: "labs01", provider: "virtualbox", retest: false, guestint: true, verbose: true)
163
+ [node, provider, retest, guestint, verbose]
164
+ $node = node
165
+ options = {}
166
+
167
+ $chef_dir = ""
168
+ $vagrant_dir = $chef_dir + "nodes/"
169
+ $bats_test_tmp = $vagrant_dir + "bats_tmp/"
170
+
171
+ $vagrant_file = $vagrant_dir + $node + "/Vagrantfile"
172
+ #$vagrant_chef_dir = %x[ cd #{$vagrant_dir}#{node}; vagrant ssh -c "find /tmp/vagrant-chef/ -maxdepth 2 -type d -name cookbooks ]
173
+ #"/tmp/vagrant-chef/chef-solo-1/"
174
+
175
+ puts "### node: #{$node} (#{$vagrant_dir + $node}) ###"
176
+ recipes = []
177
+
178
+
179
+ if not (Dir.exists?($vagrant_dir + $node) and File.exists?($vagrant_file))
180
+ $stderr.puts "No such Vagrant node #{ $node }"
181
+ exit 1
182
+ end
183
+
184
+ # ----------------------------------------------------------------------------------
185
+ # Start Vagrant or run provision on an already running node
186
+
187
+ cwd_to_node = "cd #{ $vagrant_dir + $node}; "
188
+
189
+ v_status = %x[ cd #{ $vagrant_dir + $node}; vagrant status ]
190
+ runlist_file = "/tmp/#{$node}_testbeat.runlist";
191
+ if /poweroff/.match(v_status) or /not created/.match(v_status)
192
+ puts "Vagrant node not running, start and provision..."
193
+ if File.exists?(runlist_file)
194
+ File.delete(runlist_file)
195
+ end
196
+ vagrant_cmd = cwd_to_node + "vagrant up --provider=#{provider}"
197
+ elsif /running/.match(v_status)
198
+ # Add "if runlist file older than 1 h, assume force_long"
199
+ if retest and File.exists?(runlist_file)
200
+ old_run = File.read(runlist_file)
201
+ #run_match = /Run List expands to \[(.*?)\]/.match(old_run)
202
+ recipes = old_run.split(", ")
203
+ print "Recipes (rerun based on #{runlist_file}): "
204
+ puts recipes
205
+ all_cookbooks = CookbookDecompiler.resolve_dependencies(recipes).to_a
206
+ puts "All cookbooks included: " + all_cookbooks.join(", ")
207
+ # code duplicated from uncached runlist below
208
+ rspec_ok = true
209
+ if guestint
210
+ rspec_ok = rspec_ok && run_integration_tests(all_cookbooks)
211
+ end
212
+ rspec_ok = rspec_ok && run_tests(all_cookbooks)
213
+ if not rspec_ok
214
+ puts "There were test failures!"
215
+ exit 1
216
+ end
217
+ puts "All tests for cached runlist passed"
218
+ exit 0
219
+ else
220
+ puts "Vagrant node running, provision..."
221
+ vagrant_cmd = cwd_to_node + "vagrant provision"
222
+ end
223
+ else
224
+ $stderr.puts "Unknown Vagrant state: #{v_status}"
225
+ end
226
+
227
+ # ----------------------------------------------------------------------------------
228
+ # Build an array consisting of custom tests to be compared with Vagrant provision
229
+ # output
230
+
231
+ # First we look up tests for our custom Vagrant output checker
232
+ test_collection = []
233
+
234
+ if options[:tests]
235
+ tests = options[:tests].split(",")
236
+ tests.each do |opt|
237
+ test_file_path = opt
238
+ if File.exists?(test_file_path)
239
+ contents = File.read(test_file_path)
240
+ obj = JSON.parse(contents)
241
+ obj["tests"].each do |test|
242
+ test_collection.push(test)
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ #vagrant_run_output = %x[ export LANG=en_US.UTF-8; #{vagrant_cmd} ]
249
+ vagrant_run_output = ''
250
+ IO.popen(vagrant_cmd, :err=>[:child, :out], :external_encoding=>"UTF-8") do |io|
251
+ io.each do |line|
252
+ if verbose then puts line end
253
+ vagrant_run_output << line + "\n"
254
+ end
255
+ end
256
+ result = $?.success?
257
+
258
+ if not result
259
+ $stderr.puts "Vagrant run failed! See output below"
260
+ $stderr.puts vagrant_run_output
261
+ exit 1
262
+ else
263
+ puts "Vagrant provision completed."
264
+ # Run List expands to [repos-channel::haproxy, cms-base::folderstructure, repos-apache2, repos-subversion, repos-rweb, repos-trac, repos-liveserver, repos-indexing, repos-snapshot, repos-vagrant-labs]
265
+ run_match = /Run List expands to \[(.*?)\]/.match(vagrant_run_output)
266
+ if run_match
267
+ dump_file = File.new("/tmp/#{$node}_testbeat.runlist","w+",0755)
268
+ dump_file.write(run_match[1]) # should be run_match[1] but role-leanserver edit above...
269
+ dump_file.close()
270
+
271
+ recipes = run_match[1].split(", ")
272
+ puts "Run list extracted from Vagrant: " + recipes.join(", ")
273
+ all_cookbooks = CookbookDecompiler.resolve_dependencies(recipes).to_a
274
+ puts "All cookbooks included: " + all_cookbooks.join(", ")
275
+ puts "test_collection (presumably not used anymore): " + test_collection.join(", ");
276
+ # the run code has been duplicated for cached runlist above
277
+ rspec_ok = true
278
+ if guestint
279
+ rspec_ok = rspec_ok && run_integration_tests(all_cookbooks)
280
+ end
281
+ rspec_ok = rspec_ok && run_tests(all_cookbooks)
282
+ if not rspec_ok
283
+ exit 1
284
+ end
285
+ else
286
+ puts "Unable to find text 'Run List expands to' in Vagrant output :("
287
+ end
288
+ end
289
+
290
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testbeat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Staffan Olsson
@@ -60,7 +60,9 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - lib/testbeat.rb
63
- - lib/spec_helper.rb
63
+ - lib/rspec/spec_helper.rb
64
+ - lib/vagrant/noderunner.rb
65
+ - lib/vagrant/cookbook_decompiler.rb
64
66
  homepage: https://github.com/Reposoft/testbeat
65
67
  licenses:
66
68
  - MIT