swgr2rb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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