soaspec 0.0.77 → 0.0.78

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: 67969ede0a36306652d44ece28fb979980e81e72
4
- data.tar.gz: 6ca6c9d0887c36bcbb1683299308f349c2a70180
3
+ metadata.gz: 81af3fccf7fe08aef640bb651f3db64a35becdee
4
+ data.tar.gz: 4f3147e1f49580a340a698adf1531da764f21d58
5
5
  SHA512:
6
- metadata.gz: d31d9064daa746a272fb2cac0da67f5b797f86c3258b973136f7f55f2f91678fa3f23b3fbb038a6c57ab9d431c8a21643c02d6b0d12b53189b8735dcbb09b928
7
- data.tar.gz: 54a3005df87d30182c036ca6177818dac46b0eda51856b100aa611c5c4dde276beba4f8e010545c6d74757c316990d3f7f0ae1c31c51d6cf20e591a1779d2ad3
6
+ metadata.gz: '049af0af886c7087970fc9825afbbe1590a5088ce0cdcc60db865d1d8271578dba801c5603c50bdc1d44e38d920513612f0ccb724e30eca5551f4d19062dfb32'
7
+ data.tar.gz: a03feb257476d536b6cc03a4ce7c05939b90660d847dbae522f4d667be991596434c21f988361a28d94fee7f5f26afcda70b8759ab84c28cc48a44a703d1bfb2
data/.gitlab-ci.yml CHANGED
@@ -13,6 +13,11 @@ rspec:
13
13
  paths:
14
14
  - coverage/
15
15
 
16
+ exe_spec:
17
+ stage: test
18
+ script:
19
+ - bundle exec rake exe_spec
20
+
16
21
  cucumber:
17
22
  stage: test
18
23
  script:
data/ChangeLog CHANGED
@@ -1,3 +1,7 @@
1
+ Version 0.0.78
2
+ * Enhancements
3
+ * Use 'thor' for `soaspec generate`, allowing less prompt and more options through command line. Added tests for it
4
+
1
5
  Version 0.0.77
2
6
  * Enhancements
3
7
  * Use 'thor' for soaspec-init binary changing it to be `soaspec init`. Will update `soaspec-generate` in next version
data/Rakefile CHANGED
@@ -7,6 +7,11 @@ ENV['test'] ||= ''
7
7
 
8
8
  RSpec::Core::RakeTask.new(:run_spec) do |t|
9
9
  t.pattern = "spec/**/#{ENV['folder']}*/#{ENV['test']}*_spec.rb"
10
+ t.exclude_pattern = 'spec/exe/*_spec.rb'
11
+ end
12
+
13
+ RSpec::Core::RakeTask.new(exe_spec: %i[start_test_server]) do |t|
14
+ t.pattern = 'spec/exe/*_spec.rb'
10
15
  end
11
16
 
12
17
  desc 'Run tests'
data/exe/soaspec CHANGED
@@ -7,39 +7,117 @@ require 'savon'
7
7
  require 'soaspec'
8
8
 
9
9
  module Soaspec
10
+
10
11
  # Common executable for Soaspec
11
12
  class Exe < Thor
12
13
 
13
14
  include Soaspec::ExeHelpers
15
+ include Soaspec::WsdlGenerator
14
16
 
15
- desc 'soaspec [type]', 'Initialize soaspec repository'
16
- def init
17
- puts 'Creating files for soaspec'
17
+ long_desc <<-LONGDESC
18
+ `soaspec new` will generate the initial files and folders for starting a testing project using soaspec
19
+ \x5
20
+
21
+ `soaspec new soap` will create example files testing against a virtual SOAP service
22
+ \x5
18
23
 
19
- create_file(filename: 'Gemfile', content: gem_content)
20
- create_file(filename: 'Rakefile', content: rake_virtual_content)
21
- create_file(filename: 'README.md', content: readme_content)
24
+ `soaspec new rest` will create example files testing against a virtual REST service
25
+ LONGDESC
26
+ desc 'new [type]', 'Initialize soaspec repository'
27
+ option :ci, default: 'jenkins', banner: 'What Continuous Integration is used'
28
+ option :virtual, type: :boolean, default: true, banner: 'Whether to set things up for a virtual server'
29
+ def new(type = 'initial')
30
+ puts 'Creating files for soaspec'
31
+ @virtual = options[:virtual]
32
+ create_file(filename: 'Gemfile')
33
+ create_file(filename: 'Rakefile')
34
+ create_file(filename: '.rspec')
35
+ create_file(filename: '.travis.yml') if options[:ci] == 'travis'
36
+ create_file(filename: 'README.md')
22
37
  create_folder 'lib'
23
- create_file(filename: 'lib/blz_service.rb', content: weather_web_service)
24
- create_file filename: 'lib/shared_example.rb', content: shared_examples_content
38
+ if type == 'soap'
39
+ create_file filename: 'lib/blz_service.rb'
40
+ create_file filename: 'lib/shared_example.rb'
41
+ end
25
42
  create_folder 'config'
26
43
  create_folder 'config/data'
27
- create_file(filename: 'config/data/default.yml', content: default_yaml_content)
44
+ create_file(filename: 'config/data/default.yml')
28
45
  create_folder 'spec'
29
- create_folder 'spec/test_data'
30
- create_folder 'spec/test_data/wsdl'
31
- create_file(filename: 'spec/spec_helper.rb', content: spec_helper_content)
32
- create_file(filename: 'spec/soap_spec.rb', content: soap_spec_content)
33
- create_file(filename: 'spec/test_server.rb', content: test_server_content)
34
- create_file(filename: 'spec/test_data/wsdl/get_bank.wsdl', content: test_wsdl_content)
46
+ create_file(filename: 'spec/spec_helper.rb')
47
+ create_file(filename: 'spec/soap_spec.rb') if type == 'soap'
35
48
  create_folder 'template'
36
- create_file(filename: 'template/soap_template.xml', content: soap_template_content)
49
+ create_file(filename: 'template/soap_template.xml', erb: false) if type == 'soap'
37
50
  create_folder 'logs'
38
51
 
39
52
  puts "Run 'bundle install' to install necessary gems"
40
53
  puts "Run 'rake spec' to run the tests"
41
- puts "Note: Setup runs Sinatra for Test Service on port 4567 by default. Change Rakefile 'start_test_server' task to update this"
42
54
  end
55
+
56
+ desc 'generate', 'Generate initial test code from wsdl'
57
+ long_desc <<-LONGDESC
58
+ `soaspec generate wsdl=wsdl name=ServiceName ` will generate the initial files and folders to test each operation in a wsdl
59
+ \x5
60
+ Additionally the auth parameter can be used to use basic authentication to retrieve the WSDL.
61
+ To do use the following `soaspec generate --auth=basic`
62
+
63
+ LONGDESC
64
+ option :wsdl, required: true, aliases: :w
65
+ option :name, default: 'Service', aliases: :n
66
+ option :ci, default: 'jenkins', banner: 'What Continuous Integration is used'
67
+ option :auth
68
+ option :string_default, default: 'test string'
69
+ def generate
70
+ enter_auth_details if options[:auth] == 'basic'
71
+ @virtual = false
72
+ savon_options = { wsdl: options[:wsdl] }
73
+ savon_options[:basic_auth] = [@auth_name, @auth_password] if options[:auth] == 'basic'
74
+
75
+ @wsdl_doc = Savon.client(**savon_options).wsdl
76
+ @wsdl_schemas = @wsdl_doc.parser.schemas
77
+
78
+ create_file filename: 'Rakefile', ignore_if_present: true
79
+ create_file filename: 'Gemfile', ignore_if_present: true
80
+ create_file(filename: '.rspec')
81
+ create_file(filename: '.travis.yml') if options[:ci] == 'travis'
82
+ create_file filename: 'README.md', ignore_if_present: true
83
+ create_folder 'spec'
84
+ create_file filename: 'spec/spec_helper.rb', ignore_if_present: true
85
+
86
+ create_folder 'logs'
87
+ create_folder 'config'
88
+ create_folder 'config/data'
89
+ create_folder 'lib'
90
+ create_file filename: "lib/#{options[:name].snakecase}.rb", content: class_content
91
+
92
+ # Files according to WSDL
93
+ @wsdl_doc.operations.each do |operation, details|
94
+ puts "Creating files for operation: #{operation}"
95
+ @content = "default:\n"
96
+ @use_camel_case = false
97
+ puts 'Message params: ' + details.to_s
98
+ # From namespace identifier, find namespace, and for that find schemaLocation xsd and use that to build request
99
+ if details[:parameters]
100
+ details[:parameters].each do |element, details|
101
+ @use_camel_case = true if /[[:upper:]]/.match(element.to_s[0]) != nil
102
+ @content += " #{element.to_s.snakecase}: #{fill_in_field_from_type(details[:type])} # #{details[:type]} \n"
103
+ # TODO: If details is a Hash need to loop again
104
+ end
105
+ end
106
+
107
+ root_type = @wsdl_schemas.at_xpath("//*[@name='#{details[:input]}']")['type'].split(':').last
108
+ root_elements = @wsdl_schemas.xpath("//*[@name='#{root_type}']//xsd:element")
109
+ wsdl_to_yaml_for root_elements
110
+
111
+ params = []
112
+ params << 'convert_request_keys_to: :camelcase' if @use_camel_case
113
+ params_string = params == [] ? '' : ', ' + params.join(', ')
114
+ @class_params = "'#{camel_case(operation)}'#{params_string}"
115
+
116
+ create_file(filename: "config/data/#{operation}.yml", content: @content)
117
+ create_file(filename: "spec/#{operation}_spec.rb", content: generated_soap_spec_for(operation))
118
+ end
119
+ end
120
+
43
121
  end
44
122
  end
45
123
 
@@ -1,16 +1,27 @@
1
1
 
2
+ require 'fileutils'
2
3
  module Soaspec
3
4
  # Help with tasks common to soaspec executables
4
5
  module ExeHelpers
5
- require 'fileutils'
6
+
7
+ # Spec task string depending upon whether virtual is used
8
+ def spec_task
9
+ task_name = options[:virtual] ? 'spec: :start_test_server' : ':spec'
10
+ "RSpec::Core::RakeTask.new(#{task_name}) do |t|"
11
+ end
12
+
13
+ # Retrieve default file contents based on filename
14
+ def retrieve_contents(filename, erb)
15
+ default_file = File.join(File.dirname(__FILE__), 'generator', filename + (erb ? '.erb' : ''))
16
+ contents = File.read(default_file)
17
+ erb ? ERB.new(contents).result(binding) : contents
18
+ end
6
19
 
7
20
  # @param [String] filename Name of the file to create
8
21
  # @param [String] content Content to place inside file
9
- def create_file(filename: nil, content: nil, ignore_if_present: false)
10
- #filename = options[:filename]
22
+ def create_file(filename: nil, content: nil, ignore_if_present: false, erb: true)
11
23
  raise 'Need to pass filename' unless filename
12
- #content = options[:content]
13
- raise 'Need to pass contents to insert into file' unless content
24
+ content ||= retrieve_contents(filename, erb)
14
25
  if File.exist? filename
15
26
  old_content = File.read(filename)
16
27
  if old_content != content && !ignore_if_present
@@ -24,456 +35,22 @@ module Soaspec
24
35
 
25
36
  def create_folder(folder)
26
37
  if File.exist? folder
27
- unless File.directory? folder
28
- warn "!! #{folder} already exists and is not a directory"
29
- end
38
+ warn "!! #{folder} already exists and is not a directory" unless File.directory? folder
30
39
  else
31
40
  FileUtils.mkdir folder
32
41
  puts "Created folder: #{folder}/"
33
42
  end
34
43
  end
35
44
 
36
- def rake_content
37
- <<-RAKE
38
- # The list of task for a Rake file can be seen with `rake -T`
39
- require 'rspec/core/rake_task' # See See https://relishapp.com/rspec/rspec-core/docs/command-line/rake-task for details
40
-
41
- # This runs `rspec` command with the following options. Type `rake spec` to run this task
42
- RSpec::Core::RakeTask.new(:spec) do |t|
43
- t.pattern = "spec/*_spec.rb" # Run all specs in 'spec' folder ending in '_spec'
44
- # Next line shows output on the screen, Junit xml report and an HTML report
45
- t.rspec_opts = "--format documentation --format RspecJunitFormatter --out logs/spec.xml --format html --out logs/spec.html"
46
- t.fail_on_error = false
47
- end
48
-
49
- task :default => :spec # This runs the 'spec' task by default when no task is mentioned. E.g., if only `rake` is typed
50
-
51
- RAKE
52
- end
53
-
54
- def rake_virtual_content
55
- <<-EOF
56
- # The list of task for a Rake file can be seen with `rake -T`
57
- require 'rspec/core/rake_task' # See See https://relishapp.com/rspec/rspec-core/docs/command-line/rake-task for details
58
-
59
- # This runs `rspec` command with the following options. Type `rake spec` to run this task
60
- RSpec::Core::RakeTask.new(:run_spec) do |t|
61
- t.pattern = "spec/*_spec.rb" # Run all specs in 'spec' folder ending in '_spec'
62
- # Next line shows output on the screen, Junit xml report and an HTML report
63
- t.rspec_opts = "--format documentation --format RspecJunitFormatter --out logs/spec.xml --format html --out logs/spec.html"
64
- t.fail_on_error = false
65
- end
66
-
67
- task :spec => %w[start_test_server run_spec]
68
-
69
- task :default => :spec # This runs the 'spec' task by default when no task is mentioned. E.g., if only `rake` is typed
70
-
71
- desc 'Start virtual web service'
72
- task :start_test_server do
73
- ENV['test_server_pid'] = Process.spawn('ruby', 'spec/test_server.rb', err: %w[logs/test_server.log w]).to_s
74
- puts 'Running test server at pid ' + ENV['test_server_pid']
75
- end
76
-
77
- EOF
78
- end
79
-
80
- def gem_content
81
- <<-EOF
82
- source 'https://rubygems.org'
83
-
84
- gem 'data_magic'
85
- gem 'require_all'
86
- gem 'rspec_junit_formatter'
87
- gem 'rake'
88
- gem 'soaspec'
89
- gem 'sinatra'
90
-
91
- EOF
92
- end
93
-
94
- def spec_helper_content
95
- <<-EOF
96
-
97
- require 'soaspec'
98
- require 'require_all'
99
- require_all 'lib'
100
- require 'data_magic'
101
-
102
- include DataMagic # Used as example of loading data smartly. Use 'data_for' method to load yml data
103
-
104
- RSpec.configure do |config|
105
- # This will make backtrace much shorter by removing many lines from rspec failure message
106
- config.backtrace_exclusion_patterns = [
107
- /rspec/
108
- ]
109
-
110
- # Close test server after all RSpec tests have run
111
- config.after(:suite) do
112
- Process.kill(:QUIT, ENV['test_server_pid'].to_i) if ENV['test_server_pid'] # && Process.wait - causes failure
113
- end
114
-
115
- end
116
-
117
- EOF
118
- end
119
-
120
- # @return [String] Content of README.md to aid someone getting started with this using this gem
121
- def readme_content
122
- <<-EOF
123
-
124
- # Installation
125
-
126
- Run `bundle install` to install the gems mentioned in the Gemfile.
127
-
128
- To avoid conflict with gems on the machine globally it may be better to specify gem location with:
129
-
130
- `bundle install --path ~/.gem`
131
-
132
- # Running tests
133
- On the command line type:
134
- `bundle exec rake spec` or simply `bundle exec rake`
135
-
136
- # Structure
137
-
138
- ## Tests
139
- Tests are within the 'spec' folder and end in '_spec'. Setup and teardown for tests is in 'spec/spec_helper'
140
-
141
- ## Templates
142
- These are the base requests with ERB inside them to create smartly changing requests accoring to the test.yml
143
-
144
- ## Data
145
- Data used in the test is stored in `config/data` folder. The `data_magic` gem is used by default to read files here.
146
-
147
- ## Libaries
148
- Libaries to be installed are in 'Gemfile'. Specific gem versions can be specified here and enforeced with `bundle exec rake`
149
-
150
- ## Reports
151
- Reports are shown in the 'logs' folder. By default Rake produces a junit, an html report, and a `traffic.log` file with the API request and responses in it
152
-
153
- EOF
154
- end
155
-
156
- def test_server_content
157
- <<-FILEEOF
158
- # Used to run virtual web service on localhost. This makes tests more reliable and faster
159
-
160
- require 'sinatra'
161
- require 'nokogiri'
162
- require 'erb'
163
-
164
- # Representing a GetBank SOAP service
165
- class GetBank
166
-
167
- def self.success_response_template
168
- <<-EOF
169
- <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
170
- <soapenv:Body>
171
- <ns1:getBankResponse xmlns:ns1="http://thomas-bayer.com/blz/">
172
- <ns1:details>
173
- <ns1:bezeichnung>Deutsche Bank</ns1:bezeichnung>
174
- <ns1:bic>DEUTDEMMXXX <%= soap_action %></ns1:bic>
175
- <ns1:ort>München</ns1:ort>
176
- <ns1:plz><%= @test_id %></ns1:plz>
177
- </ns1:details>
178
- </ns1:getBankResponse>
179
- </soapenv:Body>
180
- </soapenv:Envelope>
181
- EOF
182
- end
183
-
184
- def self.error_response_template
185
- <<-EOF
186
- <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
187
- <soapenv:Body>
188
- <soapenv:Fault>
189
- <soapenv:Code>
190
- <soapenv:Value>soapenv:Receiver</soapenv:Value>
191
- </soapenv:Code>
192
- <soapenv:Reason>
193
- <soapenv:Text xml:lang="en-US">org.apache.axis2.databinding.ADBException: Unexpected subelement getBank</soapenv:Text>
194
- </soapenv:Reason>
195
- <soapenv:Detail>
196
- <Exception>org.apache.axis2.AxisFault: org.apache.axis2.databinding.ADBException: Unexpected subelement getBank
197
- at org.apache.axis2.AxisFault.makeFault(AxisFault.java:417)
198
- at com.thomas_bayer.blz.BLZServiceMessageReceiverInOut.fromOM(BLZServiceMessageReceiverInOut.java:124)
199
- at com.thomas_bayer.blz.BLZServiceMessageReceiverInOut.invokeBusinessLogic(BLZServiceMessageReceiverInOut.java:43)
200
- at org.apache.axis2.receivers.AbstractInOutSyncMessageReceiver.invokeBusinessLogic(AbstractInOutSyncMessageReceiver.java:42)
201
- at org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:96)
202
- at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:145)
203
- at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:275)
204
- at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:120)
205
- at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
206
- at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
207
- at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
208
- at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
209
- at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
210
- at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
211
- at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
212
- at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
213
- at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
214
- at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
215
- at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
216
- at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683)
217
- at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
218
- at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
219
- at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
220
- at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
221
- at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
222
- at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
223
- at java.lang.Thread.run(Thread.java:745)
224
- Caused by: java.lang.Exception: org.apache.axis2.databinding.ADBException: Unexpected subelement getBank
225
- at com.thomas_bayer.adb.GetBankType$Factory.parse(GetBankType.java:423)
226
- at com.thomas_bayer.adb.GetBank$Factory.parse(GetBank.java:304)
227
- at com.thomas_bayer.blz.BLZServiceMessageReceiverInOut.fromOM(BLZServiceMessageReceiverInOut.java:117)
228
- ... 25 more
229
- Caused by: org.apache.axis2.databinding.ADBException: Unexpected subelement getBank
230
- at com.thomas_bayer.adb.GetBankType$Factory.parse(GetBankType.java:410)
231
- ... 27 more
232
- </Exception>
233
- </soapenv:Detail>
234
- </soapenv:Fault>
235
- </soapenv:Body>
236
- </soapenv:Envelope>
237
- EOF
238
- end
239
-
240
- def self.response_for(request)
241
- request_body = request.body
242
- soap_action = request.env['HTTP_SOAPACTION'].strip
243
- doc = Nokogiri::XML(request_body)
244
- blz_element = doc.xpath('//tns:blz').first
245
- return 500, error_response_template unless blz_element
246
- @test_id = blz_element.inner_text
247
- ERB.new(success_response_template).result(binding)
248
- end
249
- end
250
-
251
- # This is the one being hit
252
- post '/BLZService' do
253
- GetBank.response_for request
254
- end
255
- FILEEOF
256
- end
257
-
258
- def weather_web_service
259
- <<-WEATH_WEB
260
- require 'soaspec'
261
-
262
- # This class is not part of the gem. It's an example of a class you can make
263
- # to describe your APIs. Usually this would exist in the 'lib' directory
264
- # Common configuration for the Savon client should go here
265
- class BLZService < Soaspec::SoapHandler
266
- # Add to or override default Savon client options
267
- def savon_options
268
- {
269
- # wsdl: 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl' # External
270
- wsdl: File.join('spec', 'test_data', 'wsdl', 'get_bank.wsdl')
271
- }
272
- end
273
-
274
- # # Specifying that get_weather_result must be present in the SOAP response
275
- mandatory_elements [:plz]
276
-
277
- # Example of xpath value that must be true for all success scenarios
278
- mandatory_xpath_values 'ns1:bezeichnung' => 'Deutsche Bank'
279
-
280
- # Example of setting an attribute on the root XML element
281
- root_attributes 'Version' => '1' # TODO: Create test on request for this
282
-
283
- end
284
-
285
- WEATH_WEB
286
- end
287
-
288
- def soap_spec_content
289
- <<-SOAP_SPEC
290
-
291
- require 'spec_helper'
292
-
293
- Soaspec.strip_namespaces = true # This allows namespace not to be used. Be careful with this
294
-
295
- id = '70070010'
296
- # BLZService.new(template_name: 'soap_template') Use this instead of default_hash to use template approach
297
-
298
- context 'Test Examples' do
299
- context BLZService.new('Get Bank', operation: :get_bank, default_hash: { blz: id }) do
300
-
301
- describe Exchange.new(:default) do
302
- it { is_expected.to contain_value id }
303
- it { is_expected.to include_in_body id }
304
- it_behaves_like 'success scenario'
305
- after(:all) { described_class.store(:title, 'bezeichnung') }
306
- end
307
-
308
- describe Exchange.new(:xpath_eg, blz: 100000) do
309
- its(['plz']) { is_expected.to eq '100000' }
310
- it { is_expected.to have_xpath_value '//ns1:bezeichnung' => 'Deutsche Bank' }
311
- context 'Handle retrieving stored value' do
312
- it { is_expected.to have_xpath_value 'bezeichnung' => described_class.retrieve(:title) }
313
- end
314
- end
315
-
316
- describe Exchange.new(:yaml_eg, data_for(:small_id)) do
317
- it_behaves_like 'success scenario'
318
- end
319
-
320
- # Retry for success more for web services that intermittently fail
321
- describe Exchange.new(:short_hand_xpath).retry_for_success do
322
- # Be careful. If you call a method that does not use namespaces, calling one that does may not find the element
323
- its(['ns1:bezeichnung']) { is_expected.to eq 'Deutsche Bank' } # '//' is not required at the beginning
324
- end
325
- describe Exchange.new('Check existence of elements') do
326
- it { is_expected.to have_element_at_xpath '//ns1:bezeichnung' }
327
- it { is_expected.not_to have_element_at_xpath '//ns1:bezeichnung_pretend' }
328
- end
329
-
330
- end
331
- end
332
-
333
- error_example = BLZService.new('Error example')
334
- error_example.operation = :get_bank
335
- error_example.default_hash = {}
336
-
337
- context 'Error Examples' do
338
- context error_example do
339
- describe Exchange.new(:no_blz_error) do
340
- it_behaves_like 'error scenario'
341
- end
342
- end
343
- end
344
-
345
-
346
- SOAP_SPEC
45
+ # Create class representing wsdl in general
46
+ def class_content
47
+ ERB.new(File.read(File.join(File.dirname(__FILE__), 'generator', 'lib/dynamic_class_content.rb.erb'))).result(binding)
347
48
  end
348
49
 
349
- def shared_examples_content
350
- <<-SHARE_EG
351
-
352
- require 'rspec'
353
-
354
- shared_examples_for 'error scenario' do
355
- it 'does not have status code of 200' do
356
- expect(described_class.status_code).not_to eq 200
357
- end
358
- end
359
-
360
- SHARE_EG
361
- end
362
-
363
- def soap_template_content
364
- <<-SOAP_TEMP
365
- <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://thomas-bayer.com/blz/" xmlns:env="http://www.w3.org/2003/05/soap-envelope">
366
- <env:Body>
367
- <tns:getBank>
368
- <tns:blz><%= test_values[:blz] || '70070010' %></tns:blz>
369
- </tns:getBank>
370
- </env:Body>
371
- </env:Envelope>
372
- SOAP_TEMP
373
- end
374
-
375
- def default_yaml_content
376
- <<-DEF_YAML
377
- small_id:
378
- blz: 100
379
-
380
- DEF_YAML
381
- end
382
-
383
- def test_wsdl_content
384
- <<TEST_WSDL
385
- <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:tns="http://thomas-bayer.com/blz/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://thomas-bayer.com/blz/">
386
- <wsdl:documentation>BLZService</wsdl:documentation>
387
- <wsdl:types>
388
- <xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://thomas-bayer.com/blz/">
389
- <xsd:element name="getBank" type="tns:getBankType"/>
390
- <xsd:element name="getBankResponse" type="tns:getBankResponseType"/>
391
- <xsd:complexType name="getBankType">
392
- <xsd:sequence>
393
- <xsd:element name="blz" type="xsd:string"/>
394
- </xsd:sequence>
395
- </xsd:complexType>
396
- <xsd:complexType name="getBankResponseType">
397
- <xsd:sequence>
398
- <xsd:element name="details" type="tns:detailsType"/>
399
- </xsd:sequence>
400
- </xsd:complexType>
401
- <xsd:complexType name="detailsType">
402
- <xsd:sequence>
403
- <xsd:element minOccurs="0" name="bezeichnung" type="xsd:string"/>
404
- <xsd:element minOccurs="0" name="bic" type="xsd:string"/>
405
- <xsd:element minOccurs="0" name="ort" type="xsd:string"/>
406
- <xsd:element minOccurs="0" name="plz" type="xsd:string"/>
407
- </xsd:sequence>
408
- </xsd:complexType>
409
- </xsd:schema>
410
- </wsdl:types>
411
- <wsdl:message name="getBank">
412
- <wsdl:part name="parameters" element="tns:getBank"/>
413
- </wsdl:message>
414
- <wsdl:message name="getBankResponse">
415
- <wsdl:part name="parameters" element="tns:getBankResponse"/>
416
- </wsdl:message>
417
- <wsdl:portType name="BLZServicePortType">
418
- <wsdl:operation name="getBank">
419
- <wsdl:input message="tns:getBank"/>
420
- <!--<wsdl:output message="tns:getBankResponse" wsaw:Action="http://thomas-bayer.com/blz/BLZService/getBankResponse"/>-->
421
- <wsdl:output message="tns:getBankResponse" wsaw:Action="http://localhost:4567/BLZService/getBankResponse"/>
422
- </wsdl:operation>
423
- </wsdl:portType>
424
- <wsdl:binding name="BLZServiceSOAP11Binding" type="tns:BLZServicePortType">
425
- <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
426
- <wsdl:operation name="getBank">
427
- <soap:operation style="document" soapAction=""/>
428
- <wsdl:input>
429
- <soap:body use="literal"/>
430
- </wsdl:input>
431
- <wsdl:output>
432
- <soap:body use="literal"/>
433
- </wsdl:output>
434
- </wsdl:operation>
435
- </wsdl:binding>
436
- <wsdl:binding name="BLZServiceSOAP12Binding" type="tns:BLZServicePortType">
437
- <soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
438
- <wsdl:operation name="getBank">
439
- <soap12:operation style="document" soapAction=""/>
440
- <wsdl:input>
441
- <soap12:body use="literal"/>
442
- </wsdl:input>
443
- <wsdl:output>
444
- <soap12:body use="literal"/>
445
- </wsdl:output>
446
- </wsdl:operation>
447
- </wsdl:binding>
448
- <wsdl:binding name="BLZServiceHttpBinding" type="tns:BLZServicePortType">
449
- <http:binding verb="POST"/>
450
- <wsdl:operation name="getBank">
451
- <http:operation location="BLZService/getBank"/>
452
- <wsdl:input>
453
- <mime:content part="getBank" type="text/xml"/>
454
- </wsdl:input>
455
- <wsdl:output>
456
- <mime:content part="getBank" type="text/xml"/>
457
- </wsdl:output>
458
- </wsdl:operation>
459
- </wsdl:binding>
460
- <wsdl:service name="BLZService">
461
- <wsdl:port name="BLZServiceSOAP11port_http" binding="tns:BLZServiceSOAP11Binding">
462
- <!-- <soap:address location="http://www.thomas-bayer.com/axis2/services/BLZService"/> -->
463
- <soap:address location="http://localhost:4567/BLZService"/>
464
- </wsdl:port>
465
- <wsdl:port name="BLZServiceSOAP12port_http" binding="tns:BLZServiceSOAP12Binding">
466
- <!--<soap12:address location="http://www.thomas-bayer.com/axis2/services/BLZService"/>-->
467
- <soap12:address location="http://localhost:4567/BLZService"/>
468
- </wsdl:port>
469
- <wsdl:port name="BLZServiceHttpport" binding="tns:BLZServiceHttpBinding">
470
- <!--<http:address location="http://www.thomas-bayer.com/axis2/services/BLZService"/>-->
471
- <soap:address location="http://localhost:4567/BLZService"/>
472
- </wsdl:port>
473
- </wsdl:service>
474
- </wsdl:definitions>
475
-
476
- TEST_WSDL
50
+ # Create a spec for an WSDL operation
51
+ # @param [String] operation Used in ERB to create a test for a WSDL operation
52
+ def generated_soap_spec_for(operation)
53
+ ERB.new(File.read(File.join(File.dirname(__FILE__), 'generator', 'spec/dynamic_soap_spec.rb.erb'))).result(binding)
477
54
  end
478
55
 
479
56
  end
@@ -0,0 +1,5 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ <%= '--format RspecJunitFormatter --out logs/spec.xml' if options[:ci] == 'jenkins' %>
4
+ --format html --out logs/spec.html
5
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.4
5
+ before_install: gem install bundler -v 1.16.0
@@ -0,0 +1,8 @@
1
+
2
+ source 'https://rubygems.org'
3
+
4
+ gem 'data_magic'
5
+ gem 'require_all'
6
+ gem 'rake'
7
+ <%= "gem 'rspec_junit_formatter'" if options[:ci] == 'jenkins' %>
8
+ gem 'soaspec'
@@ -0,0 +1,29 @@
1
+
2
+ # Installation
3
+
4
+ Run `bundle install` to install the gems mentioned in the Gemfile.
5
+
6
+ To avoid conflict with gems on the machine globally it may be better to specify gem location with:
7
+
8
+ `bundle install --path ~/.gem`
9
+
10
+ # Running tests
11
+ On the command line type:
12
+ `bundle exec rake spec` or simply `bundle exec rake`
13
+
14
+ # Structure
15
+
16
+ ## Tests
17
+ RSpec tests are within the `spec` folder and end in `_spec`. Setup and teardown for tests is in `spec/spec_helper`
18
+
19
+ ## Templates
20
+ These are the base requests with ERB inside them to create smartly changing requests accoring to the test.yml
21
+
22
+ ## Data
23
+ Data used in the test is stored in `config/data` folder. The `data_magic` gem is used by default to read files here.
24
+
25
+ ## Libraries
26
+ Libaries to be installed are in 'Gemfile'. Specific gem versions can be specified here and enforeced with `bundle exec rake`
27
+
28
+ ## Reports
29
+ Reports are shown in the 'logs' folder. By default Rake produces a junit, an html report, and a `traffic.log` file with the API request and responses in it
@@ -0,0 +1,20 @@
1
+
2
+ # The list of task for a Rake file can be seen with `rake -T`
3
+ require 'rspec/core/rake_task' # See https://relishapp.com/rspec/rspec-core/docs/command-line/rake-task for details
4
+
5
+ # This runs `rspec` command with the following options. Type `rake spec` to run this task
6
+ <%= spec_task %>
7
+ t.pattern = "spec/*_spec.rb" # Run all specs in 'spec' folder ending in '_spec'
8
+ <%= 't.fail_on_error = false' if options[:ci] == 'jenkins' %>
9
+ end
10
+
11
+ task default: :spec # This runs the 'spec' task by default when no task is mentioned. E.g., if only `rake` is typed
12
+
13
+ <% if @virtual %>
14
+ desc 'Start virtual web service'
15
+ task :start_test_server do
16
+ ENV['test_server_pid'] = Process.spawn('soaspec-virtual-server', err: %w[logs/test_server.log w]).to_s
17
+ puts 'Running test server at pid ' + ENV['test_server_pid']
18
+ sleep 0.5 # Wait a little for virtual server to start up
19
+ end
20
+ <% end %>
@@ -0,0 +1,2 @@
1
+ small_id:
2
+ blz: 100
@@ -0,0 +1,24 @@
1
+
2
+ require 'soaspec'
3
+
4
+ # This class is not part of the gem. It's an example of a class you can make
5
+ # to describe your APIs. Usually this would exist in the 'lib' directory
6
+ # Common configuration for the Savon client should go here
7
+ class BLZService < Soaspec::SoapHandler
8
+ # Add to or override default Savon client options
9
+ def savon_options
10
+ {
11
+ wsdl: 'http://localhost:4999/BLZService?wsdl'
12
+ }
13
+ end
14
+
15
+ # # Specifying that get_weather_result must be present in the SOAP response
16
+ mandatory_elements [:plz]
17
+
18
+ # Example of xpath value that must be true for all success scenarios
19
+ mandatory_xpath_values 'ns1:bezeichnung' => 'Deutsche Bank'
20
+
21
+ # Example of setting an attribute on the root XML element
22
+ root_attributes 'Version' => '1'
23
+
24
+ end
@@ -0,0 +1,12 @@
1
+
2
+ require 'soaspec'
3
+
4
+ class <%= options[:name] %> < Soaspec::SoapHandler
5
+ # Add to or override default Savon client options
6
+ def savon_options
7
+ {
8
+ wsdl: '<%= options[:wsdl] %>'
9
+ }
10
+ end
11
+
12
+ end
@@ -0,0 +1,8 @@
1
+
2
+ require 'rspec'
3
+
4
+ shared_examples_for 'error scenario' do
5
+ it 'does not have status code of 200' do
6
+ expect(described_class.status_code).not_to eq 200
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ Soaspec.strip_namespaces = true # This allows namespace not to be used. Be careful with this
5
+
6
+ <%= operation %> = <%= options[:name] %>.new(<%= @class_params %>)
7
+ <%= operation %>.operation = :<%= operation %>
8
+ <%= operation %>.default_hash = data_for '<%= operation %>/default'
9
+
10
+ context <%= operation %> do
11
+ describe Exchange.new(:default) do
12
+ it_behaves_like 'success scenario'
13
+ end
14
+ end
@@ -0,0 +1,53 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ Soaspec.strip_namespaces = true # This allows namespace not to be used. Be careful with this
5
+
6
+ id = '70070010'
7
+ # BLZService.new(template_name: 'soap_template') Use this instead of default_hash to use template approach
8
+
9
+ context 'Test Examples' do
10
+ context BLZService.new('Get Bank', operation: :get_bank, default_hash: { blz: id }) do
11
+
12
+ describe Exchange.new(:default) do
13
+ it { is_expected.to contain_value id }
14
+ it { is_expected.to include_in_body id }
15
+ it_behaves_like 'success scenario'
16
+ after(:all) { described_class.store(:title, 'bezeichnung') }
17
+ end
18
+
19
+ describe Exchange.new(:xpath_eg, blz: 100000) do
20
+ its(['plz']) { is_expected.to eq '100000' }
21
+ it { is_expected.to have_xpath_value '//ns1:bezeichnung' => 'Deutsche Bank' }
22
+ context 'Handle retrieving stored value' do
23
+ it { is_expected.to have_xpath_value 'bezeichnung' => described_class.retrieve(:title) }
24
+ end
25
+ end
26
+
27
+ describe Exchange.new(:yaml_eg, data_for(:small_id)) do
28
+ it_behaves_like 'success scenario'
29
+ end
30
+
31
+ # Retry for success more for web services that intermittently fail
32
+ describe Exchange.new(:short_hand_xpath).retry_for_success do
33
+ # Be careful. If you call a method that does not use namespaces, calling one that does may not find the element
34
+ its(['ns1:bezeichnung']) { is_expected.to eq 'Deutsche Bank' } # '//' is not required at the beginning
35
+ end
36
+ describe Exchange.new('Check existence of elements') do
37
+ it { is_expected.to have_element_at_xpath '//ns1:bezeichnung' }
38
+ it { is_expected.not_to have_element_at_xpath '//ns1:bezeichnung_pretend' }
39
+ end
40
+ end
41
+ end
42
+
43
+ error_example = BLZService.new('Error example')
44
+ error_example.operation = :get_bank
45
+ error_example.default_hash = {}
46
+
47
+ context 'Error Examples' do
48
+ context error_example do
49
+ describe Exchange.new(:no_blz_error) do
50
+ it_behaves_like 'error scenario'
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,20 @@
1
+
2
+ require 'soaspec'
3
+ require 'require_all'
4
+ require_all 'lib'
5
+ require 'data_magic'
6
+
7
+ include DataMagic # Used as example of loading data smartly. Use 'data_for' method to load yml data
8
+
9
+ RSpec.configure do |config|
10
+ # This will make backtrace much shorter by removing many lines from rspec failure message
11
+ config.backtrace_exclusion_patterns = [
12
+ /rspec/
13
+ ]
14
+ <% if @virtual %>
15
+ # Close test server after all RSpec tests have run
16
+ config.after(:suite) do
17
+ Process.kill(:QUIT, ENV['test_server_pid'].to_i) if ENV['test_server_pid']
18
+ end
19
+ <% end %>
20
+ end
@@ -0,0 +1,7 @@
1
+ <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://thomas-bayer.com/blz/" xmlns:env="http://www.w3.org/2003/05/soap-envelope">
2
+ <env:Body>
3
+ <tns:getBank>
4
+ <tns:blz><%= test_values[:blz] || '70070010' %></tns:blz>
5
+ </tns:getBank>
6
+ </env:Body>
7
+ </env:Envelope>
@@ -1,3 +1,3 @@
1
1
  module Soaspec
2
- VERSION = '0.0.77'.freeze
2
+ VERSION = '0.0.78'.freeze
3
3
  end
@@ -0,0 +1,94 @@
1
+
2
+ module Soaspec
3
+ module WsdlGenerator
4
+ def try_enum_for(type)
5
+ custom_type = @wsdl_schemas.xpath("//*[@name='#{type}']")
6
+ if custom_type.first
7
+ prefix = custom_type.first.namespace.prefix
8
+ enumerations = custom_type.xpath("//#{prefix}:enumeration")
9
+ return 'Custom Type' if enumerations.empty?
10
+ @enums_values = Array.new
11
+ enumerations.each do |enum_value|
12
+ @enums_values << "'#{enum_value['value']}'"
13
+ end
14
+ "~randomize [#{@enums_values.join(', ')}]"
15
+ else
16
+ 'Custom Type'
17
+ end
18
+ end
19
+
20
+ def value_after_namespace(string)
21
+ string.split(':').last
22
+ end
23
+
24
+ # Based on WSDL type return a valid value
25
+ # @param [String] type Type without the WSDL
26
+ def fill_in_field_from_type(type)
27
+ case type
28
+ when 'string'
29
+ options[:string_default] # 'test string'
30
+ when 'int'
31
+ 2
32
+ when 'boolean'
33
+ true
34
+ when 'double'
35
+ '1.5'
36
+ else
37
+ try_enum_for type
38
+ end
39
+ end
40
+
41
+ # @param [String, Symbol] underscore_separated Snakecase value to be converted to camel case
42
+ def camel_case(underscore_separated)
43
+ underscore_separated.to_s.split('_').collect(&:capitalize).join
44
+ end
45
+
46
+ # @param [Nokogiri::NodeSet] list List
47
+ def wsdl_to_yaml_for(list)
48
+ puts list
49
+ list.each do |element|
50
+ name = element['name']
51
+ type = value_after_namespace(element['type'])
52
+ puts 'Name ' + name + ' type ' + type
53
+ @use_camel_case = true if (/[[:upper:]]/.match(name[0]) != nil)
54
+ @content += " #{name.snakecase}: #{fill_in_field_from_type(type)} # #{type} \n"
55
+ # TODO: If details is a Hash need to loop again
56
+ end
57
+ end
58
+
59
+ def ask_wsdl
60
+ prompt = <<-EOF
61
+ Enter WSDL:
62
+ EOF
63
+ print prompt.chop
64
+ @wsdl = $stdin.gets.strip
65
+ puts
66
+ end
67
+
68
+ def name_of_wsdl
69
+ prompt = <<-EOF
70
+ Enter what you would like to name WSDL (CamelCase):
71
+ EOF
72
+ print prompt.chop
73
+ @name = $stdin.gets.strip
74
+ puts
75
+ end
76
+
77
+ # Prompt user to enter basic auth details
78
+ def enter_auth_details
79
+ prompt = <<-EOF
80
+ User Name:
81
+ EOF
82
+ print prompt.chop
83
+ @auth_name = $stdin.gets.strip
84
+ puts
85
+
86
+ prompt = <<-EOF
87
+ User Password:
88
+ EOF
89
+ print prompt.chop
90
+ @auth_password = $stdin.gets.strip
91
+ puts
92
+ end
93
+ end
94
+ end
data/lib/soaspec.rb CHANGED
@@ -26,6 +26,7 @@ require 'soaspec/test_server/get_bank'
26
26
  require 'soaspec/test_server/test_attribute'
27
27
  require 'soaspec/test_server/puppy_service'
28
28
  require 'soaspec/test_server/invoices'
29
+ require 'soaspec/wsdl_generator'
29
30
 
30
31
  # Gem for handling SOAP and REST api tests
31
32
  module Soaspec
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soaspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.77
4
+ version: 0.0.78
5
5
  platform: ruby
6
6
  authors:
7
7
  - SamuelGarrattIQA
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-18 00:00:00.000000000 Z
11
+ date: 2018-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -282,7 +282,6 @@ email:
282
282
  - samuel.garratt@integrationqa.com
283
283
  executables:
284
284
  - soaspec
285
- - soaspec-generate
286
285
  - soaspec-virtual-server
287
286
  - xml_to_yaml_file
288
287
  extensions: []
@@ -301,7 +300,6 @@ files:
301
300
  - Rakefile
302
301
  - Todo.md
303
302
  - exe/soaspec
304
- - exe/soaspec-generate
305
303
  - exe/soaspec-virtual-server
306
304
  - exe/xml_to_yaml_file
307
305
  - lib/soaspec.rb
@@ -313,6 +311,19 @@ files:
313
311
  - lib/soaspec/exchange_handlers/rest_methods.rb
314
312
  - lib/soaspec/exchange_handlers/soap_handler.rb
315
313
  - lib/soaspec/exe_helpers.rb
314
+ - lib/soaspec/generator/.rspec.erb
315
+ - lib/soaspec/generator/.travis.yml.erb
316
+ - lib/soaspec/generator/Gemfile.erb
317
+ - lib/soaspec/generator/README.md.erb
318
+ - lib/soaspec/generator/Rakefile.erb
319
+ - lib/soaspec/generator/config/data/default.yml.erb
320
+ - lib/soaspec/generator/lib/blz_service.rb.erb
321
+ - lib/soaspec/generator/lib/dynamic_class_content.rb.erb
322
+ - lib/soaspec/generator/lib/shared_example.rb.erb
323
+ - lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb
324
+ - lib/soaspec/generator/spec/soap_spec.rb.erb
325
+ - lib/soaspec/generator/spec/spec_helper.rb.erb
326
+ - lib/soaspec/generator/template/soap_template.xml
316
327
  - lib/soaspec/interpreter.rb
317
328
  - lib/soaspec/matchers.rb
318
329
  - lib/soaspec/not_found_errors.rb
@@ -325,6 +336,7 @@ files:
325
336
  - lib/soaspec/test_server/puppy_service.rb
326
337
  - lib/soaspec/test_server/test_attribute.rb
327
338
  - lib/soaspec/version.rb
339
+ - lib/soaspec/wsdl_generator.rb
328
340
  - soaspec.gemspec
329
341
  - test.wsdl
330
342
  - test.xml
data/exe/soaspec-generate DELETED
@@ -1,200 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Generate Soaspec tests from a WSDL. Later Swagger, other definitions will be added
4
- #
5
- #http://www.webservicex.com/globalweather.asmx?wsdl
6
-
7
- $LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
8
-
9
- require 'savon'
10
- require 'soaspec'
11
-
12
- include Soaspec::ExeHelpers
13
-
14
- def try_enum_for(type)
15
- custom_type = @wsdl_schemas.xpath("//*[@name='#{type}']")
16
- if custom_type.first
17
- prefix = custom_type.first.namespace.prefix
18
- enumerations = custom_type.xpath("//#{prefix}:enumeration")
19
- return 'Custom Type' if enumerations.empty?
20
- @enums_values = Array.new
21
- enumerations.each do |enum_value|
22
- @enums_values << "'#{enum_value['value']}'"
23
- end
24
- "~randomize [#{@enums_values.join(', ')}]"
25
- else
26
- 'Custom Type'
27
- end
28
- end
29
-
30
- def value_after_namespace(string)
31
- string.split(':').last
32
- end
33
-
34
- # Based on WSDL type return a valid value
35
- # @param [String] type Type without the WSDL
36
- def fill_in_field_from_type(type)
37
- case type
38
- when 'string'
39
- 'test string'
40
- when 'int'
41
- 2
42
- when 'boolean'
43
- true
44
- when 'double'
45
- '1.5'
46
- else
47
- try_enum_for type
48
- end
49
- end
50
-
51
- def ask_wsdl
52
- prompt = <<-EOF
53
- Enter WSDL:
54
- EOF
55
- print prompt.chop
56
- @wsdl = $stdin.gets.strip
57
- puts
58
- end
59
-
60
- def name_of_wsdl
61
- prompt = <<-EOF
62
- Enter what you would like to name WSDL (CamelCase):
63
- EOF
64
- print prompt.chop
65
- @name = $stdin.gets.strip
66
- puts
67
- end
68
-
69
- def authentication_type
70
- prompt = <<-EOF
71
- Authentication
72
- (1) Basic
73
- (2) None
74
-
75
- Type:
76
- EOF
77
- print prompt.chop
78
- num = $stdin.gets.to_i - 1
79
- puts
80
-
81
- @auth = [:basic, :none][num] || :none
82
-
83
- if @auth == :basic
84
- prompt = <<-EOF
85
- User Name:
86
- EOF
87
- print prompt.chop
88
- @auth_name = $stdin.gets.strip
89
- puts
90
-
91
- prompt = <<-EOF
92
- User Password:
93
- EOF
94
- print prompt.chop
95
- @auth_password = $stdin.gets.strip
96
- puts
97
- end
98
-
99
- end
100
-
101
- def camel_case(underscore_seperated)
102
- underscore_seperated.to_s.split('_').collect(&:capitalize).join
103
- end
104
-
105
- @class_content = <<-EOF
106
-
107
- require 'soaspec'
108
-
109
- class <%= @name %> < Soaspec::SoapHandler
110
- # Add to or override default Savon client options
111
- def savon_options
112
- {
113
- wsdl: '<%= @wsdl %>'
114
- }
115
- end
116
-
117
- end
118
- EOF
119
-
120
- @soap_spec_content = <<-EOF
121
-
122
- require 'spec_helper'
123
-
124
- Soaspec.strip_namespaces = true # This allows namespace not to be used. Be careful with this
125
-
126
- <%= operation %> = <%= @name %>.new(<%= @class_params %>)
127
- <%= operation %>.operation = :<%= operation %>
128
- <%= operation %>.default_hash = data_for '<%= operation %>/default'
129
-
130
- context <%= operation %> do
131
- describe Exchange.new(:default) do
132
- it_behaves_like 'success scenario'
133
- end
134
- end
135
-
136
- EOF
137
-
138
- # @param [Nokogiri::NodeSet] list List
139
- def wsdl_to_yaml_for(list)
140
- puts list
141
- list.each do |element|
142
- name = element['name']
143
- type = value_after_namespace(element['type'])
144
- puts 'Name ' + name + ' type ' + type
145
- @use_camel_case = true if (/[[:upper:]]/.match(name[0]) != nil)
146
- @content += " #{name.snakecase}: #{fill_in_field_from_type(type)} # #{type} \n"
147
- # TODO: If details is a Hash need to loop again
148
- end
149
- end
150
-
151
- name_of_wsdl
152
- ask_wsdl
153
-
154
- authentication_type
155
-
156
- savon_options = { wsdl: @wsdl }
157
- savon_options[:basic_auth] = [@auth_name, @auth_password] if @auth == :basic
158
-
159
- @wsdl_doc = Savon.client(**savon_options).wsdl
160
- @wsdl_schemas = @wsdl_doc.parser.schemas
161
-
162
- # Basic files. May already be there
163
- create_file filename: 'Rakefile', content: rake_content, ignore_if_present: true
164
- create_file filename: 'Gemfile', content: gem_content, ignore_if_present: true
165
- create_folder 'spec'
166
- create_file filename: 'spec/spec_helper.rb', content: spec_helper_content
167
- create_file filename: 'README.md', content: readme_content, ignore_if_present: true
168
-
169
- create_folder 'logs'
170
- create_folder 'config'
171
- create_folder 'config/data'
172
- create_folder 'lib'
173
- create_file filename: "lib/#{@name.to_s.snakecase}.rb", content: ERB.new(@class_content).result(binding)
174
- # Files according to WSDL
175
- @wsdl_doc.operations.each do |operation, details|
176
- puts "Creating files for operation: #{operation}"
177
- @content = "default:\n"
178
- @use_camel_case = false
179
- puts 'Message params: ' + details.to_s
180
- # From namespace identifier, find namespace, and for that find schemaLocation xsd and use that to build request
181
- if details[:parameters]
182
- details[:parameters].each do |element, details|
183
- @use_camel_case = true if (/[[:upper:]]/.match(element.to_s[0]) != nil)
184
- @content += " #{element.to_s.snakecase}: #{fill_in_field_from_type(details[:type])} # #{details[:type]} \n"
185
- # TODO: If details is a Hash need to loop again
186
- end
187
- end
188
-
189
- root_type = @wsdl_schemas.at_xpath("//*[@name='#{details[:input]}']")['type'].split(':').last
190
- root_elements = @wsdl_schemas.xpath("//*[@name='#{root_type}']//xsd:element")
191
- wsdl_to_yaml_for root_elements
192
-
193
- params = []
194
- params << 'convert_request_keys_to: :camelcase' if @use_camel_case
195
- params_string = params == [] ? '' : ', ' + params.join(', ')
196
- @class_params = "'#{camel_case(operation)}'#{params_string}"
197
-
198
- create_file(filename: "config/data/#{operation}.yml", content: @content)
199
- create_file(filename: "spec/#{operation}_spec.rb", content: ERB.new(@soap_spec_content).result(binding))
200
- end