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 +4 -4
- data/.gitlab-ci.yml +5 -0
- data/ChangeLog +4 -0
- data/Rakefile +5 -0
- data/exe/soaspec +95 -17
- data/lib/soaspec/exe_helpers.rb +24 -447
- data/lib/soaspec/generator/.rspec.erb +5 -0
- data/lib/soaspec/generator/.travis.yml.erb +5 -0
- data/lib/soaspec/generator/Gemfile.erb +8 -0
- data/lib/soaspec/generator/README.md.erb +29 -0
- data/lib/soaspec/generator/Rakefile.erb +20 -0
- data/lib/soaspec/generator/config/data/default.yml.erb +2 -0
- data/lib/soaspec/generator/lib/blz_service.rb.erb +24 -0
- data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -0
- data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -0
- data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +14 -0
- data/lib/soaspec/generator/spec/soap_spec.rb.erb +53 -0
- data/lib/soaspec/generator/spec/spec_helper.rb.erb +20 -0
- data/lib/soaspec/generator/template/soap_template.xml +7 -0
- data/lib/soaspec/version.rb +1 -1
- data/lib/soaspec/wsdl_generator.rb +94 -0
- data/lib/soaspec.rb +1 -0
- metadata +16 -4
- data/exe/soaspec-generate +0 -200
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81af3fccf7fe08aef640bb651f3db64a35becdee
|
4
|
+
data.tar.gz: 4f3147e1f49580a340a698adf1531da764f21d58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '049af0af886c7087970fc9825afbbe1590a5088ce0cdcc60db865d1d8271578dba801c5603c50bdc1d44e38d920513612f0ccb724e30eca5551f4d19062dfb32'
|
7
|
+
data.tar.gz: a03feb257476d536b6cc03a4ce7c05939b90660d847dbae522f4d667be991596434c21f988361a28d94fee7f5f26afcda70b8759ab84c28cc48a44a703d1bfb2
|
data/.gitlab-ci.yml
CHANGED
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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
24
|
-
|
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'
|
44
|
+
create_file(filename: 'config/data/default.yml')
|
28
45
|
create_folder 'spec'
|
29
|
-
|
30
|
-
|
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',
|
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
|
|
data/lib/soaspec/exe_helpers.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
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,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,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,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>
|
data/lib/soaspec/version.rb
CHANGED
@@ -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.
|
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-
|
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
|