#!/usr/bin/env ruby # Generate Soaspec tests from a WSDL. Later Swagger, other definitions will be added # #http://www.webservicex.com/globalweather.asmx?wsdl $LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) require 'savon' require 'soaspec' include Soaspec::ExeHelpers def try_enum_for(type) custom_type = @wsdl_schemas.xpath("//*[@name='#{type}']") if custom_type.first prefix = custom_type.first.namespace.prefix enumerations = custom_type.xpath("//#{prefix}:enumeration") return 'Custom Type' if enumerations.empty? @enums_values = Array.new enumerations.each do |enum_value| @enums_values << "'#{enum_value['value']}'" end "~randomize [#{@enums_values.join(', ')}]" else 'Custom Type' end end def value_after_namespace(string) string.split(':').last end # Based on WSDL type return a valid value # @param [String] type Type without the WSDL def fill_in_field_from_type(type) case type when 'string' 'test string' when 'int' 2 when 'boolean' true when 'double' '1.5' else try_enum_for type end end def ask_wsdl prompt = <<-EOF Enter WSDL: EOF print prompt.chop @wsdl = $stdin.gets.strip puts end def name_of_wsdl prompt = <<-EOF Enter what you would like to name WSDL (CamelCase): EOF print prompt.chop @name = $stdin.gets.strip puts end def authentication_type prompt = <<-EOF Authentication (1) Basic (2) None Type: EOF print prompt.chop num = $stdin.gets.to_i - 1 puts @auth = [:basic, :none][num] || :none if @auth == :basic prompt = <<-EOF User Name: EOF print prompt.chop @auth_name = $stdin.gets.strip puts prompt = <<-EOF User Password: EOF print prompt.chop @auth_password = $stdin.gets.strip puts end end def camel_case(underscore_seperated) underscore_seperated.to_s.split('_').collect(&:capitalize).join end @class_content = <<-EOF require 'soaspec' class <%= @name %> < Soaspec::SoapHandler # Add to or override default Savon client options def savon_options { wsdl: '<%= @wsdl %>' } end end EOF @soap_spec_content = <<-EOF require 'spec_helper' Soaspec.strip_namespaces = true # This allows namespace not to be used. Be careful with this <%= operation %> = <%= @name %>.new(<%= @class_params %>) <%= operation %>.operation = :<%= operation %> <%= operation %>.default_hash = data_for '<%= operation %>/default' context <%= operation %> do describe Exchange.new(:default) do it_behaves_like 'success scenario' end end EOF # @param [Nokogiri::NodeSet] list List def wsdl_to_yaml_for(list) puts list list.each do |element| name = element['name'] type = value_after_namespace(element['type']) puts 'Name ' + name + ' type ' + type @use_camel_case = true if (/[[:upper:]]/.match(name[0]) != nil) @content += " #{name.snakecase}: #{fill_in_field_from_type(type)} # #{type} \n" # TODO: If details is a Hash need to loop again end end name_of_wsdl ask_wsdl authentication_type savon_options = { wsdl: @wsdl } savon_options[:basic_auth] = [@auth_name, @auth_password] if @auth == :basic @wsdl_doc = Savon.client(**savon_options).wsdl @wsdl_schemas = @wsdl_doc.parser.schemas # Basic files. May already be there create_file filename: 'Rakefile', content: rake_content, ignore_if_present: true create_file filename: 'Gemfile', content: gem_content, ignore_if_present: true create_folder 'spec' create_file filename: 'spec/spec_helper.rb', content: spec_helper_content create_file filename: 'README.md', content: readme_content, ignore_if_present: true create_folder 'logs' create_folder 'config' create_folder 'config/data' create_folder 'lib' create_file filename: "lib/#{@name.to_s.snakecase}.rb", content: ERB.new(@class_content).result(binding) # Files according to WSDL @wsdl_doc.operations.each do |operation, details| puts "Creating files for operation: #{operation}" @content = "default:\n" @use_camel_case = false puts 'Message params: ' + details.to_s # From namespace identifier, find namespace, and for that find schemaLocation xsd and use that to build request if details[:parameters] details[:parameters].each do |element, details| @use_camel_case = true if (/[[:upper:]]/.match(element.to_s[0]) != nil) @content += " #{element.to_s.snakecase}: #{fill_in_field_from_type(details[:type])} # #{details[:type]} \n" # TODO: If details is a Hash need to loop again end end root_type = @wsdl_schemas.at_xpath("//*[@name='#{details[:input]}']")['type'].split(':').last root_elements = @wsdl_schemas.xpath("//*[@name='#{root_type}']//xsd:element") wsdl_to_yaml_for root_elements params = [] params << 'convert_request_keys_to: :camelcase' if @use_camel_case params_string = params == [] ? '' : ', ' + params.join(', ') @class_params = "'#{camel_case(operation)}'#{params_string}" create_file(filename: "config/data/#{operation}.yml", content: @content) create_file(filename: "spec/#{operation}_spec.rb", content: ERB.new(@soap_spec_content).result(binding)) end