diff --git a/.gitignore b/.gitignore index 80364be..59c9777 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ lefthook-local.yml /gemfiles/*gemfile* /spec/internal/log/*.log /spec/internal/pacts +test.log + diff --git a/Gemfile b/Gemfile index a419c01..92c1867 100644 --- a/Gemfile +++ b/Gemfile @@ -3,9 +3,3 @@ source ENV.fetch("RUBYGEMS_PUBLIC_SOURCE", "https://rubygems.org/") gemspec - -source ENV.fetch("RUBYGEMS_PRIVATE_SOURCE", "https://nexus.sbmt.io/repository/ruby-gems-sbermarket/") do - group :development, :test do - gem "sbmt-app" - end -end diff --git a/lib/sbmt/pact/version.rb b/lib/sbmt/pact/version.rb index 42f28a5..0fcb6e9 100644 --- a/lib/sbmt/pact/version.rb +++ b/lib/sbmt/pact/version.rb @@ -2,6 +2,6 @@ module Sbmt module Pact - VERSION = "0.11.1" + VERSION = "0.12.0" end end diff --git a/sbmt-pact.gemspec b/sbmt-pact.gemspec index 2fcf7dd..a7ed484 100644 --- a/sbmt-pact.gemspec +++ b/sbmt-pact.gemspec @@ -33,17 +33,17 @@ Gem::Specification.new do |spec| spec.add_dependency "zeitwerk", "~> 2.3" spec.add_dependency "pact-ffi", "~> 0.4.22" + spec.add_dependency "rack", "~> 2.0" spec.add_dependency "webrick" spec.add_dependency "rack-proxy" spec.add_development_dependency "appraisal", ">= 2.4" spec.add_development_dependency "bundler", ">= 2.3" spec.add_development_dependency "combustion", ">= 1.3" + spec.add_development_dependency "gruf", ">= 2.18" spec.add_development_dependency "rake", ">= 13.0" - spec.add_development_dependency "sbmt-app", ">= 1.43.1" spec.add_development_dependency "sbmt-kafka_consumer", ">= 2.0.1" spec.add_development_dependency "sbmt-kafka_producer", ">= 1.0" - spec.add_development_dependency "dry-monads", "~> 1.3" spec.add_development_dependency "rspec" spec.add_development_dependency "rspec-rails" spec.add_development_dependency "rspec_junit_formatter" @@ -53,6 +53,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rubocop-performance" spec.add_development_dependency "standard", ">= 1.35.1" spec.add_development_dependency "vcr", ">= 6.0" + spec.add_development_dependency "faraday", "> 1.0" spec.add_development_dependency "webmock", ">= 3.0" spec.add_development_dependency "gruf-rspec", ">= 0.6.0" end diff --git a/spec/internal/app/api_clients/pet_store/grpc/pet_store/v1/pets_api.rb b/spec/internal/app/api_clients/pet_store/grpc/pet_store/v1/pets_api.rb deleted file mode 100644 index f799b82..0000000 --- a/spec/internal/app/api_clients/pet_store/grpc/pet_store/v1/pets_api.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -module PetStore - module Grpc - module PetStore::V1 - # You can use this class to call any GRPC methods declared - # in the `PetStore::Grpc::PetStore::V1::Pets::Service` GRPC service - # within the `deps/services/pet_store/grpc/pet_store.v1.proto` file - # For each GRPC method, an instance method named in CamelCase will be added to this class - # @example - # grpc_module = PetStore::Grpc::PetStore::V1 - # api = grpc_module::PetsApi.new - # # Suppose a contract has a `rpc GetSomeDataById (SomeRequest) returns (SomeResponse);` method - # result = api.get_some_data_by_id(grpc_module::SomeRequest.new(id: id) - # case result - # in Success(some_response) - # do_something(some_response.response_attr) - # in Failure(code, message) - # handle_error(code, message) - # end - class PetsApi < Sbmt::App::Grpc::Client::BaseApi - # You can override the generated methods for GRPC requests here, e.g.: - # def get_some_data_by_id(id) - # request = SomeRequest.new(id: id) - # - # super(request) - # end - end - end - end -end diff --git a/spec/internal/app/api_clients/pet_store/open_api.rb b/spec/internal/app/api_clients/pet_store/open_api.rb deleted file mode 100644 index d3e06b9..0000000 --- a/spec/internal/app/api_clients/pet_store/open_api.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -require "internal/config/configs/pet_store_open_api_config" -require_relative "open_api/v1" diff --git a/spec/internal/app/api_clients/pet_store/open_api/v1.rb b/spec/internal/app/api_clients/pet_store/open_api/v1.rb deleted file mode 100644 index 8df1aac..0000000 --- a/spec/internal/app/api_clients/pet_store/open_api/v1.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require Rails.root.join("pkg/client/pet_store/open_api/v1") - -module PetStore - module OpenApi - module V1 - CONFIG = PetStoreOpenApiConfig - - class ApiClient < Sbmt::App::OpenApi::ApiClient - end - end - end -end diff --git a/spec/internal/app/consumers/pet_json_consumer.rb b/spec/internal/app/consumers/pet_json_consumer.rb index 1bc5c4d..0bc7777 100644 --- a/spec/internal/app/consumers/pet_json_consumer.rb +++ b/spec/internal/app/consumers/pet_json_consumer.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "sbmt/kafka_consumer" - class PetJsonConsumer < Sbmt::KafkaConsumer::BaseConsumer def process_message(message) pet_id = message.payload["id"] diff --git a/spec/internal/app/consumers/pet_proto_consumer.rb b/spec/internal/app/consumers/pet_proto_consumer.rb index 4adf8f5..d4ee89c 100644 --- a/spec/internal/app/consumers/pet_proto_consumer.rb +++ b/spec/internal/app/consumers/pet_proto_consumer.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "sbmt/kafka_consumer" - class PetProtoConsumer < Sbmt::KafkaConsumer::BaseConsumer def process_message(message) Rails.logger.info "Pet ID: #{message.payload.id}" diff --git a/spec/internal/app/producers/pet_json_producer.rb b/spec/internal/app/producers/pet_json_producer.rb index 7887531..be42664 100644 --- a/spec/internal/app/producers/pet_json_producer.rb +++ b/spec/internal/app/producers/pet_json_producer.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "sbmt/kafka_producer" - class PetJsonProducer < Sbmt::KafkaProducer::BaseProducer option :topic, default: -> { "json-topic" } option :uuid, default: -> { SecureRandom.uuid } diff --git a/spec/internal/app/producers/pet_proto_producer.rb b/spec/internal/app/producers/pet_proto_producer.rb index eccf5b7..141b542 100644 --- a/spec/internal/app/producers/pet_proto_producer.rb +++ b/spec/internal/app/producers/pet_proto_producer.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "sbmt/kafka_producer" - class PetProtoProducer < Sbmt::KafkaProducer::BaseProducer option :topic, default: -> { "proto-topic" } option :uuid, default: -> { SecureRandom.uuid } diff --git a/spec/internal/app/rpc/pet_store/pet_store_controller.rb b/spec/internal/app/rpc/pet_store/pet_store_controller.rb index f3fc205..5cb069a 100644 --- a/spec/internal/app/rpc/pet_store/pet_store_controller.rb +++ b/spec/internal/app/rpc/pet_store/pet_store_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module PetStore - class PetStoreController < Sbmt::App::Gruf::Server::Controller + class PetStoreController < Gruf::Controllers::Base bind PetStore::Grpc::PetStore::V1::Pets::Service def pet_by_id diff --git a/spec/internal/config/configs/pet_store_grpc_config.rb b/spec/internal/config/configs/pet_store_grpc_config.rb deleted file mode 100644 index 6108af2..0000000 --- a/spec/internal/config/configs/pet_store_grpc_config.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -class PetStoreGrpcConfig < Sbmt::App::Grpc::Client::Config - config_name :pet_store_grpc - env_prefix :pet_store_grpc -end diff --git a/spec/internal/config/configs/pet_store_open_api_config.rb b/spec/internal/config/configs/pet_store_open_api_config.rb deleted file mode 100644 index a5d0efb..0000000 --- a/spec/internal/config/configs/pet_store_open_api_config.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -class PetStoreOpenApiConfig < Sbmt::App::OpenApi::Config - config_name :pet_store_open_api - env_prefix :pet_store_open_api -end diff --git a/spec/internal/config/grpc_server.yml b/spec/internal/config/grpc_server.yml deleted file mode 100644 index 62f4c63..0000000 --- a/spec/internal/config/grpc_server.yml +++ /dev/null @@ -1,16 +0,0 @@ -default: &default - binding_url: '0.0.0.0:3009' - pool_size: 30 - pool_keep_alive: 1 - -development: - <<: *default - -test: - <<: *default - -staging: - <<: *default - -production: - <<: *default diff --git a/spec/internal/config/initializers/grpc_server.rb b/spec/internal/config/initializers/grpc_server.rb index dfb235c..3cf1c08 100644 --- a/spec/internal/config/initializers/grpc_server.rb +++ b/spec/internal/config/initializers/grpc_server.rb @@ -1,4 +1,11 @@ # frozen_string_literal: true -Sbmt::App::Gruf::Server.configure! -Sbmt::App::Grpc.load_server_packages +::Gruf.interceptors.clear + +::Gruf.configure do |c| + c.server_binding_url = "0.0.0.0:3009" + c.logger = Rails.logger +end + +Rails.root.glob("pkg/server/**/*_services_pb.rb").sort.each { require _1 } +Rails.root.glob("app/rpc/**/*.rb").sort.each { require _1 } diff --git a/spec/internal/config/pet_store_open_api.yml b/spec/internal/config/pet_store_open_api.yml deleted file mode 100644 index 48cbe0d..0000000 --- a/spec/internal/config/pet_store_open_api.yml +++ /dev/null @@ -1,17 +0,0 @@ -default: &default - host: localhost - port: 3000 - -development: - <<: *default - -test: - <<: *default - -staging: - host: ".svc.cluster.local" - port: 8080 - -production: - host: ".svc.cluster.local" - port: 8080 diff --git a/spec/internal/configs/app.toml b/spec/internal/configs/app.toml deleted file mode 100644 index a990d58..0000000 --- a/spec/internal/configs/app.toml +++ /dev/null @@ -1,15 +0,0 @@ -name = "test-app" -version = "0.0.1" - -[team] -owner_team = "dex-1" -channel = "dev-ruby-platform" -maintainer_team = "dex-1" -BO = "aleksandr.susikov@sbermarket.ru" - -[env] - [env.APP_NAME] - type = "string" - value = "TEST-APP" - envName = "APP_NAME" - required = true diff --git a/spec/internal/pkg/client/pet_store/open_api/v1.rb b/spec/internal/pkg/client/pet_store/open_api/v1.rb deleted file mode 100644 index c34d4b4..0000000 --- a/spec/internal/pkg/client/pet_store/open_api/v1.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -module PetStore - module OpenApi - module V1 - Dir[File.join(__dir__, "v1/api/*.rb")].each { |f| require_dependency f } - Dir[File.join(__dir__, "v1/models/*.rb")].each { |f| require_dependency f } - end - end -end diff --git a/spec/internal/pkg/client/pet_store/open_api/v1/PetsApi.md b/spec/internal/pkg/client/pet_store/open_api/v1/PetsApi.md deleted file mode 100644 index 9f91d86..0000000 --- a/spec/internal/pkg/client/pet_store/open_api/v1/PetsApi.md +++ /dev/null @@ -1,119 +0,0 @@ -# PetStore::OpenApi::V1::PetsApi - -All URIs are relative to */api/v3* - -| Method | HTTP request | Description | -| ------ | ------------ | ----------- | -| [**pets_id_get**](PetsApi.md#pets_id_get) | **GET** /pets/{id} | | -| [**pets_id_patch**](PetsApi.md#pets_id_patch) | **PATCH** /pets/{id} | | - - -## pets_id_get - -> pets_id_get(id) - - - -### Examples - -```ruby -require 'time' -require 'pet_store_open_api_v1' - -api_instance = PetStore::OpenApi::V1::PetsApi.new -id = 56 # Integer | ID of pet to return - -result = api_instance.pets_id_get(id) -p result -``` - -#### Using the pets_id_get_with_http_info variant - -This returns an Array which contains the response data, status code and headers. - -> , Integer, Hash)> pets_id_get_with_http_info(id) - -```ruby - -data, status_code, headers = api_instance.pets_id_get_with_http_info(id) -p status_code # => 2xx -p headers # => { ... } -p data.value! # => -``` - -### Parameters - -| Name | Type | Description | Notes | -| ---- | ---- | ----------- | ----- | -| **id** | **Integer** | ID of pet to return | | - -### Return type - -[**Pet**](Pet.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: application/json - - -## pets_id_patch - -> pets_id_patch(id, opts) - - - -### Examples - -```ruby -require 'time' -require 'pet_store_open_api_v1' - -api_instance = PetStore::OpenApi::V1::PetsApi.new -id = 56 # Integer | ID of pet to return -opts = { - pet: PetStore::OpenApi::V1::Cat.new # Pet | -} - -result = api_instance.pets_id_patch(id, opts) -p result -``` - -#### Using the pets_id_patch_with_http_info variant - -This returns an Array which contains the response data, status code and headers. - -> , Integer, Hash)> pets_id_patch_with_http_info(id, opts) - -```ruby - -data, status_code, headers = api_instance.pets_id_patch_with_http_info(id, opts) -p status_code # => 2xx -p headers # => { ... } -p data.value! # => -``` - -### Parameters - -| Name | Type | Description | Notes | -| ---- | ---- | ----------- | ----- | -| **id** | **Integer** | ID of pet to return | | -| **pet** | [**Pet**](Pet.md) | | [optional] | - -### Return type - -[**Pet**](Pet.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: application/json -- **Accept**: application/json - diff --git a/spec/internal/pkg/client/pet_store/open_api/v1/api/pets_api.rb b/spec/internal/pkg/client/pet_store/open_api/v1/api/pets_api.rb deleted file mode 100644 index 1cfd4f8..0000000 --- a/spec/internal/pkg/client/pet_store/open_api/v1/api/pets_api.rb +++ /dev/null @@ -1,149 +0,0 @@ -=begin -#Swagger Petstore - OpenAPI 3.0 - -#This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. Some useful links: - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) - -The version of the OpenAPI document: 1.0.4 -Contact: apiteam@swagger.io -Generated by: https://openapi-generator.tech -OpenAPI Generator version: 7.3.0 - -=end - -require 'cgi' - -module PetStore::OpenApi::V1 - class PetsApi - attr_accessor :api_client - - def initialize(api_client = ApiClient.default) - @api_client = api_client - end - # @param id [Integer] ID of pet to return - # @param [Hash] opts the optional parameters - # @return [Pet] - def pets_id_get(id, opts = {}) - data, _status_code, _headers = pets_id_get_with_http_info(id, opts) - data - end - - # @param id [Integer] ID of pet to return - # @param [Hash] opts the optional parameters - # @return [Array<(Pet, Integer, Hash)>] Pet data, response status code and response headers - def pets_id_get_with_http_info(id, opts = {}) - if @api_client.config.debugging - @api_client.config.logger.debug 'Calling API: PetsApi.pets_id_get ...' - end - # verify the required parameter 'id' is set - if @api_client.config.client_side_validation && id.nil? - fail ArgumentError, "Missing the required parameter 'id' when calling PetsApi.pets_id_get" - end - # resource path - local_var_path = '/pets/{id}'.sub('{' + 'id' + '}', CGI.escape(id.to_s)) - - # query parameters - query_params = opts[:query_params] || {} - - # header parameters - header_params = opts[:header_params] || {} - # HTTP header 'Accept' (if needed) - header_params['Accept'] = @api_client.select_header_accept(['application/json']) - - # form parameters - form_params = opts[:form_params] || {} - - # http body (model) - post_body = opts[:debug_body] - - # return_type - return_type = opts[:debug_return_type] || 'Pet' - - # auth_names - auth_names = opts[:debug_auth_names] || [] - - new_options = opts.merge( - :operation => :"PetsApi.pets_id_get", - :header_params => header_params, - :query_params => query_params, - :form_params => form_params, - :body => post_body, - :auth_names => auth_names, - :return_type => return_type - ) - - data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options) - if @api_client.config.debugging - @api_client.config.logger.debug "API called: PetsApi#pets_id_get\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" - end - return data, status_code, headers - end - - # @param id [Integer] ID of pet to return - # @param [Hash] opts the optional parameters - # @option opts [Pet] :pet - # @return [Pet] - def pets_id_patch(id, opts = {}) - data, _status_code, _headers = pets_id_patch_with_http_info(id, opts) - data - end - - # @param id [Integer] ID of pet to return - # @param [Hash] opts the optional parameters - # @option opts [Pet] :pet - # @return [Array<(Pet, Integer, Hash)>] Pet data, response status code and response headers - def pets_id_patch_with_http_info(id, opts = {}) - if @api_client.config.debugging - @api_client.config.logger.debug 'Calling API: PetsApi.pets_id_patch ...' - end - # verify the required parameter 'id' is set - if @api_client.config.client_side_validation && id.nil? - fail ArgumentError, "Missing the required parameter 'id' when calling PetsApi.pets_id_patch" - end - # resource path - local_var_path = '/pets/{id}'.sub('{' + 'id' + '}', CGI.escape(id.to_s)) - - # query parameters - query_params = opts[:query_params] || {} - - # header parameters - header_params = opts[:header_params] || {} - # HTTP header 'Accept' (if needed) - header_params['Accept'] = @api_client.select_header_accept(['application/json']) - # HTTP header 'Content-Type' - content_type = @api_client.select_header_content_type(['application/json']) - if !content_type.nil? - header_params['Content-Type'] = content_type - end - - # form parameters - form_params = opts[:form_params] || {} - - # http body (model) - post_body = opts[:debug_body] || @api_client.object_to_http_body(opts[:'pet']) - - # return_type - return_type = opts[:debug_return_type] || 'Pet' - - # auth_names - auth_names = opts[:debug_auth_names] || [] - - new_options = opts.merge( - :operation => :"PetsApi.pets_id_patch", - :header_params => header_params, - :query_params => query_params, - :form_params => form_params, - :body => post_body, - :auth_names => auth_names, - :return_type => return_type - ) - - data, status_code, headers = @api_client.call_api(:PATCH, local_var_path, new_options) - if @api_client.config.debugging - @api_client.config.logger.debug "API called: PetsApi#pets_id_patch\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" - end - return data, status_code, headers - end - - ActiveSupport.run_load_hooks("pet_store/open_api/v1/pets_api", self) - end -end diff --git a/spec/internal/pkg/client/pet_store/open_api/v1/models/cat.rb b/spec/internal/pkg/client/pet_store/open_api/v1/models/cat.rb deleted file mode 100644 index 7a60b76..0000000 --- a/spec/internal/pkg/client/pet_store/open_api/v1/models/cat.rb +++ /dev/null @@ -1,228 +0,0 @@ -# #Swagger Petstore - OpenAPI 3.0 -# -# This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. Some useful links: - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) -# -# The version of the OpenAPI document: 1.0.4 -# Contact: apiteam@swagger.io -# Generated by: https://openapi-generator.tech -# OpenAPI Generator version: 7.3.0 -# - -require "date" -require "time" - -module PetStore::OpenApi::V1 - class Cat - attr_accessor :id - - attr_accessor :hunts - - attr_accessor :age - - # Attribute mapping from ruby-style variable name to JSON key. - def self.attribute_map - { - id: :id, - hunts: :hunts, - age: :age - } - end - - # Returns all the JSON keys this model knows about - def self.acceptable_attributes - attribute_map.values - end - - # Attribute type mapping. - def self.openapi_types - { - id: :Integer, - hunts: :Boolean, - age: :Integer - } - end - - # List of attributes with nullable: true - def self.openapi_nullable - Set.new([]) - end - - # Initializes the object - # @param [Hash] attributes Model attributes in the form of hash - def initialize(attributes = {}) - if !attributes.is_a?(Hash) - fail ArgumentError, "The input argument (attributes) must be a hash in `PetStore::OpenApi::V1::Cat` initialize method" - end - - # check to see if the attribute exists and convert string to symbol for hash key - attributes = attributes.each_with_object({}) { |(k, v), h| - if !self.class.attribute_map.key?(k.to_sym) - fail ArgumentError, "`#{k}` is not a valid attribute in `PetStore::OpenApi::V1::Cat`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect - end - h[k.to_sym] = v - } - - if attributes.key?(:id) - self.id = attributes[:id] - end - - if attributes.key?(:hunts) - self.hunts = attributes[:hunts] - end - - if attributes.key?(:age) - self.age = attributes[:age] - end - end - - # Show invalid properties with the reasons. Usually used together with valid? - # @return Array for valid properties with the reasons - def list_invalid_properties - warn "[DEPRECATED] the `list_invalid_properties` method is obsolete" - [] - end - - # Check to see if the all the properties in the model are valid - # @return true if the model is valid - def valid? - warn "[DEPRECATED] the `valid?` method is obsolete" - true - end - - # Checks equality by comparing each attribute. - # @param [Object] Object to be compared - def ==(other) - return true if equal?(other) - self.class == other.class && - id == other.id && - hunts == other.hunts && - age == other.age - end - - # @see the `==` method - # @param [Object] Object to be compared - def eql?(other) - self == other - end - - # Calculates hash code according to all attributes. - # @return [Integer] Hash code - def hash - [id, hunts, age].hash - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - attributes = attributes.transform_keys(&:to_sym) - transformed_hash = {} - openapi_types.each_pair do |key, type| - if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil? - transformed_hash[key.to_s] = nil - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[attribute_map[key]].is_a?(Array) - transformed_hash[key.to_s] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) } - end - elsif !attributes[attribute_map[key]].nil? - transformed_hash[key.to_s] = _deserialize(type, attributes[attribute_map[key]]) - end - end - new(transformed_hash) - end - - # Deserializes the data based on type - # @param string type Data type - # @param string template Value to be deserialized - # @return [Object] Deserialized data - def self._deserialize(type, value) - case type.to_sym - when :Time - Time.zone.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - {}.tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = PetStore::OpenApi::V1.const_get(type) - (klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of)) ? klass.build(value) : klass.build_from_hash(value) - end - end - - # Returns the string representation of the object - # @return [String] String presentation of the object - delegate :to_s, to: :to_hash - - # to_body is an alias to to_hash (backward compatibility) - # @return [Hash] Returns the object in the form of hash - def to_body - to_hash - end - - # Returns the object in the form of hash - # @return [Hash] Returns the object in the form of hash - def to_hash - hash = {} - self.class.attribute_map.each_pair do |attr, param| - value = send(attr) - if value.nil? - is_nullable = self.class.openapi_nullable.include?(attr) - next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}")) - end - - hash[param] = _to_hash(value) - end - hash - end - - # Outputs non-array value in the form of hash - # For object, use to_hash. Otherwise, just return the value - # @param [Object] value Any valid value - # @return [Hash] Returns the value in the form of hash - def _to_hash(value) - if value.is_a?(Array) - value.compact.map { |v| _to_hash(v) } - elsif value.is_a?(Hash) - {}.tap do |hash| - value.each { |k, v| hash[k] = _to_hash(v) } - end - elsif value.respond_to? :to_hash - value.to_hash - else - value - end - end - - include Sbmt::App::OpenApi::Model - - ActiveSupport.run_load_hooks("pet_store/open_api/v1/cat", self) - end -end diff --git a/spec/internal/pkg/client/pet_store/open_api/v1/models/dog.rb b/spec/internal/pkg/client/pet_store/open_api/v1/models/dog.rb deleted file mode 100644 index 19e6c9f..0000000 --- a/spec/internal/pkg/client/pet_store/open_api/v1/models/dog.rb +++ /dev/null @@ -1,262 +0,0 @@ -# #Swagger Petstore - OpenAPI 3.0 -# -# This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. Some useful links: - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) -# -# The version of the OpenAPI document: 1.0.4 -# Contact: apiteam@swagger.io -# Generated by: https://openapi-generator.tech -# OpenAPI Generator version: 7.3.0 -# - -require "date" -require "time" - -module PetStore::OpenApi::V1 - class Dog - attr_accessor :id - - attr_accessor :bark - - attr_accessor :breed - - class EnumAttributeValidator - attr_reader :datatype - attr_reader :allowable_values - - def initialize(datatype, allowable_values) - @allowable_values = allowable_values.map do |value| - case datatype.to_s - when /Integer/i - value.to_i - when /Float/i - value.to_f - else - value - end - end - end - - def valid?(value) - !value || allowable_values.include?(value) - end - end - - # Attribute mapping from ruby-style variable name to JSON key. - def self.attribute_map - { - id: :id, - bark: :bark, - breed: :breed - } - end - - # Returns all the JSON keys this model knows about - def self.acceptable_attributes - attribute_map.values - end - - # Attribute type mapping. - def self.openapi_types - { - id: :Integer, - bark: :Boolean, - breed: :String - } - end - - # List of attributes with nullable: true - def self.openapi_nullable - Set.new([]) - end - - # Initializes the object - # @param [Hash] attributes Model attributes in the form of hash - def initialize(attributes = {}) - if !attributes.is_a?(Hash) - fail ArgumentError, "The input argument (attributes) must be a hash in `PetStore::OpenApi::V1::Dog` initialize method" - end - - # check to see if the attribute exists and convert string to symbol for hash key - attributes = attributes.each_with_object({}) { |(k, v), h| - if !self.class.attribute_map.key?(k.to_sym) - fail ArgumentError, "`#{k}` is not a valid attribute in `PetStore::OpenApi::V1::Dog`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect - end - h[k.to_sym] = v - } - - if attributes.key?(:id) - self.id = attributes[:id] - end - - if attributes.key?(:bark) - self.bark = attributes[:bark] - end - - if attributes.key?(:breed) - self.breed = attributes[:breed] - end - end - - # Show invalid properties with the reasons. Usually used together with valid? - # @return Array for valid properties with the reasons - def list_invalid_properties - warn "[DEPRECATED] the `list_invalid_properties` method is obsolete" - [] - end - - # Check to see if the all the properties in the model are valid - # @return true if the model is valid - def valid? - warn "[DEPRECATED] the `valid?` method is obsolete" - breed_validator = EnumAttributeValidator.new("String", ["Dingo", "Husky", "Retriever", "Shepherd"]) - return false unless breed_validator.valid?(@breed) - true - end - - # Custom attribute writer method checking allowed values (enum). - # @param [Object] breed Object to be assigned - def breed=(breed) - validator = EnumAttributeValidator.new("String", ["Dingo", "Husky", "Retriever", "Shepherd"]) - unless validator.valid?(breed) - fail ArgumentError, "invalid value for \"breed\", must be one of #{validator.allowable_values}." - end - @breed = breed - end - - # Checks equality by comparing each attribute. - # @param [Object] Object to be compared - def ==(other) - return true if equal?(other) - self.class == other.class && - id == other.id && - bark == other.bark && - breed == other.breed - end - - # @see the `==` method - # @param [Object] Object to be compared - def eql?(other) - self == other - end - - # Calculates hash code according to all attributes. - # @return [Integer] Hash code - def hash - [id, bark, breed].hash - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - attributes = attributes.transform_keys(&:to_sym) - transformed_hash = {} - openapi_types.each_pair do |key, type| - if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil? - transformed_hash[key.to_s] = nil - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[attribute_map[key]].is_a?(Array) - transformed_hash[key.to_s] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) } - end - elsif !attributes[attribute_map[key]].nil? - transformed_hash[key.to_s] = _deserialize(type, attributes[attribute_map[key]]) - end - end - new(transformed_hash) - end - - # Deserializes the data based on type - # @param string type Data type - # @param string template Value to be deserialized - # @return [Object] Deserialized data - def self._deserialize(type, value) - case type.to_sym - when :Time - Time.zone.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - {}.tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = PetStore::OpenApi::V1.const_get(type) - (klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of)) ? klass.build(value) : klass.build_from_hash(value) - end - end - - # Returns the string representation of the object - # @return [String] String presentation of the object - delegate :to_s, to: :to_hash - - # to_body is an alias to to_hash (backward compatibility) - # @return [Hash] Returns the object in the form of hash - def to_body - to_hash - end - - # Returns the object in the form of hash - # @return [Hash] Returns the object in the form of hash - def to_hash - hash = {} - self.class.attribute_map.each_pair do |attr, param| - value = send(attr) - if value.nil? - is_nullable = self.class.openapi_nullable.include?(attr) - next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}")) - end - - hash[param] = _to_hash(value) - end - hash - end - - # Outputs non-array value in the form of hash - # For object, use to_hash. Otherwise, just return the value - # @param [Object] value Any valid value - # @return [Hash] Returns the value in the form of hash - def _to_hash(value) - if value.is_a?(Array) - value.compact.map { |v| _to_hash(v) } - elsif value.is_a?(Hash) - {}.tap do |hash| - value.each { |k, v| hash[k] = _to_hash(v) } - end - elsif value.respond_to? :to_hash - value.to_hash - else - value - end - end - - include Sbmt::App::OpenApi::Model - - ActiveSupport.run_load_hooks("pet_store/open_api/v1/dog", self) - end -end diff --git a/spec/internal/pkg/client/pet_store/open_api/v1/models/pet.rb b/spec/internal/pkg/client/pet_store/open_api/v1/models/pet.rb deleted file mode 100644 index 25bfff5..0000000 --- a/spec/internal/pkg/client/pet_store/open_api/v1/models/pet.rb +++ /dev/null @@ -1,101 +0,0 @@ -# #Swagger Petstore - OpenAPI 3.0 -# -# This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3. Some useful links: - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) -# -# The version of the OpenAPI document: 1.0.4 -# Contact: apiteam@swagger.io -# Generated by: https://openapi-generator.tech -# OpenAPI Generator version: 7.3.0 -# - -require "date" -require "time" - -module PetStore::OpenApi::V1 - module Pet - class << self - # List of class defined in oneOf (OpenAPI v3) - def openapi_one_of - [ - :Cat, - :Dog - ] - end - - # Builds the object - # @param [Mixed] Data to be matched against the list of oneOf items - # @return [Object] Returns the model or the data itself - def build(data) - # Go through the list of oneOf items and attempt to identify the appropriate one. - # Note: - # - We do not attempt to check whether exactly one item matches. - # - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 }) - # due to the way the deserialization is made in the base_object template (it just casts without verifying). - # - TODO: scalar values are de facto behaving as if they were nullable. - # - TODO: logging when debugging is set. - openapi_one_of.each do |klass| - next if klass == :AnyType # "nullable: true" - typed_data = find_and_cast_into_type(klass, data) - return typed_data if typed_data - rescue # rescue all errors so we keep iterating even if the current item lookup raises - end - - openapi_one_of.include?(:AnyType) ? data : nil - end - - private - - SchemaMismatchError = Class.new(StandardError) - - # Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse. - def find_and_cast_into_type(klass, data) - return if data.nil? - - case klass.to_s - when "Boolean" - return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass) - when "Float" - return data if data.instance_of?(Float) - when "Integer" - return data if data.instance_of?(Integer) - when "Time" - return Time.zone.parse(data) - when "Date" - return Date.parse(data) - when "String" - return data if data.instance_of?(String) - when "Object" # "type: object" - return data if data.instance_of?(Hash) - when /\AArray<(?.+)>\z/ # "type: array" - if data.instance_of?(Array) - sub_type = Regexp.last_match[:sub_type] - return data.map { |item| find_and_cast_into_type(sub_type, item) } - end - when /\AHash.+)>\z/ # "type: object" with "additionalProperties: { ... }" - if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) } - sub_type = Regexp.last_match[:sub_type] - return data.each_with_object({}) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) } - end - else # model - const = PetStore::OpenApi::V1.const_get(klass) - if const - if const.respond_to?(:openapi_one_of) # nested oneOf model - model = const.build(data) - else - # raise if data contains keys that are not known to the model - raise if const.respond_to?(:acceptable_attributes) && !(data.keys - const.acceptable_attributes).empty? - model = const.build_from_hash(data) - end - return model if model - end - end - - raise # if no match by now, raise - rescue - raise SchemaMismatchError, "#{data} doesn't match the #{klass} type" - end - end - - ActiveSupport.run_load_hooks("pet_store/open_api/v1/pet", self) - end -end diff --git a/spec/pact/providers/sbmt-pact-test-app/grpc_client_spec.rb b/spec/pact/providers/sbmt-pact-test-app/grpc_client_spec.rb index 9b45cd5..de0471c 100644 --- a/spec/pact/providers/sbmt-pact-test-app/grpc_client_spec.rb +++ b/spec/pact/providers/sbmt-pact-test-app/grpc_client_spec.rb @@ -1,17 +1,14 @@ # frozen_string_literal: true require "sbmt/pact/rspec" -require "internal/config/configs/pet_store_grpc_config" RSpec.describe "Sbmt::Pact::Providers::Test::GrpcClient", :pact do - include Anyway::Testing::Helpers - has_grpc_pact_between "sbmt-pact-test-app", "sbmt-pact-test-app" let(:pet_id) { 123 } - let(:api) { PetStore::Grpc::PetStore::V1::PetsApi.new } - let(:make_request) { api.pet_by_id(id: pet_id) } + let(:api) { ::PetStore::Grpc::PetStore::V1::Pets::Stub.new("localhost:3009", :this_channel_is_insecure) } + let(:make_request) { api.pet_by_id(PetStore::Grpc::PetStore::V1::PetByIdRequest.new(id: pet_id)) } let(:interaction) do new_interaction @@ -33,7 +30,7 @@ it "executes the pact test without errors" do interaction.execute do - expect(make_request).to be_success + expect { make_request }.not_to raise_error end end end diff --git a/spec/pact/providers/sbmt-pact-test-app/http_client_spec.rb b/spec/pact/providers/sbmt-pact-test-app/http_client_spec.rb index c375bce..715faaa 100644 --- a/spec/pact/providers/sbmt-pact-test-app/http_client_spec.rb +++ b/spec/pact/providers/sbmt-pact-test-app/http_client_spec.rb @@ -1,19 +1,24 @@ # frozen_string_literal: true require "sbmt/pact/rspec" -require "internal/config/configs/pet_store_open_api_config" RSpec.describe "Sbmt::Pact::Providers::Test::HttpClient", :pact do - include Anyway::Testing::Helpers - has_http_pact_between "sbmt-pact-test-app", "sbmt-pact-test-app" let(:pet_id) { 123 } - let(:api) { PetStore::OpenApi::V1::PetsApi.new } + let(:host) { "localhost:3000" } let(:interaction) { new_interaction } + let(:http_client) do + Faraday.new do |conn| + conn.response :json + conn.request :json + end + end context "with GET /pets/:id" do - let(:make_request) { api.pets_id_get(pet_id) } + let(:make_request) do + http_client.get("http://#{host}/pets/#{pet_id}") + end context "with successful interaction" do let(:interaction) do @@ -39,8 +44,10 @@ end context "with PATCH /pets" do - let(:make_request) { api.pets_id_patch(pet_id, pet: pet, header_params: {"Authorization" => "some-token"}) } - let(:pet) { PetStore::OpenApi::V1::Dog.new(pet_data) } + let(:make_request) do + http_client.patch("http://#{host}/pets/#{pet_id}", pet_data.to_json, + {"Authorization" => "some-token"}) + end let(:pet_data) { {breed: "Shepherd"} } context "with successful interaction" do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 192a165..4b214bf 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -9,7 +9,10 @@ require "webmock" require "vcr" +require "faraday" +require "gruf" require "gruf/rspec" +require "yabeda" # we have to require it becase of this https://github.com/yabeda-rb/yabeda/pull/38 require "combustion" @@ -26,6 +29,11 @@ end require "rspec/rails" + # Add additional requires below this line. Rails is not loaded until this point! Dir["#{__dir__}/support/**/*.rb"].sort.each { |f| require f } + +# Optional dependencies +require "sbmt/kafka_consumer" +require "sbmt/kafka_producer" diff --git a/spec/sbmt/pact/provider/gruf_server_spec.rb b/spec/sbmt/pact/provider/gruf_server_spec.rb index 7e729de..15e77c0 100644 --- a/spec/sbmt/pact/provider/gruf_server_spec.rb +++ b/spec/sbmt/pact/provider/gruf_server_spec.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -require "internal/config/configs/pet_store_grpc_config" - describe Sbmt::Pact::Provider::GrufServer do - let(:api) { PetStore::Grpc::PetStore::V1::PetsApi.new } + let(:api) { ::PetStore::Grpc::PetStore::V1::Pets::Stub.new("localhost:3009", :this_channel_is_insecure) } let(:call_rpc) do subject.run { api.pet_by_id(PetStore::Grpc::PetStore::V1::PetByIdRequest.new(id: 1)) } end context "when success" do it "succeeds" do - result = call_rpc - expect(result).to be_success + resp = call_rpc - resp = result.value! expect(resp.pet.id).to eq 1 expect(resp.pet.name).to eq "Jack" end diff --git a/spec/sbmt/pact/provider/pact_broker_proxy_runner_spec.rb b/spec/sbmt/pact/provider/pact_broker_proxy_runner_spec.rb index bf3f5ea..3f3896e 100644 --- a/spec/sbmt/pact/provider/pact_broker_proxy_runner_spec.rb +++ b/spec/sbmt/pact/provider/pact_broker_proxy_runner_spec.rb @@ -3,7 +3,6 @@ describe Sbmt::Pact::Provider::PactBrokerProxyRunner do let(:http_client) do Faraday.new do |conn| - Sbmt::App::Http.configure_faraday(conn, name: "http-client") conn.response :json conn.request :json end diff --git a/spec/sbmt/pact/provider/provider_server_runner_spec.rb b/spec/sbmt/pact/provider/provider_server_runner_spec.rb index 1eb1608..acaffcf 100644 --- a/spec/sbmt/pact/provider/provider_server_runner_spec.rb +++ b/spec/sbmt/pact/provider/provider_server_runner_spec.rb @@ -3,7 +3,6 @@ describe Sbmt::Pact::Provider::ProviderServerRunner do let(:http_client) do Faraday.new do |conn| - Sbmt::App::Http.configure_faraday(conn, name: "http-client") conn.response :json conn.request :json end