brpm_content_framework 0.1.55

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 (77) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +38 -0
  3. data/.travis.yml +17 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +21 -0
  6. data/README.md +308 -0
  7. data/Rakefile +23 -0
  8. data/TO_BE_MIGRATED.txt +9 -0
  9. data/architecture.png +0 -0
  10. data/automations/direct_execute.meta +10 -0
  11. data/automations/direct_execute.rb +10 -0
  12. data/automations/install_module.meta +10 -0
  13. data/automations/install_module.rb +13 -0
  14. data/bin/brpm_install +30 -0
  15. data/bin/brpm_uninstall +30 -0
  16. data/bin/event_handler +63 -0
  17. data/bin/webhook_receiver +49 -0
  18. data/brpm_content.gemspec +31 -0
  19. data/config.yml +8 -0
  20. data/infrastructure/.bashrc +6 -0
  21. data/infrastructure/.brpm +2 -0
  22. data/infrastructure/config/customer_include.rb +26 -0
  23. data/infrastructure/config/server.yml +3 -0
  24. data/infrastructure/log.html +39 -0
  25. data/infrastructure/scripts/backup_database.sh +19 -0
  26. data/infrastructure/scripts/ddns.sh +10 -0
  27. data/infrastructure/scripts/install_brpm.sh +63 -0
  28. data/infrastructure/scripts/maintenance.sh +4 -0
  29. data/infrastructure/scripts/patch_brpm.sh +90 -0
  30. data/infrastructure/scripts/restore_database.sh +33 -0
  31. data/infrastructure/scripts/run_event_handler.cmd +19 -0
  32. data/infrastructure/scripts/run_event_handler.sh +20 -0
  33. data/infrastructure/scripts/run_webhook_receiver.cmd +15 -0
  34. data/infrastructure/scripts/run_webhook_receiver.sh +15 -0
  35. data/infrastructure/silent_install_options_4.6.txt +93 -0
  36. data/infrastructure/silent_install_options_upgrade_4.6.txt +92 -0
  37. data/infrastructure/smtp_settings.rb +42 -0
  38. data/lib/brpm_auto.rb +358 -0
  39. data/lib/brpm_script_executor.rb +80 -0
  40. data/lib/logging/brpm_logger.rb +39 -0
  41. data/lib/logging/logger_base.rb +36 -0
  42. data/lib/logging/simple_logger.rb +27 -0
  43. data/lib/module_installer.rb +483 -0
  44. data/lib/params/all_params.rb +80 -0
  45. data/lib/params/integration_settings.rb +27 -0
  46. data/lib/params/params.rb +174 -0
  47. data/lib/params/params_base.rb +81 -0
  48. data/lib/params/request_params.rb +38 -0
  49. data/lib/rest_api.rb +155 -0
  50. data/lib/semaphore.rb +79 -0
  51. data/lib/utilities.rb +317 -0
  52. data/lib/version_control/git.rb +192 -0
  53. data/lib/version_control/svn.rb +221 -0
  54. data/lib/write_to.rb +1 -0
  55. data/tests/all_params_spec.rb +116 -0
  56. data/tests/brpm_auto_spec.rb +84 -0
  57. data/tests/customer_include/config/customer_include.rb +10 -0
  58. data/tests/customer_include/config/server.yml +3 -0
  59. data/tests/customer_include_spec.rb +29 -0
  60. data/tests/gemspec_spec.rb +11 -0
  61. data/tests/module_installer_spec.rb +46 -0
  62. data/tests/params_spec.rb +172 -0
  63. data/tests/request_params_spec.rb +86 -0
  64. data/tests/server_yaml_spec.rb +19 -0
  65. data/tests/spec_helper.rb +64 -0
  66. data/to_be_migrated/brpm_framework.rb +88 -0
  67. data/to_be_migrated/customer_include_default.rb +25 -0
  68. data/to_be_migrated/local_jirb.rb +15 -0
  69. data/to_be_migrated/resource_framework.rb +211 -0
  70. data/transport/dispatch_baa.rb +355 -0
  71. data/transport/dispatch_base.rb +345 -0
  72. data/transport/dispatch_nsh.rb +248 -0
  73. data/transport/dispatch_ssh.rb +154 -0
  74. data/transport/transport_baa.rb +1095 -0
  75. data/transport/transport_nsh.rb +359 -0
  76. data/transport/transport_ssh.rb +220 -0
  77. metadata +204 -0
@@ -0,0 +1,221 @@
1
+ require 'uri'
2
+
3
+ # Base class for working with Subversion
4
+ class Svn
5
+
6
+ # Initializes an instance of the class
7
+ #
8
+ # ==== Attributes
9
+ #
10
+ # * +svn+ - path to the svn executable
11
+ # * +params+ - params hash
12
+ # * +options+ - hash of options includes:...
13
+ # url - url for svn repository...
14
+ # base_path - path for the local repository...
15
+ # username - repository user username...
16
+ # password - repository user password...
17
+ # verbose - true for verbose output (default = false)...
18
+ # rebase - starting path for checkouts...
19
+ # simulate - simulate command - echo it (default = false)...
20
+ # prerun_lines - pass any text to run before svn (such as env variables)...
21
+ # command_options - options to pass on command line e.g. --non-interactive
22
+ #
23
+ def initialize(svn, params, options)
24
+ self.extend Utilities
25
+ @url = required_option(options,"url")
26
+ @base_path = required_option(options,"base_path")
27
+ user = get_option(options,"username")
28
+ @password = get_option(options,"password")
29
+ @verbose = get_option(options,"verbose", false)
30
+ @prerun = get_option(options, "prerun_lines")
31
+ @command_options = get_option(options, "command_options")
32
+ @command_options += " --non-interactive" unless @command_options.include?("non-interactive")
33
+ @rebase = get_option(options, "rebase")
34
+ @rebase = @url.split("/")[-1] if @rebase == ""
35
+ @simulate = get_option(options,"simulate", false)
36
+ make_credential(user, @password)
37
+ @svn = svn
38
+ end
39
+
40
+ # Parses a complex svn uri into parts
41
+ #
42
+ # ==== Attributes
43
+ #
44
+ # * +svn_url+ - svn url, like this:...
45
+ # https://user:password@host:port/path/path[#revision]...
46
+ # https://user:password@svn.nam.nsroot.net:9050/svn/16667/appreldep/RLM/artifacts/CATE[7777777]
47
+ # * +reset_values+ - resets the svn object parameters host, password etc from url (default=false)
48
+ #
49
+ # ==== Returns
50
+ #
51
+ # * parse result, like this:...
52
+ # {"uri_result" => URIGemResult, "revision" => ""}
53
+ def parse_uri(svn_uri, reset_values = false)
54
+ result = {"uri_result" => nil, "revision" => ""}
55
+ k = svn_uri.scan(/\[.*\]/)
56
+ result["revision"] = k[0].gsub("[","").gsub("]","") if k.size > 0
57
+ rev = k.size > 0 ? "[#{result["revision"]}]" : "__ZZZ__"
58
+ parts = URI.parse(svn_uri.gsub(rev,""))
59
+ result["uri_result"] = parts
60
+ if reset_values
61
+ @url = "#{parts.scheme}://#{parts.host}:#{parts.port}#{parts.path}"
62
+ make_credential(parts.user, parts.password) unless parts.password.nil?
63
+ end
64
+ result
65
+ end
66
+
67
+ # Performs an svn checkout
68
+ #
69
+ # ==== Attributes
70
+ #
71
+ # * +init+ - true to initilize the checkout and local repo
72
+ # ==== Returns
73
+ #
74
+ # * command output
75
+ def checkout(init = false)
76
+ FileUtils.cd(@base_path, :verbose => true)
77
+ if init
78
+ cmd = "#{@svn} checkout #{@url} #{@rebase} #{@credential} #{@command_options}"
79
+ else
80
+ cmd = "#{@svn} checkout #{@command_options}"
81
+ end
82
+ process_cmd(cmd)
83
+ end
84
+
85
+ # Performs an svn export
86
+ #
87
+ # ==== Attributes
88
+ #
89
+ # * +revision+ - revision to export (options - defaults to latest)
90
+ # ==== Returns
91
+ #
92
+ # * command output
93
+ def export(target = "", revision = "")
94
+ url_items = URI.parse(@url)
95
+ target = url_items.path if target == ""
96
+ cmd_options = @command_options
97
+ cmd_options += " --no-auth-cache --trust-server-cert --force" if cmd_options == " --non-interactive"
98
+ base_cmd = "#{@svn} export #{@credential} #{@command_options} #{@url}"
99
+ FileUtils.cd(@base_path, :verbose => true)
100
+ if revision == ""
101
+ cmd = "#{base_cmd} ."
102
+ else
103
+ cmd = "#{base_cmd} -r #{revision} ."
104
+ end
105
+ process_cmd(cmd)
106
+ end
107
+
108
+ # Performs an svn checkout
109
+ #
110
+ # ==== Returns
111
+ #
112
+ # * command output
113
+ def get
114
+ cmd = "#{@svn} checkout --non-interactive"
115
+ process_cmd(cmd)
116
+ end
117
+
118
+ # Performs an svn commit
119
+ #
120
+ # ==== Attributes
121
+ #
122
+ # * +message+ - commit string
123
+ # ==== Returns
124
+ #
125
+ # * command output
126
+ def commit(message = "Automation pushed changes")
127
+ # /usr/bin/svn commit . -m "PSENG-0000 Adding PSENG files"
128
+ cmd = "#{@svn} commit . -m \"#{message}\""
129
+ process_cmd(cmd)
130
+ end
131
+
132
+ # Performs an svn tag
133
+ #
134
+ # ==== Attributes
135
+ #
136
+ # * +source_path+ - path in repo to tag
137
+ # * +tag_name+ - name for tag
138
+ # * +message+ - message to add to tag
139
+ #
140
+ # ==== Returns
141
+ #
142
+ # * command output
143
+ def tag(source_path, tag_name, message)
144
+ ipos = @url.index("trunk")
145
+ raise "Cannot locate trunk path" if ipos.nil?
146
+ tag_path = @url[0..ipos] + "tags/" + tag_name
147
+ cmd = "#{@svn} copy #{source_path} #{tag_path} -m \"#{message}\""
148
+ process_cmd(cmd)
149
+ end
150
+
151
+ # Performs an svn status
152
+ #
153
+ # ==== Returns
154
+ #
155
+ # * command output
156
+ def status
157
+ process_cmd("#{@svn} status")
158
+ end
159
+
160
+ # Adds any new files in the local repo to the svn commit list
161
+ #
162
+ # ==== Attributes
163
+ #
164
+ # * +exclude_regex+ - regex to filter add files (file !=~ filter)
165
+ #
166
+ # ==== Returns
167
+ #
168
+ # * command output
169
+ def add_files(options = {})
170
+ result = status
171
+ msg = ""
172
+ exclude = get_option(options,"exclude_regex")
173
+ result.split("\n").each do |item|
174
+ if item.start_with?("?")
175
+ file = item.gsub("?","").strip
176
+ cmd = "#{@svn} add #{file}"
177
+ if exclude == ""
178
+ msg += process_cmd(cmd)
179
+ else
180
+ msg += process_cmd(cmd) if file =~ /#{exclude}/
181
+ end
182
+ res = `#{cmd}`
183
+ end
184
+ end
185
+ "#{result}\n#{msg}"
186
+ end
187
+
188
+ private
189
+
190
+ def process_cmd(cmd)
191
+ goto_base
192
+ cmd = "#{@prerun} && #{cmd}" unless @prerun == ""
193
+ res = execute_shell(cmd) unless @simulate
194
+ BrpmAuto.log cmd.gsub(@password,"-private-") if @verbose || @simulate
195
+ @simulate ? "ok" : display_result(res)
196
+ end
197
+
198
+ def goto_base
199
+ @pwd = FileUtils.pwd
200
+ goto_path = @base_path #@rebase != "" ? File.join(@base_path,@rebase) : @base_path
201
+ FileUtils.cd(goto_path, :verbose => true) if @verbose
202
+ FileUtils.cd(goto_path) unless @verbose
203
+ end
204
+
205
+ def svn_errors?(output)
206
+ svn_terms = ["403 Forbidden", "SSL error code", "moorrreee"]
207
+ found = output.scan(/#{svn_terms.join("|")}/)
208
+ found.size > 0
209
+ end
210
+
211
+ def make_credential(user, password)
212
+ if user.to_s != "" && password.to_s != ""
213
+ @credential = " --username #{user} --password #{password}"
214
+ else
215
+ @credential = ""
216
+ end
217
+ end
218
+
219
+ end
220
+
221
+
data/lib/write_to.rb ADDED
@@ -0,0 +1 @@
1
+ write_to(File.read(BrpmAuto.logger.step_run_log_file_path)) unless BrpmAuto.logger.nil?
@@ -0,0 +1,116 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe 'All params' do
4
+ before(:each) do
5
+ cleanup_request_params
6
+ end
7
+
8
+ it 'should get a param from the param store' do
9
+ input_params = get_default_params
10
+ input_params["key1"] = "value1"
11
+
12
+ BrpmAuto.setup(input_params)
13
+ all_params = BrpmAuto.all_params
14
+
15
+ expect(all_params).to have_key("key1")
16
+ expect(all_params["key1"]).to eql("value1")
17
+ end
18
+
19
+ it 'should get a param from the request_param store' do
20
+ input_params = get_default_params
21
+ input_params["key1"] = "value1"
22
+
23
+ BrpmAuto.setup(input_params)
24
+ all_params = BrpmAuto.all_params
25
+
26
+ expect(all_params).to have_key("key1")
27
+ expect(all_params["key1"]).to eql("value1")
28
+ end
29
+
30
+ it 'should get a param by the get method' do
31
+ input_params = get_default_params
32
+ input_params["key1"] = "value1"
33
+
34
+ BrpmAuto.setup(input_params)
35
+ all_params = BrpmAuto.all_params
36
+
37
+ expect(all_params).to have_key("key1")
38
+ expect(all_params.get("key1")).to eql("value1")
39
+ end
40
+
41
+ it 'should raise an error when trying to add a param using []=' do
42
+ BrpmAuto.setup(get_default_params)
43
+ all_params = BrpmAuto.all_params
44
+
45
+ expect{ all_params["key1"] = "value1" }.to raise_exception(RuntimeError)
46
+ end
47
+
48
+ it 'should add a param by the add method to the params store' do
49
+ input_params = get_default_params
50
+
51
+ BrpmAuto.setup(input_params)
52
+ all_params = BrpmAuto.all_params
53
+
54
+ all_params.add("key1", "value1", "params")
55
+
56
+ expect(all_params).to have_key("key1")
57
+ expect(all_params["key1"]).to eql("value1")
58
+ expect(all_params.count).to eql(get_default_params.count + 1)
59
+
60
+ expect(BrpmAuto.params.count).to eql(all_params.count)
61
+
62
+ request_params = get_request_params
63
+ expect(request_params.count).to eql(0)
64
+ end
65
+
66
+ it 'should add a param by the add method to the request_param store' do
67
+ input_params = get_default_params
68
+ BrpmAuto.setup(input_params)
69
+ all_params = BrpmAuto.all_params
70
+
71
+ all_params.add("key1", "value1", "json")
72
+
73
+ expect(all_params).to have_key("key1")
74
+ expect(all_params["key1"]).to eql("value1")
75
+ expect(all_params.count).to eql(input_params.count + 1)
76
+
77
+ expect(BrpmAuto.params.count).to eql(all_params.count - 1)
78
+
79
+ request_params = get_request_params
80
+ expect(request_params.count).to eql(1)
81
+ end
82
+
83
+ it 'should find or add a param to the params store' do
84
+ input_params = get_default_params
85
+ input_params["key1"] = "value1"
86
+
87
+ BrpmAuto.setup(input_params)
88
+ all_params = BrpmAuto.all_params
89
+
90
+ expect(all_params.find_or_add("key1", "value1-bis", "params")).to eql("value1")
91
+ expect(all_params.count).to eql(input_params.count)
92
+
93
+ expect(all_params.find_or_add("key2", "value2", "params")).to eql("value2")
94
+ expect(all_params.count).to eql(input_params.count + 1)
95
+ expect(all_params["key2"]).to eql("value2")
96
+ end
97
+
98
+ it 'should find or add a param to the request_params store' do
99
+ input_request_params = {}
100
+ input_request_params["key1"] = "value1"
101
+ set_request_params(input_request_params)
102
+
103
+ input_params = get_default_params
104
+ BrpmAuto.setup(input_params)
105
+ all_params = BrpmAuto.all_params
106
+
107
+ expect(all_params.find_or_add("key1", "value1-bis", "json")).to eql("value1")
108
+ expect(all_params.count).to eql(input_params.count + 1)
109
+
110
+ expect(all_params.find_or_add("key2", "value2", "json")).to eql("value2")
111
+ expect(all_params.count).to eql(input_params.count + 2)
112
+ expect(all_params["key2"]).to eql("value2")
113
+ end
114
+ end
115
+
116
+
@@ -0,0 +1,84 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe 'BRPM automation framework' do
4
+ before(:all) do
5
+ setup_brpm_auto
6
+ end
7
+
8
+ describe 'privatize' do
9
+ it 'should hide a sensitive string' do
10
+ result = BrpmAuto.privatize("The password should be replaced here: MySecret, and also here:MySecret! ", "MySecret")
11
+
12
+ expect(result).not_to include("MySecret")
13
+ expect(result).to include("The password should be replaced here: ")
14
+ expect(result).to include(", and also here:")
15
+ expect(result).to include("! ")
16
+ end
17
+
18
+ it 'should hide an array of sensitive strings' do
19
+ privatized_string = BrpmAuto.privatize("The password should be replaced here: MySecret, and also here:MyOtherSecret! ", [ "MySecret", "MyOtherSecret" ])
20
+
21
+ expect(privatized_string).not_to include("MySecret")
22
+ expect(privatized_string).not_to include("MyOtherSecret")
23
+ expect(privatized_string).to include("The password should be replaced here: ")
24
+ expect(privatized_string).to include(", and also here:")
25
+ expect(privatized_string).to include("! ")
26
+ end
27
+ end
28
+
29
+ describe 'substitute_tokens' do
30
+ it 'should replace a token' do
31
+ params = {}
32
+ params["application"] = "E-Finance"
33
+ result = BrpmAuto.substitute_tokens("The application is called rpm{application}", params)
34
+
35
+ expect(result).to eq("The application is called E-Finance")
36
+ end
37
+
38
+ it 'should replace a set of tokens' do
39
+ params = {}
40
+ params["application"] = "E-Finance"
41
+ params["component"] = "EF - java calculation engine"
42
+ params["component_version"] = "1.2.3"
43
+ result = BrpmAuto.substitute_tokens("The application is called rpm{application} and has component rpm{component} with version number rpm{component_version}", params)
44
+
45
+ expect(result).to eq("The application is called E-Finance and has component EF - java calculation engine with version number 1.2.3")
46
+ end
47
+
48
+ it 'should replace a set of nested tokens' do
49
+ params = {}
50
+ params["application"] = "E-Finance"
51
+ params["component"] = "EF - java calculation engine"
52
+ params["component_version"] = "1.2.rpm{component_version_revision}"
53
+ params["component_version_revision"] = "3"
54
+ result = BrpmAuto.substitute_tokens("The application is called rpm{application} and has component rpm{component} with version number rpm{component_version}", params)
55
+
56
+ expect(result).to eq("The application is called E-Finance and has component EF - java calculation engine with version number 1.2.3")
57
+ end
58
+ end
59
+
60
+ describe 'dos_path' do
61
+ it 'should convert a path from the UNIX to the Windows format' do
62
+ result = BrpmAuto.dos_path("C/windows/path")
63
+
64
+ expect(result).to eq("C:\\windows\\path")
65
+ end
66
+ end
67
+
68
+ describe 'execute_shell' do
69
+ it 'should execute a command successfully' do
70
+ result = BrpmAuto.execute_shell("echo Hello")
71
+
72
+ expect(result["status"]).to eql(0)
73
+ expect(result["stdout"]).to eql("Hello\n")
74
+ end
75
+
76
+ it 'should return with a non-zero status when passing a bad command' do
77
+ result = BrpmAuto.execute_shell("xxxx")
78
+
79
+ expect(result["status"]).not_to eql(0)
80
+ end
81
+ end
82
+ end
83
+
84
+
@@ -0,0 +1,10 @@
1
+ def get_customer_include_params
2
+ params = {}
3
+ params["key1"] = "value1"
4
+
5
+ params
6
+ end
7
+
8
+ def my_custom_method(a, b)
9
+ a + b
10
+ end
@@ -0,0 +1,3 @@
1
+ # This file should be located in BRPM_HOME/config
2
+ # See the README for more information on how to use this file
3
+ key2: "value2"
@@ -0,0 +1,29 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe 'Customer include' do
4
+ before(:each) do
5
+ cleanup_request_params
6
+ end
7
+
8
+ it 'should get the parameters' do
9
+ input_params = get_default_params
10
+ input_params["home_dir"] = "#{File.dirname(__FILE__)}/customer_include"
11
+
12
+ BrpmAuto.setup(input_params)
13
+
14
+ params = BrpmAuto.params
15
+
16
+ expect(params).to have_key("key1")
17
+ expect(params["key1"]).to eql("value1")
18
+ end
19
+
20
+ it 'should execute a custom method' do
21
+ input_params = get_default_params
22
+ input_params["home_dir"] = "#{File.dirname(__FILE__)}/customer_include"
23
+
24
+ BrpmAuto.setup(input_params)
25
+
26
+ expect(defined?(my_custom_method)).to eql("method")
27
+ expect(my_custom_method("a", "b")).to eql("ab")
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe 'Gemspec' do
4
+ it 'should have the right license' do
5
+ config = YAML.load_file(File.expand_path("#{File.dirname(__FILE__)}/../config.yml"))
6
+
7
+ expect(config).to have_key("license")
8
+ expect(config["license"].downcase).not_to include("gpl")
9
+ expect(config["license"].downcase).not_to include("gnu")
10
+ end
11
+ end
@@ -0,0 +1,46 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe 'Module installer' do
4
+ before(:all) do
5
+ raise "Module installation tests don't work under Bundler." if ENV["RUBYOPT"] and ENV["RUBYOPT"].include?("-rbundler/setup")
6
+
7
+ setup_brpm_auto
8
+
9
+ BrpmAuto.log "Creating ~/.brpm file..."
10
+ create_brpm_file
11
+ end
12
+
13
+ before(:each) do
14
+ module_installer = ModuleInstaller.new
15
+
16
+ brpm_specs = Gem::Specification.find_all_by_name("brpm_module_bladelogic")
17
+
18
+ brpm_specs.each do |brpm_spec|
19
+ BrpmAuto.log "Module brpm_module_bladelogic (#{brpm_spec.version.to_s}) is already installed, uninstalling it..."
20
+ module_installer.uninstall_module("brpm_module_bladelogic", brpm_spec.version.to_s)
21
+ end
22
+ end
23
+
24
+ it 'should install the Bladelogic module from rubygems.org' do
25
+ module_installer = ModuleInstaller.new
26
+ module_installer.install_module("brpm_module_bladelogic")
27
+
28
+ expect{Gem::Specification.find_by_name("brpm_module_bladelogic")}.not_to raise_error #(Gem::LoadError)
29
+ end
30
+
31
+ it 'should install a specific version of the Bladelogic module from rubygems.org' do
32
+ module_installer = ModuleInstaller.new
33
+ module_installer.install_module("brpm_module_bladelogic", "0.1.21")
34
+
35
+ expect{Gem::Specification.find_by_name("brpm_module_bladelogic", Gem::Requirement.create(Gem::Version.new("0.1.21")))}.not_to raise_error #(Gem::LoadError)
36
+ end
37
+
38
+ it 'should install a Bladelogic module from a local gem file' do
39
+ `wget https://rubygems.org/downloads/brpm_module_bladelogic-0.1.21.gem` unless File.exists?("./brpm_module_bladelogic-0.1.21.gem")
40
+
41
+ module_installer = ModuleInstaller.new
42
+ module_installer.install_module("./brpm_module_bladelogic-0.1.21.gem")
43
+
44
+ expect{Gem::Specification.find_by_name("brpm_module_bladelogic", Gem::Requirement.create(Gem::Version.new("0.1.21")))}.not_to raise_error #(Gem::LoadError)
45
+ end
46
+ end