Top Level Namespace
Defined Under Namespace
Modules: CookbookDecompiler Classes: TestbeatContext, TestbeatNode, TestbeatRestRequest, TestbeatShell, TestbeatShellStub, TestbeatShellVagrant
Constant Summary collapse
- HTTP_VERBS =
{ 'COPY' => Net::HTTP::Copy, 'DELETE' => Net::HTTP::Delete, 'GET' => Net::HTTP::Get, 'HEAD' => Net::HTTP::Head, 'LOCK' => Net::HTTP::Lock, 'MKCOL' => Net::HTTP::Mkcol, 'MOVE' => Net::HTTP::Move, 'OPTIONS' => Net::HTTP::Options, 'PATCH' => Net::HTTP::Patch, 'POST' => Net::HTTP::Post, 'PROPFIND' => Net::HTTP::Propfind, 'PROPPATCH' => Net::HTTP::Proppatch, 'PUT' => Net::HTTP::Put, 'TRACE' => Net::HTTP::Trace, 'UNLOCK' => Net::HTTP::Unlock }
- HTTP_VERB_RESOURCE =
/^(COPY|DELETE|GET|HEAD|LOCK|MKCOL|MOVE|OPTIONS|PATCH|POST|PROPFIND|PROPPATCH|PUT|TRACE|UNLOCK)\s+(\S+)/
Instance Method Summary collapse
- #get_cookbook_name(line) ⇒ Object
- #get_default_recipe(cookbook_name) ⇒ Object
- #get_include_lines(file) ⇒ Object
- #get_included_cookbooks(cookbook_name) ⇒ Object
-
#get_match(pattern, text) ⇒ Object
Get first matching subgroup stripped of quotes and leading/trailing whitespace.
-
#main(node: "labs01", provider: "virtualbox", retest: false, guestint: true, verbose: true) ⇒ Object
guestint: run on-guest integration tests.
- #remove_recipe_part(name) ⇒ Object
- #run_integration_tests(recipes) ⇒ Object
-
#run_integration_tests_bats(tests) ⇒ Object
Prepared commands from run_tests are fed in here.
- #run_rspec(node, path, outf, verbose) ⇒ Object
- #run_tests(recipes, out: "#{$vagrant_dir}#{$node}/generated/", testglob: "test/acceptance/*.rb", verbose: true) ⇒ Object
Instance Method Details
#get_cookbook_name(line) ⇒ Object
22 23 24 25 26 27 28 29 30 |
# File 'lib/vagrant/cookbook_decompiler.rb', line 22 def get_cookbook_name(line) name_match = /include_recipe.?"([^"]*)"/.match(line) if name_match just_name = name_match[1].split("::")[0] return just_name else raise "Line #{line} does not contain an include_recipe statement" end end |
#get_default_recipe(cookbook_name) ⇒ Object
8 9 10 |
# File 'lib/vagrant/cookbook_decompiler.rb', line 8 def get_default_recipe(cookbook_name) return File.open($cookbooks_dir + "/" + cookbook_name + "/recipes/default.rb","r") end |
#get_include_lines(file) ⇒ Object
12 13 14 15 16 17 18 19 20 |
# File 'lib/vagrant/cookbook_decompiler.rb', line 12 def get_include_lines(file) lines_with_include = [] file.each_line do |line| if /include_recipe/.match(line) lines_with_include.push(line) end end return lines_with_include end |
#get_included_cookbooks(cookbook_name) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/vagrant/cookbook_decompiler.rb', line 36 def get_included_cookbooks(cookbook_name) just_name = remove_recipe_part(cookbook_name) recipe_default = get_default_recipe(just_name) lines = get_include_lines(recipe_default) names = [] lines.each do |line| name = get_cookbook_name(line) names.push(name) unless names.include? name end return names end |
#get_match(pattern, text) ⇒ Object
Get first matching subgroup
stripped of quotes and leading/trailing whitespace
13 14 15 16 17 |
# File 'lib/vagrant/noderunner.rb', line 13 def get_match(pattern, text) matches = pattern.match(text) the_match = matches[1] the_match.delete("\"").strip() end |
#main(node: "labs01", provider: "virtualbox", retest: false, guestint: true, verbose: true) ⇒ Object
guestint: run on-guest integration tests
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/vagrant/noderunner.rb', line 162 def main(node: "labs01", provider: "virtualbox", retest: false, guestint: true, verbose: true) [node, provider, retest, guestint, verbose] $node = node = {} $chef_dir = "" $vagrant_dir = $chef_dir + "nodes/" $bats_test_tmp = $vagrant_dir + "bats_tmp/" $vagrant_file = $vagrant_dir + $node + "/Vagrantfile" #$vagrant_chef_dir = %x[ cd #{$vagrant_dir}#{node}; vagrant ssh -c "find /tmp/vagrant-chef/ -maxdepth 2 -type d -name cookbooks ] #"/tmp/vagrant-chef/chef-solo-1/" puts "### node: #{$node} (#{$vagrant_dir + $node}) ###" recipes = [] if not (Dir.exists?($vagrant_dir + $node) and File.exists?($vagrant_file)) $stderr.puts "No such Vagrant node #{ $node }" exit 1 end # ---------------------------------------------------------------------------------- # Start Vagrant or run provision on an already running node cwd_to_node = "cd #{ $vagrant_dir + $node}; " v_status = %x[ cd #{ $vagrant_dir + $node}; vagrant status ] runlist_file = "/tmp/#{$node}_testbeat.runlist"; if /poweroff/.match(v_status) or /not created/.match(v_status) puts "Vagrant node not running, start and provision..." if File.exists?(runlist_file) File.delete(runlist_file) end vagrant_cmd = cwd_to_node + "vagrant up --provider=#{provider}" elsif /running/.match(v_status) # Add "if runlist file older than 1 h, assume force_long" if retest and File.exists?(runlist_file) old_run = File.read(runlist_file) #run_match = /Run List expands to \[(.*?)\]/.match(old_run) recipes = old_run.split(", ") print "Recipes (rerun based on #{runlist_file}): " puts recipes all_cookbooks = CookbookDecompiler.resolve_dependencies(recipes).to_a puts "All cookbooks included: " + all_cookbooks.join(", ") # code duplicated from uncached runlist below rspec_ok = true if guestint rspec_ok = rspec_ok && run_integration_tests(all_cookbooks) end rspec_ok = rspec_ok && run_tests(all_cookbooks) if not rspec_ok puts "There were test failures!" exit 1 end puts "All tests for cached runlist passed" exit 0 else puts "Vagrant node running, provision..." vagrant_cmd = cwd_to_node + "vagrant provision" end else $stderr.puts "Unknown Vagrant state: #{v_status}" end # ---------------------------------------------------------------------------------- # Build an array consisting of custom tests to be compared with Vagrant provision # output # First we look up tests for our custom Vagrant output checker test_collection = [] if [:tests] tests = [:tests].split(",") tests.each do |opt| test_file_path = opt if File.exists?(test_file_path) contents = File.read(test_file_path) obj = JSON.parse(contents) obj["tests"].each do |test| test_collection.push(test) end end end end #vagrant_run_output = %x[ export LANG=en_US.UTF-8; #{vagrant_cmd} ] vagrant_run_output = '' IO.popen(vagrant_cmd, :err=>[:child, :out], :external_encoding=>"UTF-8") do |io| io.each do |line| if verbose then puts line end vagrant_run_output << line + "\n" end end result = $?.success? if not result $stderr.puts "Vagrant run failed! See output below" $stderr.puts vagrant_run_output exit 1 else puts "Vagrant provision completed." # 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] run_match = /Run List expands to \[(.*?)\]/.match(vagrant_run_output) if run_match dump_file = File.new("/tmp/#{$node}_testbeat.runlist","w+",0755) dump_file.write(run_match[1]) # should be run_match[1] but role-leanserver edit above... dump_file.close() recipes = run_match[1].split(", ") puts "Run list extracted from Vagrant: " + recipes.join(", ") all_cookbooks = CookbookDecompiler.resolve_dependencies(recipes).to_a puts "All cookbooks included: " + all_cookbooks.join(", ") puts "test_collection (presumably not used anymore): " + test_collection.join(", "); # the run code has been duplicated for cached runlist above rspec_ok = true if guestint rspec_ok = rspec_ok && run_integration_tests(all_cookbooks) end rspec_ok = rspec_ok && run_tests(all_cookbooks) if not rspec_ok exit 1 end else puts "Unable to find text 'Run List expands to' in Vagrant output :(" end end end |
#remove_recipe_part(name) ⇒ Object
32 33 34 |
# File 'lib/vagrant/cookbook_decompiler.rb', line 32 def remove_recipe_part(name) return name.split("::")[0] end |
#run_integration_tests(recipes) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/vagrant/noderunner.rb', line 29 def run_integration_tests(recipes) # Now its time for the bats tests. integration_tests = [] repos_backup_testing = false # Next we reduce recipes to cookbooks if recipes.include?("repos-backup") recipes.delete("repos-backup") repos_backup_testing = true end integration_result_format = "--format RspecJunitFormatter" node_path_to_cookbooks = "" sync_data = File.read($vagrant_dir + $node + "/.vagrant/machines/default/virtualbox/synced_folders") sync_info = JSON.parse(sync_data) sync_info['virtualbox'].each do |key,value| if /cookbooks/.match(value['hostpath']) node_path_to_cookbooks = value['guestpath'].split("/")[0..-2].join("/") break end end recipes.each do |recipe| # break off sub-recipe name from cookbook name # repos-channel::haproxy -> repos-channel puts "Recipe: #{recipe}" cookbook_name = recipe.split("::")[0] path_to_cookbook_integration_tests = "cookbooks/#{cookbook_name}/test/integration/default" if Dir.exists?(path_to_cookbook_integration_tests) puts "Found: #{path_to_cookbook_integration_tests}" Dir.glob("#{path_to_cookbook_integration_tests}/*.rb").each do |path_to_file| # /tmp/vagrant-chef-?/chef-solo-1/ # cd #{$vagrant_dir}#{node}; vagrant ssh -c puts "node_path_to_cookbooks: #{node_path_to_cookbooks}. path_to_file: #{path_to_file}" integration_tests.push("rspec #{integration_result_format} #{node_path_to_cookbooks}/#{path_to_file} > /vagrant/generated_integration_results_#{cookbook_name}.xml") end else puts "Couldn't find #{path_to_cookbook_integration_tests}" end end path_to_node_integration_tests = "#{$vagrant_dir}#{$node}/integration/default" if Dir.exists?(path_to_node_integration_tests) Dir.glob("#{path_to_node_integration_tests}/*.rb").each do |path_to_file| just_filename = path_to_file.split("/")[-1] integration_tests.push("rspec #{integration_result_format} /vagrant/integration/default/#{just_filename} > /vagrant/generated_integration_results_#{$node}.xml") end else puts "No node-specific integration tests available for #{$node} in #{path_to_node_integration_tests}" end if integration_tests.empty?() puts "No integration tests for node #{$node}" else run_integration_tests_bats(integration_tests) end if repos_backup_testing 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]'\"") end #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" #run_integration_tests_bats([backup_test_cmd]) end |
#run_integration_tests_bats(tests) ⇒ Object
Prepared commands from run_tests are fed in here.
20 21 22 23 24 25 26 27 |
# File 'lib/vagrant/noderunner.rb', line 20 def run_integration_tests_bats(tests) puts "Running bats tests for cookbooks." tests.sort().each do |cmd| #print "Running bats test #{cmd}" system("cd #{ $vagrant_dir + $node }; vagrant ssh -c \"#{cmd}\"") end end |
#run_rspec(node, path, outf, verbose) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/vagrant/noderunner.rb', line 90 def run_rspec(node, path, outf, verbose) puts "Starting test: #{path}" rspec_cmd = "NODE=#{node} rspec #{path} --format documentation --out #{outf}.txt --format html --out #{outf}.html --format RspecJunitFormatter --out #{outf}.xml --format progress" IO.popen(rspec_cmd, :err=>[:child, :out], :external_encoding=>"UTF-8") do |io| io.each_char do |c| if verbose then $stdout.print c if c == '.' or c == 'F' or c == "\n" then $stdout.flush end end end end return $?.success? end |
#run_tests(recipes, out: "#{$vagrant_dir}#{$node}/generated/", testglob: "test/acceptance/*.rb", verbose: true) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/vagrant/noderunner.rb', line 104 def run_tests(recipes, out: "#{$vagrant_dir}#{$node}/generated/", testglob: "test/acceptance/*.rb", verbose: true) [recipes, out, testglob, verbose] rspec_ok = true # if no tests => no failure if Dir.exists?(out) puts "Using existing output directory #{out}" Dir.glob("#{out}acceptance*").each do |previous| File.delete(previous); end else puts "Creating output directory #{out}" end run_history = Set.new() recipes.each do |recipe| # break off sub-recipe name from cookbook name # repos-channel::haproxy -> repos-channel #puts "Recipe: " + recipe cookbook_name = recipe.split("::")[0] cookbook_specs = Dir.glob("cookbooks/#{cookbook_name}/#{testglob}") if cookbook_specs.length == 0 puts "No generic acceptance tests available for #{recipe} in #{$chef_dir}cookbooks/#{cookbook_name}/test/acceptance" end cookbook_specs.each do |path_to_file| if not run_history.include?(path_to_file) run_history.add(path_to_file) just_filename = path_to_file.split("/")[-1] rspec_ok = run_rspec($node, path_to_file, "#{out}acceptance_#{cookbook_name}_#{just_filename}", verbose) && rspec_ok end end end path_to_node_acceptance_tests = "#{$vagrant_dir}#{$node}/acceptance" if Dir.exists?(path_to_node_acceptance_tests) rspec_ok = run_rspec($node, "#{path_to_node_acceptance_tests}/*.rb", "#{out}acceptance_node", verbose) && rspec_ok else puts "No node-specific acceptance tests available for #{$node} in #{path_to_node_acceptance_tests}" end # Print a summary in the end concat = File.open("#{out}acceptance.txt", "w") Dir.glob("#{out}acceptance_*.txt").each do |generated_docs| puts generated_docs concat.write("#" + generated_docs) File.readlines(generated_docs).each do |line| concat.write(line) results = /^\d+ examples, (\d+) failure.?/.match(line) if results puts line end end end concat.close unless concat.nil? return rspec_ok end |