swgr2rb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +69 -0
  4. data/assets/Gemfile +8 -0
  5. data/assets/README.md +94 -0
  6. data/assets/configs/conductor_sender_configs.yaml +4 -0
  7. data/assets/endpoint_object_models/config_loaders/base_config.rb +28 -0
  8. data/assets/endpoint_object_models/config_loaders/conductor_config_loader.rb +18 -0
  9. data/assets/endpoint_object_models/json_validator/json_data_validator.rb +44 -0
  10. data/assets/endpoint_object_models/json_validator/json_schema_validator.rb +52 -0
  11. data/assets/endpoint_object_models/json_validator/json_validator.rb +34 -0
  12. data/assets/endpoint_object_models/loader.rb +16 -0
  13. data/assets/endpoint_object_models/object_models/base_endpoint_object_model.rb +22 -0
  14. data/assets/endpoint_object_models/object_models/base_endpoint_object_model_constants.rb +2 -0
  15. data/assets/endpoint_object_models/object_models/base_endpoint_object_model_methods.rb +82 -0
  16. data/assets/endpoint_object_models/prototypes/json_schema_data_types.rb +3 -0
  17. data/assets/endpoint_object_models/prototypes/request.rb +31 -0
  18. data/assets/features/step_definitions/base_steps.rb +56 -0
  19. data/assets/features/support/env.rb +9 -0
  20. data/assets/features/support/instance_variables.rb +9 -0
  21. data/assets/features/support/world.rb +12 -0
  22. data/assets/request_sender/conductor_sender/conductor_sender.rb +53 -0
  23. data/assets/request_sender/conductor_sender/response.rb +105 -0
  24. data/assets/request_sender/loader.rb +16 -0
  25. data/bin/swgr2rb +8 -0
  26. data/lib/cli/cli_options_parser.rb +139 -0
  27. data/lib/endpoint_class_config_generator/endpoint_class_config.rb +25 -0
  28. data/lib/endpoint_class_config_generator/endpoint_class_config_generator.rb +91 -0
  29. data/lib/endpoint_class_config_generator/json_paths_parser_methods.rb +68 -0
  30. data/lib/endpoint_class_config_generator/json_schema_definitions_parser_methods.rb +59 -0
  31. data/lib/endpoint_class_generator/endpoint_class_generator.rb +168 -0
  32. data/lib/endpoint_class_generator/endpoint_classes_generator.rb +76 -0
  33. data/lib/endpoint_class_generator/ruby_file_generator.rb +52 -0
  34. data/lib/endpoint_class_generator/ruby_file_generator_constants.rb +106 -0
  35. data/lib/endpoint_class_generator/schema_module_generator.rb +49 -0
  36. data/lib/json_fetcher/swagger_json_fetcher.rb +45 -0
  37. data/lib/prototypes/json_schema_data_types.rb +11 -0
  38. data/lib/prototypes/swgr2rb_error.rb +13 -0
  39. data/lib/request_sender/conductor_sender.rb +28 -0
  40. data/lib/request_sender/request.rb +31 -0
  41. data/lib/request_sender/response.rb +115 -0
  42. data/lib/scaffold_generator/feature_file_generator.rb +62 -0
  43. data/lib/scaffold_generator/scaffold_generator.rb +51 -0
  44. data/lib/scaffold_generator/scaffold_generator_constants.rb +19 -0
  45. data/lib/swgr2rb.rb +53 -0
  46. metadata +206 -0
@@ -0,0 +1,3 @@
1
+ module Boolean; end
2
+ class TrueClass; include Boolean; end
3
+ class FalseClass; include Boolean; end
@@ -0,0 +1,31 @@
1
+ class Request
2
+ attr_reader :type, :headers, :body, :subdomain, :endpoint_name
3
+
4
+ def initialize(endpoint_name, type, headers, body)
5
+ @endpoint_name = endpoint_name
6
+ @type = type
7
+ @headers = headers
8
+ @body = body
9
+ process_request_type
10
+ end
11
+
12
+ def url
13
+ generate_url
14
+ end
15
+
16
+ private
17
+
18
+ def process_request_type
19
+ if type.split(' ').length > 1
20
+ @type = type.split(' ').join('_')
21
+ end
22
+ end
23
+
24
+ def generate_url
25
+ configs = ConductorConfigLoader.load
26
+
27
+ "#{configs.connection.protocol}"\
28
+ "#{configs.connection.host}:#{configs.connection.port}"\
29
+ "#{endpoint_name}"
30
+ end
31
+ end
@@ -0,0 +1,56 @@
1
+ Given(/^I send "([^"]*)" request to "([^"]*)"(?: with using results of ([^"]*) request to "([^"]*)" endpoint)?$/) do |request_type, endpoint_name, sub_request_type, sub_endpoint_name|
2
+ request_type = request_type.sub(' ', '_')
3
+ endpoint_instances["#{request_type}_#{endpoint_name}"] = eval("#{endpoint_name.split(' ').map(&:capitalize).join}.new")
4
+ if sub_request_type && sub_endpoint_name
5
+ sub_results = endpoint_instances["#{sub_request_type}_#{sub_endpoint_name}"].results
6
+ else
7
+ sub_results = {}
8
+ end
9
+ endpoint_instances["#{request_type}_#{endpoint_name}"].send_request(request_type, nil, sub_results)
10
+ end
11
+
12
+ Given(/^I send "([^"]*)" request to "([^"]*)" with the following properties(?: with using results of ([^"]*) request to "([^"]*)" endpoint)?:$/) do |request_type, endpoint_name, sub_request_type, sub_endpoint_name, table|
13
+ request_type = request_type.sub(' ', '_')
14
+ endpoint_instances["#{request_type}_#{endpoint_name}"] = eval("#{endpoint_name.split(' ').map(&:capitalize).join}.new")
15
+ if sub_request_type && sub_endpoint_name
16
+ sub_results = endpoint_instances["#{sub_request_type}_#{sub_endpoint_name}"].results
17
+ else
18
+ sub_results = {}
19
+ end
20
+ endpoint_instances["#{request_type}_#{endpoint_name}"].send_request(request_type,
21
+ table.hashes.first, sub_results)
22
+ end
23
+
24
+ Given(/^I send "([^"]*)" request to "([^"]*)"(?: with the following properties)? with using results of the following requests:$/) do |request_type, endpoint_name, table|
25
+ request_type = request_type.sub(' ', '_')
26
+ endpoint_instances["#{request_type}_#{endpoint_name}"] = eval("#{endpoint_name.split(' ').map(&:capitalize).join}.new")
27
+ sub_results = {}
28
+ table.hashes.first[:sub_requests].split(/;\s*/).map do |sub_request_str|
29
+ match_data = sub_request_str.match(/^(?<request_type>\w+) (?<endpoint_name>.+)$/)
30
+ sub_results[match_data[:endpoint_name]] = endpoint_instances["#{match_data[:request_type]}_#{match_data[:endpoint_name]}"].results
31
+ end
32
+ params = table.hashes.first.reject { |k, _v| k.to_sym == :sub_requests }
33
+ endpoint_instances["#{request_type}_#{endpoint_name}"].send_request(request_type, params, sub_results)
34
+ end
35
+
36
+ And(/^the response schema for "([^"]*)" request to "([^"]*)" endpoint should be valid$/) do |request_type, endpoint_name|
37
+ request_type = request_type.sub(' ', '_')
38
+ endpoint_instances["#{request_type}_#{endpoint_name}"].validate_response_schema
39
+ end
40
+
41
+ And(/^the error response for "([^"]*)" request to "([^"]*)" endpoint should be valid with ([^"]*) code$/) do |request_type, endpoint_name, error_code|
42
+ request_type = request_type.sub(' ', '_')
43
+ endpoint_instances["#{request_type}_#{endpoint_name}"].validate_error_response(error_code.to_i)
44
+ end
45
+
46
+ And(/^I wait (\d+) seconds/) do |seconds|
47
+ sleep(seconds)
48
+ end
49
+
50
+ And(/^I (do|do not do) this: (.*[^:])$/) do |do_or_not, step_str|
51
+ step step_str if do_or_not == 'do'
52
+ end
53
+
54
+ And(/^I (do|do not do) this: (.*:)$/) do |do_or_not, step_str, table|
55
+ step step_str, table if do_or_not == 'do'
56
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the entry point for Cucumber
4
+
5
+ require_relative 'world'
6
+
7
+ World do
8
+ World.new
9
+ end
@@ -0,0 +1,9 @@
1
+ module InstanceVariables
2
+ attr_accessor :endpoint_instances
3
+
4
+ def initialize_instance_variables
5
+ @endpoint_instances = {}
6
+ @db_query_results = {}
7
+ @broker_results = {}
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../../endpoint_object_models/loader'
2
+ require_relative '../../request_sender/loader'
3
+ require_relative 'instance_variables'
4
+ require 'base64'
5
+
6
+ class World
7
+ include InstanceVariables
8
+
9
+ def initialize
10
+ initialize_instance_variables
11
+ end
12
+ end
@@ -0,0 +1,53 @@
1
+ require 'httparty'
2
+ require_relative 'response'
3
+
4
+ class ConductorSender
5
+ class << self
6
+ def send_request(request)
7
+ response = send("send_#{request.type}_request",
8
+ request)
9
+
10
+ Response.new(response)
11
+ end
12
+
13
+ private
14
+
15
+ def send_post_request(request)
16
+ HTTParty.post(request.url, body: request.body, headers: request.headers, verify: false)
17
+ end
18
+
19
+ def send_multipart_post_request(request)
20
+ cmd = "curl -k -i --verbose --request POST "\
21
+ " --form 'file=@#{request.body[:filePath]}'"\
22
+ " -H 'Content-Type: #{request.headers[:'Content-Type']}'"\
23
+ " -H 'Authorization: #{request.headers[:'Authorization']}'"\
24
+ " #{request.url}"
25
+
26
+ `#{cmd}`
27
+ end
28
+
29
+ def send_get_request(request)
30
+ HTTParty.get(request.url, query: request.body, headers: request.headers, verify: false)
31
+ end
32
+
33
+ def send_put_request(request)
34
+ HTTParty.put(request.url, body: request.body, headers: request.headers, verify: false)
35
+ end
36
+
37
+ def send_delete_request(request)
38
+ HTTParty.delete(request.url, query: request.body, headers: request.headers, verify: false)
39
+ end
40
+
41
+ def send_head_request(request)
42
+ HTTParty.head(request.url, query: request.body, headers: request.headers, verify: false)
43
+ end
44
+
45
+ def send_patch_request(request)
46
+ HTTParty.patch(request.url, query: request.body, headers: request.headers, verify: false)
47
+ end
48
+
49
+ def send_options_request(request)
50
+ HTTParty.options(request.url, query: request.body, headers: request.headers, verify: false)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,105 @@
1
+ class Response
2
+ attr_accessor :code, :headers, :body
3
+
4
+ def initialize(response)
5
+ @response = response
6
+ check_response
7
+ end
8
+
9
+ private
10
+
11
+ def check_response
12
+ case @response
13
+ when String
14
+ begin
15
+ hash_ = JSON.parse(@response)
16
+ if hash_
17
+ @code = 200
18
+ @headers = ''
19
+ @body = convert_hash(hash_)
20
+ return
21
+ end
22
+ rescue
23
+ end
24
+ end
25
+
26
+ if @response.nil? || (@response.respond_to?(:body) && %w[null true false].include?(@response.body))
27
+ handle_nil_response
28
+ else
29
+ handle_response
30
+ end
31
+ end
32
+
33
+ def convert_hash(base_hash)
34
+ return base_hash unless base_hash.is_a? Hash
35
+ temp_hash = base_hash.dup
36
+ base_hash.each do |k, v|
37
+ case v
38
+ when Hash
39
+ temp_hash[k.to_sym] = convert_hash(v)
40
+ when Array
41
+ temp_hash[k.to_sym] = v.map { |v_el| convert_hash(v_el) }
42
+ else
43
+ temp_hash = temp_hash.inject({}) { |memo, (k1, v1)| memo[k1.to_sym] = v1; memo }
44
+ end
45
+ end
46
+ temp_hash
47
+ end
48
+
49
+ def handle_nil_response
50
+ @code = @response.code
51
+ @headers = @response.headers
52
+
53
+ if @code == 204
54
+ raise 'Received non-null body in 204 No Content response' unless @response.body.nil?
55
+ @body = nil
56
+ else
57
+ case @response.body
58
+ when 'null', ''
59
+ @body = {}
60
+ when 'true'
61
+ @body = true
62
+ when 'false'
63
+ @body = false
64
+ else
65
+ raise 'Not implemented behavior for the empty response'
66
+ end
67
+ end
68
+ end
69
+
70
+ def handle_response
71
+ case @response
72
+ when String
73
+ @code = (@response.match /(HTTP Status|HTTP\/2) \d{3}/).to_s.split(' ')[-1].to_i
74
+ content_type = if @response.match?(/content-type: (.*);/)
75
+ @response.match(/content-type: (.*);/)[1]
76
+ else
77
+ 'text/html'
78
+ end
79
+ @headers = {
80
+ "ContentType": content_type
81
+ }
82
+ @body = if @response.match?(/{.*}/)
83
+ convert_hash(JSON.parse(@response.match(/{.*}/)[0]))
84
+ else
85
+ @response
86
+ end
87
+ return
88
+ else
89
+ @code = @response.code
90
+ @headers = @response.headers
91
+ end
92
+ if @headers&.content_type == 'application/json'
93
+ @body = if @response.parsed_response.is_a? Array
94
+ @response.parsed_response.map { |i| convert_hash(i)}
95
+ elsif @response.parsed_response.is_a? Integer
96
+ @response.parsed_response
97
+ else
98
+ convert_hash(@response.parsed_response)
99
+ end
100
+ else
101
+ # parsed response is string
102
+ @body = @response.parsed_response
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ puts 'Loading Request sender component'
4
+
5
+ def recursive_require(dir)
6
+ Dir["#{File.dirname(__FILE__)}/#{dir}/**/*.rb"].each do |f|
7
+ require(f)
8
+ end
9
+ end
10
+
11
+ dirs = Dir.entries(File.dirname(__FILE__)).select { |entry| File.directory? File.join(File.dirname(__FILE__), entry) and !(entry == '.' || entry == '..') }
12
+ dirs.each do |dir|
13
+ recursive_require(dir)
14
+ end
15
+
16
+ puts 'Done loading Request sender component'
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = nil
3
+ require 'swgr2rb'
4
+ begin
5
+ Swgr2rb::Main.new(ARGV).execute
6
+ rescue Swgr2rb::Swgr2rbError => e
7
+ abort(e.message)
8
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'swgr2rb'
5
+
6
+ module Swgr2rb
7
+ # CliOptionsParser parses arguments received from
8
+ # command line and generates parameters for endpoint generation.
9
+ class CliOptionsParser
10
+ def initialize
11
+ @params = default_params
12
+ end
13
+
14
+ def parse(args)
15
+ option_parser = OptionParser.new do |parser|
16
+ define_options(parser)
17
+ end
18
+ parse_options(option_parser, args)
19
+ path = parse_swagger_path_from_args(args)
20
+ [path, @params]
21
+ end
22
+
23
+ private
24
+
25
+ def default_params
26
+ {
27
+ target_dir: ScaffoldGeneratorConstants::ENDPOINT_MODELS_DIR,
28
+ component: 'component1',
29
+ update_only: false,
30
+ rewrite_schemas: true,
31
+ from_scratch: false
32
+ }
33
+ end
34
+
35
+ def define_options(opts)
36
+ define_banner(opts)
37
+ define_target_dir_option(opts)
38
+ define_component_option(opts)
39
+ define_update_only_option(opts)
40
+ define_rewrite_schemas_option(opts)
41
+ define_from_scratch_option(opts)
42
+ define_help_option(opts)
43
+ end
44
+
45
+ def parse_options(options_parser, args)
46
+ options_parser.parse(args)
47
+ rescue OptionParser::ParseError => e
48
+ raise Swgr2rbError, e.message
49
+ end
50
+
51
+ def parse_swagger_path_from_args(args)
52
+ path = args[0]
53
+ if path.nil? || !(url?(path) || json_file_path?(path))
54
+ raise Swgr2rbError,
55
+ "Provided Swagger URL/file path '#{path}' is neither "\
56
+ 'a URL nor a path of an existing JSON file'
57
+ end
58
+ path.to_s
59
+ end
60
+
61
+ def define_banner(opts)
62
+ opts.banner = "Usage:\tswgr2rb SWAGGER_URL|FILE_PATH [OPTIONS]"
63
+ opts.separator("\nTo generate a new testing framework from scratch:\n\t"\
64
+ 'swgr2rb SWAGGER_URL|FILE_PATH --from-scratch'\
65
+ " [-c COMPONENT]\n\n"\
66
+ "To update an existing testing framework:\n\t"\
67
+ 'swgr2rb SWAGGER_URL|FILE_PATH [-t TARGET_DIR]'\
68
+ "[-c COMPONENT]\n\t"\
69
+ ' [--[no-]update-only] [--[no-]rewrite-schemas]')
70
+ opts.separator('')
71
+ opts.separator('Options:')
72
+ end
73
+
74
+ def define_target_dir_option(opts)
75
+ opts.on('-t TARGET_DIR', '--target-dir TARGET_DIR', String,
76
+ 'Target directory for endpoint object models',
77
+ "(the directory that contains components' folders).",
78
+ "Default: #{@params[:target_dir]}.") do |dir|
79
+ @params[:target_dir] = dir
80
+ end
81
+ end
82
+
83
+ def define_component_option(opts)
84
+ opts.on('-c COMPONENT', '--component COMPONENT', String,
85
+ 'Component name for endpoint classes. For a new',
86
+ 'project, a directory named like this will be created',
87
+ 'inside the target directory, and all the generated',
88
+ 'endpoint object models will be located inside.',
89
+ "Default: #{@params[:component]}.") do |component|
90
+ @params[:component] = component
91
+ end
92
+ end
93
+
94
+ def define_update_only_option(opts)
95
+ opts.on('--[no-]update-only', TrueClass,
96
+ 'Do not create new files, only update existing. This',
97
+ 'option is useful when there are new (previously',
98
+ 'untested) endpoints in Swagger. '\
99
+ "Default: #{@params[:update_only]}.") do |update_only|
100
+ @params[:update_only] = update_only
101
+ end
102
+ end
103
+
104
+ def define_rewrite_schemas_option(opts)
105
+ opts.on('--[no-]rewrite-schemas', TrueClass,
106
+ 'Rewrite schema modules (located in',
107
+ 'TARGET_DIR/COMPONENT/object_model_schemas)',
108
+ 'if they already exist. '\
109
+ "Default: #{@params[:rewrite_schemas]}.") do |rewrite_schemas|
110
+ @params[:rewrite_schemas] = rewrite_schemas
111
+ end
112
+ end
113
+
114
+ def define_from_scratch_option(opts)
115
+ opts.on('--from-scratch', TrueClass,
116
+ 'Generate new testing framework. Will create',
117
+ "a directory named 'harness' and generate the scaffold",
118
+ 'of the framework inside. '\
119
+ "Default: #{@params[:from_scratch]}.") do |from_scratch|
120
+ @params[:from_scratch] = from_scratch
121
+ end
122
+ end
123
+
124
+ def define_help_option(opts)
125
+ opts.on('-h', '--help', 'Prints this help') do
126
+ puts opts
127
+ exit
128
+ end
129
+ end
130
+
131
+ def url?(path)
132
+ URI.extract(path).present?
133
+ end
134
+
135
+ def json_file_path?(path)
136
+ path.end_with?('.json') && File.exist?(path)
137
+ end
138
+ end
139
+ end