pennyworth-tool 0.0.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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.hound.yml +3 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +18 -0
  6. data/CONTRIBUTING.md +67 -0
  7. data/COPYING +674 -0
  8. data/Gemfile +28 -0
  9. data/README.md +339 -0
  10. data/Rakefile +33 -0
  11. data/bin/pennyworth +26 -0
  12. data/config/setup.yml +17 -0
  13. data/examples/README.md +23 -0
  14. data/examples/kiwi/definitions/base_opensuse13.1_kvm/config.sh +87 -0
  15. data/examples/kiwi/definitions/base_opensuse13.1_kvm/config.xml +64 -0
  16. data/examples/kiwi/definitions/base_opensuse13.1_kvm/root/etc/sysconfig/network/ifcfg-eth0 +2 -0
  17. data/examples/kiwi/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
  18. data/examples/vagrant/Vagrantfile +14 -0
  19. data/files/99-libvirt.rules +2 -0
  20. data/files/image_test-template.xml +43 -0
  21. data/files/pool-default.xml +6 -0
  22. data/lib/image_runner.rb +89 -0
  23. data/lib/pennyworth.rb +65 -0
  24. data/lib/pennyworth/cli.rb +339 -0
  25. data/lib/pennyworth/cli_host_controller.rb +107 -0
  26. data/lib/pennyworth/commands/base_command.rb +96 -0
  27. data/lib/pennyworth/commands/boot_command.rb +29 -0
  28. data/lib/pennyworth/commands/build_base_command.rb +103 -0
  29. data/lib/pennyworth/commands/command.rb +43 -0
  30. data/lib/pennyworth/commands/down_command.rb +25 -0
  31. data/lib/pennyworth/commands/import_base_command.rb +112 -0
  32. data/lib/pennyworth/commands/import_ssh_keys_command.rb +27 -0
  33. data/lib/pennyworth/commands/list_command.rb +41 -0
  34. data/lib/pennyworth/commands/setup_command.rb +209 -0
  35. data/lib/pennyworth/commands/shutdown_command.rb +28 -0
  36. data/lib/pennyworth/commands/status_command.rb +26 -0
  37. data/lib/pennyworth/commands/up_command.rb +27 -0
  38. data/lib/pennyworth/exceptions.rb +39 -0
  39. data/lib/pennyworth/helper.rb +39 -0
  40. data/lib/pennyworth/host_config.rb +86 -0
  41. data/lib/pennyworth/host_runner.rb +133 -0
  42. data/lib/pennyworth/image_runner.rb +89 -0
  43. data/lib/pennyworth/libvirt.rb +93 -0
  44. data/lib/pennyworth/local_command_runner.rb +77 -0
  45. data/lib/pennyworth/local_runner.rb +34 -0
  46. data/lib/pennyworth/lock_service.rb +87 -0
  47. data/lib/pennyworth/remote_command_runner.rb +144 -0
  48. data/lib/pennyworth/runner.rb +27 -0
  49. data/lib/pennyworth/settings.rb +42 -0
  50. data/lib/pennyworth/spec.rb +96 -0
  51. data/lib/pennyworth/spec_profiler.rb +85 -0
  52. data/lib/pennyworth/ssh_keys_importer.rb +107 -0
  53. data/lib/pennyworth/urls.rb +28 -0
  54. data/lib/pennyworth/vagrant.rb +81 -0
  55. data/lib/pennyworth/vagrant_command.rb +120 -0
  56. data/lib/pennyworth/vagrant_runner.rb +44 -0
  57. data/lib/pennyworth/version.rb +22 -0
  58. data/lib/pennyworth/vm.rb +62 -0
  59. data/man/.gitignore +2 -0
  60. data/man/pennyworth.1.md +28 -0
  61. data/pennyworth.gemspec +57 -0
  62. data/prophet/Gemfile +3 -0
  63. data/prophet/prophet.rb +82 -0
  64. data/spec/base_command_spec.rb +30 -0
  65. data/spec/build_base_command_spec.rb +147 -0
  66. data/spec/cli_host_controller_spec.rb +113 -0
  67. data/spec/data/hosts.yaml +10 -0
  68. data/spec/data/kiwi/base_opensuse12.3_kvm.box +1 -0
  69. data/spec/data/kiwi/base_opensuse13.1_kvm.box +1 -0
  70. data/spec/data/kiwi/definitions/base_opensuse12.3_kvm/config.sh +1 -0
  71. data/spec/data/kiwi/definitions/base_opensuse12.3_kvm/config.xml +1 -0
  72. data/spec/data/kiwi/definitions/base_opensuse12.3_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
  73. data/spec/data/kiwi/definitions/base_opensuse13.1_kvm/config.sh +1 -0
  74. data/spec/data/kiwi/definitions/base_opensuse13.1_kvm/config.xml +1 -0
  75. data/spec/data/kiwi/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
  76. data/spec/data/kiwi2/box_state.yaml +14 -0
  77. data/spec/data/kiwi2/definitions/base_opensuse12.3_kvm/config.sh +1 -0
  78. data/spec/data/kiwi2/definitions/base_opensuse12.3_kvm/config.xml +1 -0
  79. data/spec/data/kiwi2/definitions/base_opensuse12.3_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
  80. data/spec/data/kiwi2/definitions/base_opensuse13.1_kvm/config.sh +1 -0
  81. data/spec/data/kiwi2/definitions/base_opensuse13.1_kvm/config.xml +1 -0
  82. data/spec/data/kiwi2/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
  83. data/spec/data/kiwi3/box_state.yaml +13 -0
  84. data/spec/data/kiwi3/definitions/base_opensuse12.3_kvm/.gitkeep +0 -0
  85. data/spec/data/kiwi3/definitions/base_opensuse13.1_kvm/.gitkeep +0 -0
  86. data/spec/data/kiwi3/import_state.yaml +3 -0
  87. data/spec/data/kiwi4/definitions/base_opensuse12.3_kvm/.gitkeep +0 -0
  88. data/spec/data/kiwi4/definitions/base_opensuse13.1_kvm/.gitkeep +0 -0
  89. data/spec/data/kiwi4/import_state.yaml +3 -0
  90. data/spec/data/kiwi5/import_state.yaml +3 -0
  91. data/spec/data/vagrant/.gitkeep +0 -0
  92. data/spec/host_config_spec.rb +197 -0
  93. data/spec/host_runner_spec.rb +112 -0
  94. data/spec/image_runner_spec.rb +62 -0
  95. data/spec/import_base_command_spec.rb +189 -0
  96. data/spec/local_command_runner_spec.rb +117 -0
  97. data/spec/local_runner_spec.rb +42 -0
  98. data/spec/lock_service_spec.rb +95 -0
  99. data/spec/remote_command_runner_spec.rb +115 -0
  100. data/spec/settings_spec.rb +26 -0
  101. data/spec/setup_command_spec.rb +49 -0
  102. data/spec/spec_helper.rb +50 -0
  103. data/spec/spec_profiler_spec.rb +63 -0
  104. data/spec/spec_spec.rb +99 -0
  105. data/spec/support/command_runner_examples.rb +29 -0
  106. data/spec/support/runner_examples.rb +34 -0
  107. data/spec/urls_spec.rb +46 -0
  108. data/spec/vagrant_command_spec.rb +51 -0
  109. data/spec/vagrant_runner_spec.rb +40 -0
  110. data/spec/vagrant_spec.rb +288 -0
  111. data/spec/vm_spec.rb +56 -0
  112. metadata +257 -0
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ module Pennyworth
19
+ class LocalRunner < Runner
20
+ def initialize(opts = {})
21
+ @command_runner = LocalCommandRunner.new(opts)
22
+ end
23
+
24
+ def start
25
+ # Nothing to do here
26
+
27
+ "127.0.0.1"
28
+ end
29
+
30
+ def stop
31
+ # Nothing to do here either
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright (c) 2015 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ module Pennyworth
19
+ class LockService
20
+ attr_reader :lock_server_host
21
+ attr_reader :lock_server_port
22
+
23
+ def initialize(lock_server_address)
24
+ fields = lock_server_address.split(":")
25
+ @lock_server_host = fields[0]
26
+ @lock_server_port = fields[1]
27
+ @sockets = {}
28
+ end
29
+
30
+ def socket(lock_name)
31
+ if !@sockets.has_key?(lock_name)
32
+ @sockets[lock_name] = TCPSocket.new(@lock_server_host, @lock_server_port)
33
+ end
34
+ @sockets[lock_name]
35
+ end
36
+
37
+ def request_lock(lock_name)
38
+ socket(lock_name).puts("g #{lock_name}")
39
+ response = socket(lock_name).gets
40
+ if response =~ /^1/
41
+ return true
42
+ elsif response =~ /^0/
43
+ return false
44
+ else
45
+ raise LockError.new("Error, received: #{response}")
46
+ end
47
+ end
48
+
49
+ def keep_lock
50
+ # Sleep forever to keep process running to keep TCP connection to lock
51
+ # server open. When the process is ended the connection is closed and the
52
+ # lock is released. Users can end the process and release the lock with
53
+ # Ctrl-C.
54
+ sleep
55
+ end
56
+
57
+ def release_lock(lock_name)
58
+ if !@sockets[lock_name]
59
+ raise LockError.new("Lock '#{lock_name}' doesn't exist")
60
+ end
61
+ @sockets[lock_name].close
62
+ @sockets.delete(lock_name)
63
+ end
64
+
65
+ def locked?(lock_name)
66
+ socket(lock_name).puts("i #{lock_name}")
67
+ response = socket(lock_name).gets
68
+ if response =~ /^1/
69
+ return true
70
+ else
71
+ return false
72
+ end
73
+ end
74
+
75
+ def info(lock_name)
76
+ if locked?(lock_name)
77
+ socket(lock_name).puts("d #{lock_name}")
78
+ response = socket(lock_name).gets
79
+ response =~ /^#{lock_name}: (.*):/
80
+ client = $1
81
+ return "'#{lock_name}' is locked by #{client}"
82
+ else
83
+ return "'#{lock_name}' is not locked"
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,144 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ # The purpose of this class is to execute commands on a remote machine via SSH.
19
+ module Pennyworth
20
+ class RemoteCommandRunner
21
+ def initialize(ip, username)
22
+ @ip = ip
23
+ @username = username
24
+ end
25
+
26
+ def run(*args)
27
+ # When ssh executes commands, it passes them through shell expansion.
28
+ # For example, compare
29
+ #
30
+ # $ echo '$HOME'
31
+ # $HOME
32
+ #
33
+ # with
34
+ #
35
+ # $ ssh localhost echo '$HOME'
36
+ # /home/dmajda
37
+ #
38
+ # To mitigate that and maintain usual Cheetah semantics, we need to
39
+ # protect the command and its arguments using another layer of escaping.
40
+ options = args.last.is_a?(Hash) ? args.pop : {}
41
+ args.map! { |a| Shellwords.escape(a) } if !options[:skip_escape]
42
+
43
+ if user = options.delete(:as)
44
+ args = ["su", "-l", user, "-c"] + args
45
+ end
46
+
47
+ Cheetah.run(
48
+ "ssh",
49
+ "-o",
50
+ "UserKnownHostsFile=/dev/null",
51
+ "-o",
52
+ "StrictHostKeyChecking=no",
53
+ "#{@username}@#{@ip}",
54
+ "LC_ALL=C",
55
+ *args,
56
+ options
57
+ )
58
+ rescue Cheetah::ExecutionFailed => e
59
+ raise ExecutionFailed.new(e)
60
+ end
61
+
62
+ # Copy a local file to the remote system.
63
+ #
64
+ # +source+:: Path to the local file
65
+ # +destination+:: Path to the remote file or directory. If +destination+ is a
66
+ # path, the same filename as +source+ will be used.
67
+ # +opts+:: Options to modify the attributes of the remote file.
68
+ #
69
+ # Available options:
70
+ # [owner]:: Owner of the file, e.g. "tux"
71
+ # [group]:: Group of the file, e.g. "users"
72
+ # [mode]:: Mode of the file, e.g. "600"
73
+ def inject_file(source, destination, opts = {})
74
+ # Append filename (taken from +source+) to destination if it is a path, so
75
+ # that +destination+ is always the full target path including the filename.
76
+ destination += File.basename(source) if destination.end_with?("/")
77
+
78
+ Cheetah.run(
79
+ "scp",
80
+ "-o",
81
+ "UserKnownHostsFile=/dev/null",
82
+ "-o",
83
+ "StrictHostKeyChecking=no",
84
+ source,
85
+ "#{@username}@#{@ip}:#{destination}"
86
+ )
87
+
88
+ if opts[:owner] || opts[:group]
89
+ owner_group = opts[:owner] || ""
90
+ owner_group += ":#{opts[:group]}" if opts[:group]
91
+ run "chown", "-R", owner_group, destination
92
+ end
93
+
94
+ if opts[:mode]
95
+ run "chmod", opts[:mode], destination
96
+ end
97
+ rescue Cheetah::ExecutionFailed => e
98
+ raise ExecutionFailed.new(e)
99
+ end
100
+
101
+ def extract_file(source, destination)
102
+ Cheetah.run(
103
+ "scp",
104
+ "-o",
105
+ "UserKnownHostsFile=/dev/null",
106
+ "-o",
107
+ "StrictHostKeyChecking=no",
108
+ "#{@username}@#{@ip}:#{source}",
109
+ destination
110
+ )
111
+ rescue Cheetah::ExecutionFailed => e
112
+ raise ExecutionFailed.new(e)
113
+ end
114
+
115
+ def inject_directory(source, destination, opts = {})
116
+ if opts[:owner] || opts[:group]
117
+ owner_group = opts[:owner] || ""
118
+ owner_group += ":#{opts[:group]}" if opts[:group]
119
+ end
120
+
121
+ chown_cmd = " && chown #{owner_group} '#{destination}'" if owner_group
122
+ mkdir_cmd = "test -d '#{destination}' || (mkdir -p '#{destination}' #{chown_cmd} )"
123
+
124
+ run mkdir_cmd, skip_escape: true
125
+
126
+ Cheetah.run(
127
+ "scp",
128
+ "-r",
129
+ "-o",
130
+ "UserKnownHostsFile=/dev/null",
131
+ "-o",
132
+ "StrictHostKeyChecking=no",
133
+ source,
134
+ "#{@username}@#{@ip}:#{destination}"
135
+ )
136
+
137
+ if owner_group
138
+ run "chown", "-R", owner_group, File.join(destination, File.basename(source))
139
+ end
140
+ rescue Cheetah::ExecutionFailed => e
141
+ raise ExecutionFailed.new(e)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ module Pennyworth
19
+ # Base class for the runner classes
20
+ class Runner
21
+ attr_reader :command_runner
22
+
23
+ def cleanup_directory(dir)
24
+ command_runner.run("test -d #{dir} && rm -r #{dir}")
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ module Pennyworth
19
+ class Settings
20
+
21
+ attr_accessor :verbose, :silent, :definitions_dir
22
+
23
+ def initialize
24
+ @verbose = false
25
+ @silent = false
26
+ @definitions_dir = File.expand_path("~/.pennyworth")
27
+ end
28
+
29
+ def kiwi_dir
30
+ File.join(@definitions_dir, "/kiwi")
31
+ end
32
+
33
+ def vagrant_dir
34
+ File.join(@definitions_dir, "/vagrant")
35
+ end
36
+
37
+ def version
38
+ Pennyworth::VERSION
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,96 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ require "cheetah"
19
+ require "libvirt"
20
+ require "socket"
21
+ require "open-uri"
22
+ require "yaml"
23
+
24
+ require_relative "exceptions"
25
+ require_relative "helper"
26
+ require_relative "libvirt"
27
+ require_relative "runner"
28
+ require_relative "vagrant"
29
+ require_relative "vagrant_runner"
30
+ require_relative "image_runner"
31
+ require_relative "host_config"
32
+ require_relative "host_runner"
33
+ require_relative "lock_service"
34
+ require_relative "ssh_keys_importer"
35
+ require_relative "vm"
36
+ require_relative "spec_profiler"
37
+ require_relative "remote_command_runner"
38
+ require_relative "settings"
39
+ require_relative "local_runner"
40
+ require_relative "local_command_runner"
41
+
42
+ module Pennyworth
43
+ module SpecHelper
44
+ def start_system(opts)
45
+ opts = {
46
+ skip_ssh_setup: false
47
+ }.merge(opts)
48
+ username = opts[:username] || "root"
49
+ if opts[:box]
50
+ runner = VagrantRunner.new(opts[:box], RSpec.configuration.vagrant_dir, username)
51
+ password = opts[:password] || "vagrant"
52
+ elsif opts[:image]
53
+ runner = ImageRunner.new(opts[:image], username)
54
+ password = opts[:password] || "linux"
55
+ elsif opts[:host]
56
+ config = HostConfig.new(RSpec.configuration.hosts_file)
57
+ config.read
58
+ runner = HostRunner.new(opts[:host], config, username)
59
+ elsif opts[:local]
60
+ runner = LocalRunner.new(env: opts[:env])
61
+ end
62
+
63
+ raise "No image specified." unless runner
64
+
65
+ system = VM.new(runner)
66
+
67
+ # Make sure to stop the machine again when the example group is done
68
+ self.class.after(:all) do
69
+ system.stop
70
+ end
71
+
72
+ measure("Boot machine '#{opts[:box] || opts[:image] || opts[:host]}'") do
73
+ system.start
74
+ end
75
+ if !opts[:skip_ssh_setup] && !opts[:host] && !opts[:local]
76
+ SshKeysImporter.import(system.ip, username, password)
77
+ end
78
+
79
+ system
80
+ end
81
+ end
82
+ end
83
+
84
+ RSpec.configure do |config|
85
+ defaults = Pennyworth::Settings.new
86
+ config.include(Pennyworth::SpecHelper)
87
+ config.add_setting :pennyworth_mode, default: false
88
+ config.add_setting :vagrant_dir, default: defaults.vagrant_dir
89
+ config.add_setting :hosts_file, default: File.join(defaults.definitions_dir, "/hosts.yaml")
90
+
91
+ config.before(:all) do
92
+ unless RSpec.configuration.pennyworth_mode
93
+ Pennyworth::Libvirt.ensure_libvirt_env_started
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,85 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ require "benchmark"
19
+
20
+ def measure(label, &block)
21
+ own_parent = @parent_measurement
22
+ measurement = {
23
+ label: label,
24
+ child_measurements: []
25
+ }
26
+
27
+ @parent_measurement = measurement
28
+ time = Benchmark.measure do
29
+ block.call
30
+ end
31
+ @parent_measurement = own_parent
32
+ measurement.merge!(time: time.real)
33
+
34
+ # Calculate time that was not spent in the measured child blocks but somewhere
35
+ # else
36
+ if !measurement[:child_measurements].empty?
37
+ other_time = measurement[:time]
38
+ measurement[:child_measurements].each do |child|
39
+ other_time -= child[:time]
40
+ end
41
+ measurement[:child_measurements] << { label: "Other", time: other_time }
42
+ end
43
+
44
+ if own_parent
45
+ own_parent[:child_measurements] << measurement
46
+ else
47
+ @measurements << measurement
48
+ end
49
+ end
50
+
51
+ def print_measurement(measurement, indent = 0)
52
+ name = measurement[:label][0..65-indent].ljust(70-indent)
53
+ STDERR.puts (" " * indent) + "#{name}: #{measurement[:time]}"
54
+
55
+ if measurement[:child_measurements]
56
+ measurement[:child_measurements].each do |child|
57
+ print_measurement(child, indent + 2)
58
+ end
59
+ end
60
+ end
61
+
62
+ RSpec.configure do |config|
63
+ config.before(:all) do
64
+ @measurements = []
65
+ end
66
+
67
+ config.around(:each) do |example|
68
+ if RSpec.configuration.pennyworth_mode
69
+ example.run
70
+ else
71
+ measure(example.metadata[:full_description]) do
72
+ example.run
73
+ end
74
+ end
75
+ end
76
+
77
+ config.after(:all) do
78
+ if !RSpec.configuration.pennyworth_mode
79
+ @measurements.each do |measurement|
80
+ print_measurement(measurement)
81
+ end
82
+ end
83
+ end
84
+ end
85
+