From e0f1c952f34b2f2c5d745ad549ce84d6dd42a02c Mon Sep 17 00:00:00 2001 From: Matt Muller <53055821+mullermp@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:47:44 -0400 Subject: [PATCH] Add customizations hook (#218) --- Rakefile | 6 +- .../projections/rails_json/lib/rails_json.rb | 4 +- .../projections/rpcv2_cbor/lib/rpcv2_cbor.rb | 4 +- .../white_label/lib/white_label.rb | 4 +- .../lib/white_label/customization.rb | 9 + .../lib/white_label/customizations.rb | 3 + .../white_label/spec/customizations_spec.rb | 13 + .../spec/event_stream_integration_spec.rb | 6 +- .../white_label/spec/spec_helper.rb | 102 +---- .../smithy-ruby-codegen-test/build.gradle.kts | 19 +- .../integration-specs/auth_spec.rb | 418 ------------------ .../integration-specs/client_spec.rb | 75 ---- .../integration-specs/compression_spec.rb | 113 ----- .../integration-specs/config_spec.rb | 49 -- .../integration-specs/endpoints_spec.rb | 60 --- .../integration-specs/errors_spec.rb | 71 --- .../event_stream_integration_spec.rb | 217 --------- .../event_stream_stubs_spec.rb | 328 -------------- .../integration-specs/interceptor_spec.rb | 89 ---- .../integration-specs/middleware_spec.rb | 119 ----- .../integration-specs/paginators_spec.rb | 191 -------- .../integration-specs/params_spec.rb | 215 --------- .../integration-specs/plugin_spec.rb | 44 -- .../integration-specs/retry_spec.rb | 35 -- .../integration-specs/spec_helper.rb | 102 ----- .../integration-specs/streaming_spec.rb | 144 ------ .../integration-specs/stubs_spec.rb | 39 -- .../integration-specs/telemetry_spec.rb | 179 -------- .../integration-specs/types_spec.rb | 81 ---- .../integration-specs/validators_spec.rb | 258 ----------- .../integration-specs/waiters_spec.rb | 73 --- .../ruby/codegen/DirectedRubyCodegen.java | 5 +- .../codegen/generators/ModuleGenerator.java | 22 +- .../spec/hearth/middleware/endpoint_spec.rb | 2 +- 34 files changed, 67 insertions(+), 3032 deletions(-) create mode 100644 codegen/projections/white_label/lib/white_label/customization.rb create mode 100644 codegen/projections/white_label/lib/white_label/customizations.rb create mode 100644 codegen/projections/white_label/spec/customizations_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/auth_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/client_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/compression_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/config_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/endpoints_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/errors_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/event_stream_integration_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/event_stream_stubs_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/interceptor_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/middleware_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/paginators_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/params_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/plugin_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/retry_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/spec_helper.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/streaming_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/stubs_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/telemetry_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/types_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/validators_spec.rb delete mode 100644 codegen/smithy-ruby-codegen-test/integration-specs/waiters_spec.rb diff --git a/Rakefile b/Rakefile index 70ecede78..8565a87aa 100644 --- a/Rakefile +++ b/Rakefile @@ -1,8 +1,8 @@ # frozen_string_literal: true -$white_label_dir = 'codegen/smithy-ruby-codegen-test/build/smithyprojections/smithy-ruby-codegen-test/white-label/ruby-codegen/white_label' -$rpcv2_cbor_dir = 'codegen/smithy-ruby-codegen-test/build/smithyprojections/smithy-ruby-codegen-test/rpcv2cbor/ruby-codegen/rpcv2_cbor' -$rails_json_dir = 'codegen/smithy-ruby-rails-codegen-test/build/smithyprojections/smithy-ruby-rails-codegen-test/railsjson/ruby-codegen/rails_json' +$white_label_dir = 'codegen/projections/white_label' +$rpcv2_cbor_dir = 'codegen/projections/rpcv2_cbor' +$rails_json_dir = 'codegen/projections/rails_json' Dir.glob("tasks/**/*.rake").each do |task_file| load(task_file) diff --git a/codegen/projections/rails_json/lib/rails_json.rb b/codegen/projections/rails_json/lib/rails_json.rb index 20ae9960e..051d2b805 100644 --- a/codegen/projections/rails_json/lib/rails_json.rb +++ b/codegen/projections/rails_json/lib/rails_json.rb @@ -8,7 +8,6 @@ # WARNING ABOUT GENERATED CODE require 'hearth' - require_relative 'rails_json/auth' require_relative 'rails_json/builders' require_relative 'rails_json/client' @@ -24,6 +23,9 @@ require_relative 'rails_json/types' require_relative 'rails_json/validators' require_relative 'rails_json/waiters' +begin + require_relative 'rails_json/customizations' +rescue LoadError; end module RailsJson VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip diff --git a/codegen/projections/rpcv2_cbor/lib/rpcv2_cbor.rb b/codegen/projections/rpcv2_cbor/lib/rpcv2_cbor.rb index 93bdc4cb2..58995bdf9 100644 --- a/codegen/projections/rpcv2_cbor/lib/rpcv2_cbor.rb +++ b/codegen/projections/rpcv2_cbor/lib/rpcv2_cbor.rb @@ -8,7 +8,6 @@ # WARNING ABOUT GENERATED CODE require 'hearth' - require_relative 'rpcv2_cbor/auth' require_relative 'rpcv2_cbor/builders' require_relative 'rpcv2_cbor/client' @@ -24,6 +23,9 @@ require_relative 'rpcv2_cbor/types' require_relative 'rpcv2_cbor/validators' require_relative 'rpcv2_cbor/waiters' +begin + require_relative 'rpcv2_cbor/customizations' +rescue LoadError; end module Rpcv2Cbor VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip diff --git a/codegen/projections/white_label/lib/white_label.rb b/codegen/projections/white_label/lib/white_label.rb index 545cd6282..32ee6ff28 100644 --- a/codegen/projections/white_label/lib/white_label.rb +++ b/codegen/projections/white_label/lib/white_label.rb @@ -8,7 +8,6 @@ # WARNING ABOUT GENERATED CODE require 'hearth' - require_relative 'white_label/auth' require_relative 'white_label/builders' require_relative 'white_label/client' @@ -25,6 +24,9 @@ require_relative 'white_label/validators' require_relative 'white_label/waiters' require_relative 'white_label/event_stream' +begin + require_relative 'white_label/customizations' +rescue LoadError; end module WhiteLabel VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip diff --git a/codegen/projections/white_label/lib/white_label/customization.rb b/codegen/projections/white_label/lib/white_label/customization.rb new file mode 100644 index 000000000..02fc068a9 --- /dev/null +++ b/codegen/projections/white_label/lib/white_label/customization.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module WhiteLabel + class Customization + def self.customization? + true + end + end +end diff --git a/codegen/projections/white_label/lib/white_label/customizations.rb b/codegen/projections/white_label/lib/white_label/customizations.rb new file mode 100644 index 000000000..deb170b1e --- /dev/null +++ b/codegen/projections/white_label/lib/white_label/customizations.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative 'customization' \ No newline at end of file diff --git a/codegen/projections/white_label/spec/customizations_spec.rb b/codegen/projections/white_label/spec/customizations_spec.rb new file mode 100644 index 000000000..6f4dd98d8 --- /dev/null +++ b/codegen/projections/white_label/spec/customizations_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative 'spec_helper' + +module WhiteLabel + describe Customization do + describe '#customization?' do + it 'exists and returns true' do + expect(Customization.customization?).to eq(true) + end + end + end +end diff --git a/codegen/projections/white_label/spec/event_stream_integration_spec.rb b/codegen/projections/white_label/spec/event_stream_integration_spec.rb index ea0e8933c..3b40c2ba6 100644 --- a/codegen/projections/white_label/spec/event_stream_integration_spec.rb +++ b/codegen/projections/white_label/spec/event_stream_integration_spec.rb @@ -28,7 +28,7 @@ def start_mirror_event_server(port) conn = HTTP2::Server.new conn.on(:frame) do |bytes| - logger.info("SERVER -> #{bytes.inspect}") + # logger.info("SERVER -> #{bytes.inspect}") sock.write(bytes) unless sock.closed? end @@ -77,7 +77,7 @@ def start_mirror_event_server(port) end stream.on(:half_close) do - logger.info('SERVER HALF CLOSE') + # logger.info('SERVER HALF CLOSE') stream.data('', end_stream: true) stream.close end @@ -124,7 +124,7 @@ def start_mirror_event_server(port) client = WhiteLabel::Client.new( endpoint: "http://localhost:#{port}", http2_client: Hearth::HTTP2::Client.new( - debug_output: true, + debug_output: false, logger: logger ) ) diff --git a/codegen/projections/white_label/spec/spec_helper.rb b/codegen/projections/white_label/spec/spec_helper.rb index 364277ea4..b2b9c82a5 100644 --- a/codegen/projections/white_label/spec/spec_helper.rb +++ b/codegen/projections/white_label/spec/spec_helper.rb @@ -1,102 +1,14 @@ # frozen_string_literal: true -require 'white_label' - -# This file was generated by the `rspec --init` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. +# WARNING ABOUT GENERATED CODE # -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. +# This file was code generated using smithy-ruby. +# https://github.com/smithy-lang/smithy-ruby # -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. - config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end +# WARNING ABOUT GENERATED CODE - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. - config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. - mocks.verify_partial_doubles = true - end +$:.unshift(File.expand_path('../lib', __dir__)) - # This option will default to `:apply_to_host_groups` in RSpec 4 (and will - # have no way to turn it off -- the option exists only for backwards - # compatibility in RSpec 3). It causes shared context metadata to be - # inherited by the metadata hash of host groups and examples, rather than - # triggering implicit auto-inclusion in groups with matching metadata. - config.shared_context_metadata_behavior = :apply_to_host_groups +require 'white_label' - # The settings below are suggested to provide a good initial experience - # with RSpec, but feel free to customize to your heart's content. - # # This allows you to limit a spec run to individual examples or groups - # # you care about by tagging them with `:focus` metadata. When nothing - # # is tagged with `:focus`, all examples get run. RSpec also provides - # # aliases for `it`, `describe`, and `context` that include `:focus` - # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - # config.filter_run_when_matching :focus - # - # # Allows RSpec to persist some state between runs in order to support - # # the `--only-failures` and `--next-failure` CLI options. We recommend - # # you configure your source control system to ignore this file. - # config.example_status_persistence_file_path = "spec/examples.txt" - # - # # Limits the available syntax to the non-monkey patched syntax that is - # # recommended. For more details, see: - # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - # config.disable_monkey_patching! - # - # # This setting enables warnings. It's recommended, but in some cases may - # # be too noisy due to issues in dependencies. - # config.warnings = true - # - # # Many RSpec users commonly either run the entire suite or an individual - # # file, and it's useful to allow more verbose output when running an - # # individual spec file. - # if config.files_to_run.one? - # # Use the documentation formatter for detailed output, - # # unless a formatter has already been configured - # # (e.g. via a command-line flag). - # config.default_formatter = "doc" - # end - # - # # Print the 10 slowest examples and example groups at the - # # end of the spec run, to help surface which specs are running - # # particularly slow. - # config.profile_examples = 10 - # - # # Run specs in random order to surface order dependencies. If you find an - # # order dependency and want to debug it, you can fix the order by - # # providing the seed, which is printed after each run. - # # --seed 1234 - # config.order = :random - # - # # Seed global randomization in this process using the `--seed` CLI option. - # # Setting this allows you to use `--seed` to deterministically reproduce - # # test failures related to randomization by passing the same `--seed` - # # value as the one that triggered the failure. - # Kernel.srand config.seed -end +require 'rspec' diff --git a/codegen/smithy-ruby-codegen-test/build.gradle.kts b/codegen/smithy-ruby-codegen-test/build.gradle.kts index 7d7d2b02c..9642e3df9 100644 --- a/codegen/smithy-ruby-codegen-test/build.gradle.kts +++ b/codegen/smithy-ruby-codegen-test/build.gradle.kts @@ -146,29 +146,16 @@ tasks.register("generate-smithy-build") { } } - tasks.register("copyWhiteLabelGem") { - mustRunAfter("copyIntegrationSpecs") from("$buildDir/smithyprojections/smithy-ruby-codegen-test/white-label/ruby-codegen") into("$buildDir/../../projections/") } tasks.register("copyRpcv2CborGem") { - mustRunAfter("copyIntegrationSpecs") from("$buildDir/smithyprojections/smithy-ruby-codegen-test/rpcv2cbor/ruby-codegen") into("$buildDir/../../projections/") } -tasks.register("cleanProjections") { - delete("$buildDir/../../projections/white_label/") - delete("$buildDir/../../projections/rpcv2_cbor/") -} - -tasks.register("copyIntegrationSpecs") { - from("./integration-specs") - into("$buildDir/smithyprojections/smithy-ruby-codegen-test/white-label/ruby-codegen/white_label/spec") -} - tasks["smithyBuildJar"].enabled = false tasks.create("buildSdk") { @@ -176,14 +163,12 @@ tasks.create("buildSdk") { }.dependsOn(tasks["generate-smithy-build"]) tasks["build"] - .dependsOn( - // tasks["cleanProjections"], - tasks["buildSdk"]) + .dependsOn(tasks["buildSdk"]) .finalizedBy( - tasks["copyIntegrationSpecs"], tasks["copyWhiteLabelGem"], tasks["copyRpcv2CborGem"] ) + java.sourceSets["main"].java { srcDirs("model", "src/main/smithy") } diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/auth_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/auth_spec.rb deleted file mode 100644 index 2996539e8..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/auth_spec.rb +++ /dev/null @@ -1,418 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - module Auth - describe Params do - it 'is a struct with auth params' do - params = Auth::Params.new - expect(params).to respond_to(:operation_name) - expect(params).to respond_to(:custom_param) - end - end - - describe SCHEMES do - it 'is a constant with supported schemes' do - actual = Auth::SCHEMES.map(&:scheme_id) - expected = [ - 'smithy.api#httpApiKeyAuth', - 'smithy.api#httpBasicAuth', - 'smithy.api#httpBearerAuth', - 'smithy.api#httpDigestAuth', - 'smithy.api#noAuth', - 'smithy.ruby.tests#httpCustomAuth' - ] - expect(actual).to match_array(expected) - end - end - - describe Resolver do - context ':http_api_key_auth' do - it 'resolves httpApiKeyAuth' do - params = Params.new(operation_name: :http_api_key_auth) - options = subject.resolve(params) - expect(options.first.scheme_id).to eq('smithy.api#httpApiKeyAuth') - end - - it 'has signing properties' do - params = Params.new(operation_name: :http_api_key_auth) - options = subject.resolve(params) - expect(options.first.signer_properties) - .to eq(name: 'X-API-Key', in: 'header', scheme: 'Authorization') - end - end - - context ':http_basic_auth' do - it 'resolves httpBasicAuth' do - params = Params.new(operation_name: :http_basic_auth) - options = subject.resolve(params) - expect(options.first.scheme_id).to eq('smithy.api#httpBasicAuth') - end - end - - context ':http_bearer_auth' do - it 'resolves httpBearerAuth' do - params = Params.new(operation_name: :http_bearer_auth) - options = subject.resolve(params) - expect(options.first.scheme_id).to eq('smithy.api#httpBearerAuth') - end - end - - context ':http_digest_auth' do - it 'resolves httpDigestAuth' do - params = Params.new(operation_name: :http_digest_auth) - options = subject.resolve(params) - expect(options.first.scheme_id).to eq('smithy.api#httpDigestAuth') - end - end - - context ':no_auth' do - it 'resolves noAuth' do - params = Params.new(operation_name: :no_auth) - options = subject.resolve(params) - expect(options.first.scheme_id).to eq('smithy.api#noAuth') - end - end - - context ':custom_auth' do - it 'resolves httpCustomAuth' do - params = Params.new(operation_name: :custom_auth) - options = subject.resolve(params) - expect(options.first.scheme_id) - .to eq('smithy.ruby.tests#httpCustomAuth') - end - - it 'has signing properties' do - params = Params.new(operation_name: :custom_auth) - options = subject.resolve(params) - expect(options.first.signer_properties) - .to eq(static_value: 'static', model_value: 'signer') - end - - it 'has identity properties' do - params = Params.new(operation_name: :custom_auth) - options = subject.resolve(params) - expect(options.first.identity_properties) - .to eq(static_value: 'static', model_value: 'identity') - end - end - - context ':optional_auth' do - let(:auth_option_schemes) do - [ - 'smithy.api#httpApiKeyAuth', - 'smithy.api#httpBasicAuth', - 'smithy.api#httpBearerAuth', - 'smithy.api#httpDigestAuth', - 'smithy.ruby.tests#httpCustomAuth', - 'smithy.api#noAuth' - ] - end - - it 'resolves all auth including noAuth' do - params = Params.new(operation_name: :optional_auth) - options = subject.resolve(params) - expect(options.size).to eq(6) - expect(options.map(&:scheme_id)).to eq(auth_option_schemes) - end - end - - context ':ordered_auth' do - let(:auth_option_schemes) do - [ - 'smithy.api#httpBasicAuth', - 'smithy.api#httpDigestAuth', - 'smithy.api#httpBearerAuth', - 'smithy.api#httpApiKeyAuth' - ] - end - - it 'resolves all auth in order' do - params = Params.new(operation_name: :ordered_auth) - options = subject.resolve(params) - expect(options.size).to eq(4) - expect(options.map(&:scheme_id)).to eq(auth_option_schemes) - end - end - - context 'operation without auth traits' do - let(:auth_option_schemes) do - [ - 'smithy.api#httpApiKeyAuth', - 'smithy.api#httpBasicAuth', - 'smithy.api#httpBearerAuth', - 'smithy.api#httpDigestAuth', - 'smithy.ruby.tests#httpCustomAuth' - ] - end - - it 'resolves all auth without noAuth' do - params = Params.new(operation_name: :kitchen_sink) - options = subject.resolve(params) - expect(options.size).to eq(5) - expect(options.map(&:scheme_id)).to eq(auth_option_schemes) - end - end - end - end - - describe Config do - it 'validates identity resolvers', rbs_test: :skip do - msg = /to be in \[Hearth::IdentityProvider\], got String/ - expect do - Config.new(http_api_key_provider: 'foo').validate! - end.to raise_error(ArgumentError, msg) - - expect do - Config.new(http_bearer_provider: 'foo').validate! - end.to raise_error(ArgumentError, msg) - - expect do - Config.new(http_login_provider: 'foo').validate! - end.to raise_error(ArgumentError, msg) - - expect do - Config.new(http_custom_key_provider: 'foo').validate! - end.to raise_error(ArgumentError, msg) - end - - it 'does not set defaults' do - expect(subject.http_api_key_provider).to be(nil) - expect(subject.http_bearer_provider).to be(nil) - expect(subject.http_login_provider).to be(nil) - end - - context 'stub_responses' do - subject { Config.new(stub_responses: true) } - - it 'sets default identities' do - expect(subject.http_api_key_provider) - .to be_a(Hearth::IdentityProvider) - expect(subject.http_api_key_provider.identity) - .to be_a(Hearth::Identities::HTTPApiKey) - - expect(subject.http_bearer_provider) - .to be_a(Hearth::IdentityProvider) - expect(subject.http_bearer_provider.identity) - .to be_a(Hearth::Identities::HTTPBearer) - - expect(subject.http_login_provider) - .to be_a(Hearth::IdentityProvider) - expect(subject.http_login_provider.identity) - .to be_a(Hearth::Identities::HTTPLogin) - - expect(subject.http_custom_key_provider) - .to be_a(Hearth::IdentityProvider) - expect(subject.http_custom_key_provider.identity) - .to be_a(WhiteLabel::Auth::HTTPCustomKey) - end - end - end - - describe Client do - let(:identity_provider) do - Hearth::IdentityProvider.new(proc { identity }) - end - - let(:client) { Client.new(stub_responses: true, **config_hash) } - - describe '#http_api_key_auth' do - let(:config_hash) do - { http_api_key_provider: identity_provider } - end - - let(:identity) do - Hearth::Identities::HTTPApiKey.new(key: 'foo') - end - - let(:properties) do - { name: 'X-API-Key', in: 'header', scheme: 'Authorization' } - end - - it 'resolves httpApiKeyAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to eq(identity) - resolved - end - expect_any_instance_of(Hearth::Signers::HTTPApiKey).to receive(:sign) - .with(request: anything, identity: identity, properties: properties) - client.http_api_key_auth({}) - end - end - - describe '#http_basic_auth' do - let(:config_hash) do - { http_login_provider: identity_provider } - end - - let(:identity) do - Hearth::Identities::HTTPLogin.new(username: 'foo', password: 'bar') - end - - it 'resolves httpBasicAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to eq(identity) - resolved - end - expect_any_instance_of(Hearth::Signers::HTTPBasic).to receive(:sign) - .with(request: anything, identity: identity, properties: {}) - client.http_basic_auth({}) - end - end - - describe '#http_bearer_auth' do - let(:config_hash) do - { http_bearer_provider: identity_provider } - end - - let(:identity) do - Hearth::Identities::HTTPBearer.new(token: 'foo') - end - - it 'resolves httpBearerAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to eq(identity) - resolved - end - expect_any_instance_of(Hearth::Signers::HTTPBearer).to receive(:sign) - .with(request: anything, identity: identity, properties: {}) - client.http_bearer_auth({}) - end - end - - describe '#http_digest_auth' do - let(:config_hash) do - { http_login_provider: identity_provider } - end - - let(:identity) do - Hearth::Identities::HTTPLogin.new(username: 'foo', password: 'bar') - end - - it 'resolves httpDigestAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to eq(identity) - resolved - end - expect_any_instance_of(Hearth::Signers::HTTPDigest).to receive(:sign) - .with(request: anything, identity: identity, properties: {}) - client.http_digest_auth({}) - end - end - - describe '#custom_auth' do - let(:config_hash) do - { http_custom_key_provider: identity_provider } - end - - let(:identity) do - WhiteLabel::Auth::HTTPCustomKey.new(key: 'foo') - end - - let(:properties) do - { model_value: 'signer', static_value: 'static' } - end - - it 'resolves httpCustomAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to eq(identity) - resolved - end - expect_any_instance_of(WhiteLabel::Auth::HTTPCustomAuthSigner) - .to receive(:sign) - .with(request: anything, identity: identity, properties: properties) - client.custom_auth({}) - end - end - - describe '#optional_auth' do - context 'no resolvers' do - let(:config_hash) do - { - http_login_provider: nil, - http_bearer_provider: nil, - http_api_key_provider: nil, - http_custom_key_provider: nil - } - end - - it 'resolves noAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to be_a(Hearth::Identities::Anonymous) - resolved - end - client.optional_auth({}) - end - end - - context 'only anonymous auth scheme' do - # default identity resolvers are configured - let(:config_hash) do - { auth_schemes: [Hearth::AuthSchemes::Anonymous.new] } - end - - it 'resolves noAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to be_a(Hearth::Identities::Anonymous) - resolved - end - client.optional_auth({}) - end - end - end - - describe '#no_auth' do - # default identity resolvers are configured - let(:config_hash) { {} } - - it 'resolves noAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to be_a(Hearth::Identities::Anonymous) - resolved - end - client.no_auth({}) - end - end - - describe '#ordered_auth' do - let(:identity) do - Hearth::Identities::HTTPLogin.new(username: 'foo', password: 'bar') - end - - let(:config_hash) do - { - http_login_provider: identity_provider, - http_bearer_provider: nil, - http_api_key_provider: nil - } - end - - it 'resolves httpDigestAuth' do - expect_any_instance_of(Hearth::IdentityProvider).to receive(:identity) - .and_wrap_original do |m, *args| - resolved = m.call(*args) - expect(resolved).to eq(identity) - resolved - end - client.ordered_auth({}) - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/client_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/client_spec.rb deleted file mode 100644 index fa0316de2..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/client_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - let(:client) { Client.new(stub_responses: true) } - - it 'uses logger' do - expect(client.config.logger) - .to receive(:debug) - .with(anything) - .at_least(:once) - expect(client.config.logger) - .to receive(:info) - .with(anything) - .at_least(:once) - - client.kitchen_sink - end - - it 'validates config', rbs_test: :skip do - expect do - Client.new(stub_responses: 'false') - end.to raise_error(ArgumentError, /config\[:stub_responses\]/) - end - - context 'global config' do - after { Hearth.config = {} } - - it 'allows for global configuration' do - logger = Logger.new(IO::NULL, level: :debug) - Hearth.config[:logger] = logger - expect(client.config.logger).to eq(logger) - end - - it 'validates global config values', rbs_test: :skip do - Hearth.config[:logger] = 'logger' - expect do - Client.new - end.to raise_error(ArgumentError, /config\[:logger\]/) - end - - it 'is overridden by client config' do - Hearth.config[:logger] = Logger.new(IO::NULL, level: :debug) - logger = Logger.new(IO::NULL, level: :info) - client = Client.new(logger: logger) - expect(client.config.logger).to eq(logger) - end - end - - context 'operation overrides' do - it 'validates config', rbs_test: :skip do - expect do - client.kitchen_sink({}, endpoint: 1) - end.to raise_error(ArgumentError, /config\[:endpoint\]/) - end - - it 'uses config from options' do - operation_config = { endpoint: 'https://example.com' } - allow_any_instance_of(Config).to receive(:freeze) - expect_any_instance_of(Config) - .to receive(:merge).with(operation_config) - .and_call_original - client.kitchen_sink({}, operation_config) - end - - it 'raises when given stubs or stub responses' do - expect do - client.kitchen_sink({}, stub_responses: true) - end.to raise_error(ArgumentError, /stubs or stub_responses/) - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/compression_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/compression_spec.rb deleted file mode 100644 index 60345383b..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/compression_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Config do - context 'disable_request_compression' do - it 'raises when given an invalid input', rbs_test: :skip do - expect { Config.new(disable_request_compression: 'string').validate! } - .to raise_error( - ArgumentError, - 'Expected config[:disable_request_compression] ' \ - 'to be in [TrueClass, FalseClass], got String.' - ) - end - end - - context 'request_min_compression_size_bytes' do - it 'raises when given invalid integer' do - expect { Config.new(request_min_compression_size_bytes: -1).validate! } - .to raise_error( - ArgumentError, - 'Expected config[:request_min_compression_size_bytes] ' \ - 'to be between 0 to 10485760, got -1.' - ) - end - end - end - - describe Client do - let(:client) { Client.new(stub_responses: true) } - - context '#request_compression' do - it 'compresses the body and sets the Content-Encoding header' do - input_body = 'a' * 10_241 - proc = proc do |context| - uncompressed = Zlib::GzipReader.new(context.request.body) - expect(uncompressed.read).to eq(input_body) - expect(context.request.headers['Content-Encoding']).to eq('gzip') - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - - client.request_compression( - { body: input_body }, - interceptors: [interceptor] - ) - end - - it 'does not compress when body does not meet the minimum' do - input_body = 'Hello World' - proc = proc do |context| - expect(context.request.body.read).to eq(input_body) - expect(context.request.headers['Content-Encoding']).to be_nil - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - - client.request_compression( - { body: input_body }, - interceptors: [interceptor] - ) - end - end - - context '#request_compression_streaming' do - it 'compresses the streaming body and sets the Content-Encoding header' do - streaming_input = StringIO.new('Hello World') - proc = proc do |context| - expect(context.request.headers['Content-Encoding']).to eq('gzip') - # capture the body by reading it into a new IO object - body = StringIO.new - # IO.copy_stream is the same method used by Net::Http - # to write our body to the socket - IO.copy_stream(context.request.body, body) - body.rewind - streaming_input.rewind - uncompressed = Zlib::GzipReader.new(body) - expect(uncompressed.read).to eq(streaming_input.read) - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - - client.request_compression_streaming( - { body: streaming_input }, - interceptors: [interceptor] - ) - end - - it 'compresses the streaming pipe body' do - raw_body = 'a' * 10_241 - rd, wr = IO.pipe - wr.write(raw_body) - wr.close - proc = proc do |context| - expect(context.request.headers['Content-Encoding']).to eq('gzip') - # capture the body by reading it into a new IO object - body = StringIO.new - # IO.copy_stream is the same method used by Net::Http - # to write our body to the socket - IO.copy_stream(context.request.body, body) - body.rewind - uncompressed = Zlib::GzipReader.new(body) - expect(uncompressed.read).to eq(raw_body) - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - - client.request_compression_streaming( - { body: rd }, - interceptors: [interceptor] - ) - rd.close - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/config_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/config_spec.rb deleted file mode 100644 index 1dbf728cb..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/config_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Config do - describe '#initialize' do - it 'sets member values' do - config_keys = { - disable_host_prefix: true, - endpoint: 'test', - http_client: Hearth::HTTP::Client.new, - logger: Logger.new($stdout), - retry_strategy: Hearth::Retry::Adaptive.new, - stub_responses: true, - validate_input: false, - telemetry_provider: Hearth::Telemetry::NoOpTelemetryProvider.new - } - - config = Config.new(**config_keys) - - config_keys.each do |key, value| - expect(config.send(key)).to eq(value) - end - end - - it 'uses defaults' do - config = Config.new - expect(config.interceptors).to be_a(Hearth::InterceptorList) - expect(config.logger).to be_a(Logger) - expect(config.plugins).to be_a(Hearth::PluginList) - expect(config.request_min_compression_size_bytes).to be_a(Integer) - expect(config.telemetry_provider) - .to be_a(Hearth::Telemetry::NoOpTelemetryProvider) - end - - it 'validates types', rbs_test: :skip do - config = Config.new(logger: 'foo') - expect { config.validate! } - .to raise_error(ArgumentError, /config\[:logger\]/) - end - - it 'raises on unknown keys' do - expect { Config.new(foo: 'bar') } - .to raise_error(ArgumentError, /config\[:foo\]/) - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/endpoints_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/endpoints_spec.rb deleted file mode 100644 index efa6936cd..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/endpoints_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - let(:client) { Client.new(stub_responses: true, validate_input: false) } - - describe '#endpoint_operation' do - it 'prepends to the host' do - proc = proc do |context| - expect(context.request.uri.to_s).to include('foo') - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - client.endpoint_operation({}, interceptors: [interceptor]) - end - end - - describe '#endpoint_with_host_label_operation' do - let(:label) { 'input_label' } - - it 'raises when missing host label member', rbs_test: :skip do - expect { client.endpoint_with_host_label_operation } - .to raise_error( - ArgumentError, - 'Host label label_member cannot be nil or empty.' - ) - end - - it 'prepends the label to the host' do - proc = proc do |context| - expect(context.request.uri.to_s).to include("foo.#{label}") - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - client.endpoint_with_host_label_operation( - { label_member: label }, - interceptors: [interceptor] - ) - end - - context 'endpoint from rules' do - let(:client) do - Client.new(stub_responses: true, endpoint: nil) - end - - it 'prepends the label to the host' do - proc = proc do |context| - expect(context.request.uri.to_s) - .to eq("https://foo.#{label}.data.whitelabel.com/") - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - client.endpoint_with_host_label_operation( - { label_member: label }, - interceptors: [interceptor] - ) - end - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/errors_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/errors_spec.rb deleted file mode 100644 index 773d4def4..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/errors_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - module Errors - describe ApiError do - it 'inherits the base protocol api error' do - error = ApiError.new(metadata: {}, - error_code: 'error') - expect(error).to be_a(Hearth::ApiError) - end - end - - describe ApiClientError do - it 'inherits the base client api error' do - error = ApiClientError.new(metadata: {}, - error_code: 'error') - expect(error).to be_a(ApiError) - end - end - - describe ApiServerError do - it 'inherits the base client api error' do - error = ApiServerError.new(metadata: {}, - error_code: 'error') - expect(error).to be_a(ApiError) - end - end - - describe ApiRedirectError do - it 'inherits the base client api error' do - error = ApiRedirectError.new( - location: 'location', - metadata: {}, - error_code: 'error' - ) - expect(error).to be_a(ApiError) - end - - it 'stores a location' do - error = ApiRedirectError.new( - location: 'location', - error_code: 'error', - metadata: {}, - message: 'error message' - ) - expect(error.location).to eq('location') - end - end - - describe ClientError do - it 'is retryable without throttling' do - error = ClientError.new(data: Types::ClientError.new, - metadata: {}, - error_code: 'error') - expect(error.retryable?).to be true - expect(error.throttling?).to be false - end - end - - describe ServerError do - it 'is retryable with throttling' do - error = ServerError.new(data: Types::ServerError.new, metadata: {}, - error_code: 'error') - expect(error.retryable?).to be true - expect(error.throttling?).to be true - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/event_stream_integration_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/event_stream_integration_spec.rb deleted file mode 100644 index ea0e8933c..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/event_stream_integration_spec.rb +++ /dev/null @@ -1,217 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -require 'timeout' - -def sock_eof?(sock) - sock.eof? -rescue StandardError - true -end - -# rubocop:disable Metrics -def start_mirror_event_server(port) - require 'socket' - require 'openssl' - require 'uri' - require 'http/2' - - server = TCPServer.new(port) - - logger = Logger.new($stdout) - $stdout.sync = true - - server_thread = Thread.new do - sock = server.accept - sock.setsockopt(:SOCKET, :RCVBUF, 2048) - conn = HTTP2::Server.new - - conn.on(:frame) do |bytes| - logger.info("SERVER -> #{bytes.inspect}") - sock.write(bytes) unless sock.closed? - end - - conn.on(:goaway) do - sock.close - end - - conn.on(:stream) do |stream| - message_decoder = Hearth::EventStream::Binary::MessageDecoder.new - message_encoder = Hearth::EventStream::Binary::MessageEncoder.new - - stream.on(:headers) do |_h| - # send a response back - stream.headers({ - ':status' => '200', - 'content-type' => 'application/vnd.amazon.eventstream' - }, end_stream: false) - end - - stream.on(:data) do |chunk| - loop do - message, empty = message_decoder.decode(chunk) - chunk = nil - if message - type = message.headers[':event-type']&.value - if type == 'initial-request' - message.headers[':event-type'] = - Hearth::EventStream::HeaderValue.new(value: 'initial-response', - type: 'string') - end - - # an empty message means close stream, don't mirror it - # payload.empty? does NOT work here, skip rubocop suggestion for it - # rubocop:disable Style/NumericPredicate - # rubocop:disable Style/ZeroLengthPredicate - if !message.headers.empty? || message.payload.size > 0 - # rubocop:enable Style/NumericPredicate - # rubocop:enable Style/ZeroLengthPredicate - # mirror the message back - payload = message_encoder.encode(message) - stream.data(payload, end_stream: false) - end - end - break if empty - end - end - - stream.on(:half_close) do - logger.info('SERVER HALF CLOSE') - stream.data('', end_stream: true) - stream.close - end - end - - while !sock.closed? && !sock_eof?(sock) - data = sock.readpartial(16_384) - - begin - conn << data - rescue StandardError => e - puts "#{e.class} exception: #{e.message} - closing socket." - puts e.backtrace - logger.error("SERVER exception: #{e.inspect}") - sock.close - end - end - ensure - sock&.close - end - [server, server_thread] -end - -describe WhiteLabel do - let(:port) { 9041 } - - let(:event_message) { 'event_message' } - let(:event_header) { 'event_header' } - let(:initial_message) { 'initial_message' } - let(:complex_data) { { values: %w[a b c] } } - - it 'sends and receives event streams' do - # unless ENV['EVENT_STREAM_INTEGRATION_TEST'] - # msg = 'Skipping integration test, set EVENT_STREAM_INTEGRATION_TEST '\ - # 'to enable' - # skip(msg) - # end - - server, server_thread = start_mirror_event_server(port) - logger = Logger.new($stdout) - $stdout.sync = true - - Timeout.timeout(5) do - client = WhiteLabel::Client.new( - endpoint: "http://localhost:#{port}", - http2_client: Hearth::HTTP2::Client.new( - debug_output: true, - logger: logger - ) - ) - - handler = WhiteLabel::EventStream::StartEventStreamHandler.new - - event_queue = Thread::Queue.new - - handler.on_initial_response do |event| - event_queue << event - end - - handler.on_simple_event do |event| - event_queue << event - end - - handler.on_nested_event do |event| - event_queue << event - end - - handler.on_explicit_payload_event do |event| - event_queue << event - end - - unknown_events = Thread::Queue.new - # handler.on_unknown_event do |message| - # unknown_events << message - # end - - handler.on_error do |e| - msg = "Unexpected error in event stream parsing/handling: #{e.inspect}" - puts msg - raise msg - end - - stream = client.start_event_stream( - { - initial_structure: { - message: initial_message, - nested: complex_data - } - }, - event_stream_handler: handler - ) - initial_event = event_queue.pop - expect(initial_event) - .to be_a(WhiteLabel::Types::StartEventStreamOutput) - expect(initial_event.initial_structure.message).to eq(initial_message) - - stream.signal_simple_event(message: event_message) - simple_event = event_queue.pop - expect(simple_event) - .to be_a(WhiteLabel::Types::Events::SimpleEvent) - expect(simple_event.message).to eq(event_message) - - stream.signal_nested_event( - nested: complex_data, - header_a: event_header, - message: event_message - ) - nested_event = event_queue.pop - expect(nested_event).to be_a(WhiteLabel::Types::Events::NestedEvent) - expect(nested_event.nested.to_h).to eq(complex_data) - expect(nested_event.header_a).to eq(event_header) - expect(nested_event.message).to eq(event_message) - - stream.signal_explicit_payload_event( - header_a: event_header, payload: complex_data - ) - event = event_queue.pop - expect(event).to be_a(WhiteLabel::Types::Events::ExplicitPayloadEvent) - expect(event.header_a).to eq(event_header) - expect(event.payload.to_h).to eq(complex_data) - - stream.join - stream.kill - - # no unknown events received - expect(unknown_events.size).to eq(0) - end - rescue Timeout::Error - raise 'Event Stream integration test timed out. ' \ - 'This likely means one or more expected events were not ' \ - 'sent or received correctly.' - ensure - server_thread.kill - server&.close - end -end -# rubocop:enable Metrics diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/event_stream_stubs_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/event_stream_stubs_spec.rb deleted file mode 100644 index fbf52a536..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/event_stream_stubs_spec.rb +++ /dev/null @@ -1,328 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -describe WhiteLabel do - let(:event_message) { 'event_message' } - let(:event_header) { 'event_header' } - let(:initial_message) { 'initial_message' } - let(:complex_data) { { values: %w[a b c] } } - let(:event_handler) { WhiteLabel::EventStream::StartEventStreamHandler.new } - - subject do - WhiteLabel::Client.new(stub_responses: true) - end - - context 'event stub Message' do - let(:message) do - headers = { - ':message-type' => 'event', - ':event-type' => 'SimpleEvent' - } - headers.each do |k, v| - headers[k] = - Hearth::EventStream::HeaderValue.new(value: v, type: 'string') - end - Hearth::EventStream::Message.new( - headers: headers, - payload: StringIO.new('{"message":"event_message"}') - ) - end - - it 'signals the stubbed event' do - subject.stub_responses( - :start_event_stream, - { events: [message] } - ) - - events_handled = 0 - event_handler.on_simple_event do |event| - events_handled += 1 - expect(event) - .to be_a(WhiteLabel::Types::Events::SimpleEvent) - expect(event.message).to eq(event_message) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(events_handled).to eq(1) - end - end - - context 'error event stub Message' do - let(:error_code) { 'error_code' } - let(:error_message) { 'error_message' } - let(:message) do - headers = { - ':message-type' => 'error', - ':error-code' => error_code, - ':error-message' => error_message - } - headers.each do |k, v| - headers[k] = - Hearth::EventStream::HeaderValue.new(value: v, type: 'string') - end - Hearth::EventStream::Message.new( - headers: headers - ) - end - - it 'signals the stubbed error' do - subject.stub_responses( - :start_event_stream, - { events: [message] } - ) - - error_events = 0 - event_handler.on_error do |error| - error_events += 1 - expect(error).to be_a(WhiteLabel::Errors::ApiError) - expect(error.error_code).to eq(error_code) - expect(error.message).to eq(error_message) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(error_events).to eq(1) - end - end - - context 'SimpleEvent Type stub' do - let(:event) do - WhiteLabel::Types::SimpleEvent.new( - message: event_message - ) - end - - it 'signals the stubbed event' do - subject.stub_responses( - :start_event_stream, - { events: [event] } - ) - - events_handled = 0 - event_handler.on_simple_event do |event| - events_handled += 1 - expect(event) - .to be_a(WhiteLabel::Types::Events::SimpleEvent) - expect(event.message).to eq(event_message) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(events_handled).to eq(1) - end - end - - context 'multiple events' do - let(:simple_event) do - WhiteLabel::Types::SimpleEvent.new( - message: event_message - ) - end - - let(:nested_event) do - WhiteLabel::Params::NestedEvent.build( - { - nested: complex_data, - header_a: event_header, - message: event_message - }, - context: 'stub' - ) - end - - let(:explicit_payload_event) do - WhiteLabel::Params::ExplicitPayloadEvent.build( - { - header_a: event_header, - payload: complex_data - }, - context: 'stub' - ) - end - - it 'signals the stubbed events' do - subject.stub_responses( - :start_event_stream, - { - events: [ - simple_event, - nested_event, - explicit_payload_event - ] - } - ) - - events_handled = 0 - event_handler.on_simple_event do |event| - events_handled += 1 - expect(event) - .to be_a(WhiteLabel::Types::Events::SimpleEvent) - expect(event.message).to eq(event_message) - end - - event_handler.on_nested_event do |event| - events_handled += 1 - expect(event) - .to be_a(WhiteLabel::Types::Events::NestedEvent) - expect(event.message).to eq(event_message) - end - - event_handler.on_explicit_payload_event do |event| - events_handled += 1 - expect(event) - .to be_a(WhiteLabel::Types::Events::ExplicitPayloadEvent) - expect(event.header_a).to eq(event_header) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(events_handled).to eq(3) - end - end - - context 'initial response structure' do - it 'stubs the initial response' do - subject.stub_responses( - :start_event_stream, - { - initial_response: WhiteLabel::Types::StartEventStreamOutput.new( - initial_structure: WhiteLabel::Types::InitialStructure.new( - message: initial_message - ) - ) - } - ) - - events_handled = 0 - event_handler.on_initial_response do |event| - events_handled += 1 - expect(event).to be_a(WhiteLabel::Types::StartEventStreamOutput) - expect(event.initial_structure.message).to eq(initial_message) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(events_handled).to eq(1) - end - end - - context 'initial response hash' do - it 'stubs the initial response' do - subject.stub_responses( - :start_event_stream, - { - initial_response: { - initial_structure: { - message: initial_message - } - } - } - ) - - events_handled = 0 - event_handler.on_initial_response do |event| - events_handled += 1 - expect(event).to be_a(WhiteLabel::Types::StartEventStreamOutput) - expect(event.initial_structure.message).to eq(initial_message) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(events_handled).to eq(1) - end - end - - context 'initial response object' do - let(:initial_response) do - headers = { - ':message-type' => 'event', - ':event-type' => 'initial-response', - ':content-type' => 'application/json' - } - headers.each do |k, v| - headers[k] = - Hearth::EventStream::HeaderValue.new(value: v, type: 'string') - end - Hearth::HTTP2::Response.new( - status: 200, - body: Hearth::EventStream::Message.new( - headers: headers, - payload: StringIO.new('{"message":"initial_message"}') - ) - ) - end - it 'stubs the initial response' do - subject.stub_responses( - :start_event_stream, - { - initial_response: initial_response - } - ) - - events_handled = 0 - event_handler.on_initial_response do |event| - events_handled += 1 - expect(event).to be_a(WhiteLabel::Types::StartEventStreamOutput) - expect(event.initial_structure.message).to eq(initial_message) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(events_handled).to eq(1) - end - end - - context 'error response' do - it 'raises the error' do - subject.stub_responses( - :start_event_stream, - Hearth::HTTP2::ConnectionClosedError.new( - StandardError.new - ) - ) - - expect do - subject.start_event_stream({}, event_stream_handler: event_handler) - end.to raise_error(Hearth::HTTP2::ConnectionClosedError) - end - end - - context 'API error response' do - it 'signals the error' do - subject.stub_responses( - :start_event_stream, - WhiteLabel::Errors::ClientError.new( - data: WhiteLabel::Types::ClientError.new, - error_code: 'ClientError' - ) - ) - - errors_handled = 0 - event_handler.on_error do |error| - errors_handled += 1 - expect(error).to be_a(WhiteLabel::Errors::ClientError) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(errors_handled).to eq(1) - end - end - - context 'default stubs' do - let(:default_message) { 'message' } - - it 'stubs a default initial response and event' do - events_handled = 0 - event_handler.on_initial_response do |event| - events_handled += 1 - expect(event).to be_a(WhiteLabel::Types::StartEventStreamOutput) - expect(event.initial_structure.message).to eq(default_message) - end - - event_handler.on_simple_event do |event| - events_handled += 1 - expect(event) - .to be_a(WhiteLabel::Types::Events::SimpleEvent) - expect(event.message).to eq(default_message) - end - - subject.start_event_stream({}, event_stream_handler: event_handler) - expect(events_handled).to eq(2) - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/interceptor_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/interceptor_spec.rb deleted file mode 100644 index d98eb9394..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/interceptor_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - let(:interceptor_class) do - Class.new do - def initialize(name = 'NA') - @name = name - end - - def read_before_execution(context); end - end - end - - let(:interceptor) { interceptor_class.new } - let(:hook) { :read_before_execution } - - describe 'client configured interceptor' do - it 'calls interceptor hook' do - client = Client.new( - stub_responses: true, - interceptors: Hearth::InterceptorList.new([interceptor]) - ) - - expect(interceptor).to receive(hook) - .with(instance_of(Hearth::InterceptorContext)) - - client.kitchen_sink - end - end - - describe 'operation configured interceptor' do - it 'calls interceptor hook' do - client = Client.new(stub_responses: true) - - expect(interceptor).to receive(hook) - .with(instance_of(Hearth::InterceptorContext)) - - client.kitchen_sink({}, interceptors: [interceptor]) - end - end - - describe 'interceptor precedence' do - # * Interceptors registered via Class level plugins - # * Interceptors registered via config plugins (eg config.plugins) - # * Interceptors registered via config (eg, config.interceptors). - # * Interceptors registered via operation-level plugins. - # * Interceptors registered via operation-level options (passed directly). - - let(:config_plugin_interceptor) { interceptor_class.new('cfg_plg') } - let(:config_interceptor) { interceptor_class.new('cfg_int') } - let(:operation_plugin_interceptor) { interceptor_class.new('op_plg') } - let(:operation_interceptor) { interceptor_class.new('op') } - - let(:config_plugin) do - proc { |cfg| cfg.interceptors << config_plugin_interceptor } - end - - let(:operation_plugin) do - proc { |cfg| cfg.interceptors << operation_plugin_interceptor } - end - - let(:client) do - Client.new( - stub_responses: true, - plugins: Hearth::PluginList.new([config_plugin]), - interceptors: Hearth::InterceptorList.new([config_interceptor]) - ) - end - - it 'applies interceptors in expected order' do - expect(Plugins::TestPlugin::TEST_CLASS_INTERCEPTOR) - .to receive(hook).ordered - expect(config_plugin_interceptor).to receive(hook).ordered - expect(config_interceptor).to receive(hook).ordered - expect(operation_plugin_interceptor).to receive(hook).ordered - expect(operation_interceptor).to receive(hook).ordered - - client.kitchen_sink( - {}, - plugins: [operation_plugin], - interceptors: [operation_interceptor] - ) - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/middleware_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/middleware_spec.rb deleted file mode 100644 index abe5c3098..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/middleware_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - let(:client) { Client.new(stub_responses: true) } - - it 'uses auth resolver, schemes, and identity resolvers' do - expect(Hearth::Middleware::Auth) - .to receive(:new) - .with(anything, - auth_params: anything, - auth_resolver: client.config.auth_resolver, - auth_schemes: client.config.auth_schemes, - Hearth::Identities::HTTPLogin => - client.config.http_login_provider, - Hearth::Identities::HTTPBearer => - client.config.http_bearer_provider, - Hearth::Identities::HTTPApiKey => - client.config.http_api_key_provider, - Auth::HTTPCustomKey => - client.config.http_custom_key_provider) - .and_call_original - - client.kitchen_sink - end - - it 'uses disable_host_prefix' do - expect(Hearth::Middleware::HostPrefix) - .to receive(:new) - .with(anything, - disable_host_prefix: client.config.disable_host_prefix, - host_prefix: anything) - .and_call_original - - client.endpoint_operation - end - - it 'uses disable_request_compression and ' \ - 'request_min_compression_size_bytes' do - expect(Hearth::HTTP::Middleware::RequestCompression) - .to receive(:new) - .with(anything, - disable_request_compression: - client.config.disable_request_compression, - request_min_compression_size_bytes: - client.config.request_min_compression_size_bytes, - encodings: anything, - streaming: anything) - .and_call_original - - client.request_compression - end - - it 'uses endpoint and endpoint_resolver' do - expect(Hearth::Middleware::Endpoint) - .to receive(:new) - .with(anything, - endpoint: client.config.endpoint, - endpoint_resolver: client.config.endpoint_resolver, - param_builder: anything, - stage: anything) - .and_call_original - - client.kitchen_sink - end - - it 'uses stubs, stub_responses, and http client' do - expect(Hearth::Middleware::Send) - .to receive(:new) - .with(anything, - stubs: client.config.stubs, - stub_responses: client.config.stub_responses, - client: client.config.http_client, - stub_error_classes: anything, - stub_data_class: anything, - stub_message_encoder: anything, - event_handler: anything) - .and_call_original - - client.kitchen_sink - end - - it 'uses retry_strategy' do - expect(Hearth::Middleware::Retry) - .to receive(:new) - .with(anything, - retry_strategy: client.config.retry_strategy, - error_inspector_class: anything) - .and_call_original - - client.kitchen_sink - end - - it 'uses validate_input' do - expect(Hearth::Middleware::Validate) - .to receive(:new) - .with(anything, - validate_input: client.config.validate_input, - validator: anything) - .and_call_original - - client.kitchen_sink - end - - it 'allows a specific order of middleware to their relatives' do - output = client.relative_middleware - expect(output.metadata[:middleware_order]) - .to eq( - [ - WhiteLabel::Middleware::BeforeMiddleware, - WhiteLabel::Middleware::MidMiddleware, - WhiteLabel::Middleware::AfterMiddleware - ] - ) - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/paginators_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/paginators_spec.rb deleted file mode 100644 index 9a6b12b20..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/paginators_spec.rb +++ /dev/null @@ -1,191 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - module Paginators - describe PaginatorsTest do - let(:client) { Client.new } - let(:params) { { param: 'param' } } - let(:options) { { stub_responses: true } } - - subject { PaginatorsTest.new(client, params, options) } - let(:response1) do - Hearth::Output.new( - data: Types::PaginatorsTestOperationOutput.new( - next_token: 'foo', - items: %w[a b c] - ) - ) - end - let(:response2) do - Hearth::Output.new( - data: Types::PaginatorsTestOperationOutput.new( - next_token: 'bar', - items: %w[1 2 3] - ) - ) - end - let(:response3) do - Hearth::Output.new( - data: Types::PaginatorsTestOperationOutput.new(items: ['the end']) - ) - end - - describe '#pages' do - it 'yields page responses', rbs_test: :skip do - expect(client).to receive(:paginators_test) - .with({ param: 'param' }, options).and_return(response1) - expect(client).to receive(:paginators_test) - .with({ param: 'param', - next_token: 'foo' }, options).and_return(response2) - expect(client).to receive(:paginators_test) - .with({ param: 'param', - next_token: 'bar' }, options).and_return(response3) - - paginator = subject.pages - expect(paginator).to be_a(Enumerator) - page = paginator.next - expect(page).to eq(response1) - page = paginator.next - expect(page).to eq(response2) - page = paginator.next - expect(page).to eq(response3) - expect { paginator.next }.to raise_error(StopIteration) - end - - it 'does not modify original params', rbs_test: :skip do - expect(client).to receive(:paginators_test) - .with({ param: 'param' }, options).and_return(response1) - - original_params = params - paginator = subject.pages - paginator.next - expect(original_params).to be params - end - end - - describe '#items' do - it 'is not implemented' do - expect { subject.items }.to raise_error(NoMethodError) - end - end - end - - describe PaginatorsTestWithItems do - let(:client) { Client.new } - let(:params) { { param: 'param' } } - let(:options) { { stub_responses: true } } - - subject { PaginatorsTestWithItems.new(client, params, options) } - let(:response1) do - Hearth::Output.new( - data: Types::PaginatorsTestOperationOutput.new( - next_token: 'foo', - items: %w[a b c] - ) - ) - end - let(:response2) do - Hearth::Output.new( - data: Types::PaginatorsTestOperationOutput.new( - next_token: 'bar', - items: %w[1 2 3] - ) - ) - end - let(:response3) do - Hearth::Output.new( - data: Types::PaginatorsTestOperationOutput.new(items: ['the end']) - ) - end - - describe '.pages' do - # skip, already tested with PaginatorsTest.pages - end - - describe '#items' do - it 'yields items from paged response data', rbs_test: :skip do - expect(client).to receive(:paginators_test_with_items) - .with({ param: 'param' }, options).and_return(response1) - expect(client).to receive(:paginators_test_with_items) - .with({ param: 'param', - next_token: 'foo' }, options).and_return(response2) - expect(client).to receive(:paginators_test_with_items) - .with({ param: 'param', - next_token: 'bar' }, options).and_return(response3) - - paginator = subject.items - expect(paginator).to be_a(Enumerator) - items = paginator.to_a - expect(items).to eq(['a', 'b', 'c', '1', '2', '3', 'the end']) - end - end - end - - describe Operation____PaginatorsTestWithBadNames do - let(:client) { Client.new } - let(:params) { { param: 'param' } } - let(:options) { { stub_responses: true } } - - subject do - Operation____PaginatorsTestWithBadNames.new(client, params, options) - end - let(:response1) do - Hearth::Output.new( - data: Types::Struct____PaginatorsTestWithBadNamesOutput.new( - member___wrapper: Types::ResultWrapper.new( - member___123next_token: 'foo' - ), - member___items: %w[a b c] - ) - ) - end - let(:response2) do - Hearth::Output.new( - data: Types::Struct____PaginatorsTestWithBadNamesOutput.new( - member___wrapper: Types::ResultWrapper.new( - member___123next_token: 'bar' - ), - member___items: %w[1 2 3] - ) - ) - end - let(:response3) do - Hearth::Output.new( - data: Types::Struct____PaginatorsTestWithBadNamesOutput.new( - member___items: ['the end'] - ) - ) - end - - describe '.pages' do - # skip, already tested with PaginatorsTest.pages - end - - describe '#items' do - it 'yields items from paged response data', rbs_test: :skip do - expect(client) - .to receive(:operation____paginators_test_with_bad_names) - .with({ param: 'param' }, options) - .and_return(response1) - expect(client) - .to receive(:operation____paginators_test_with_bad_names) - .with({ param: 'param', - member___next_token: 'foo' }, options) - .and_return(response2) - expect(client) - .to receive(:operation____paginators_test_with_bad_names) - .with({ param: 'param', - member___next_token: 'bar' }, options) - .and_return(response3) - - paginator = subject.items - expect(paginator).to be_a(Enumerator) - items = paginator.to_a - expect(items).to eq(['a', 'b', 'c', '1', '2', '3', 'the end']) - end - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/params_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/params_spec.rb deleted file mode 100644 index d3c51c446..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/params_spec.rb +++ /dev/null @@ -1,215 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -# guaranteed to trip validation -class BadType; end - -RSpec.shared_examples 'validates params' do |*types| - it "validates params as #{types}" do - expect do - shape = Object.const_get(self.class.description) - shape.build(BadType.new, context: 'params') - end.to raise_error(ArgumentError, - 'Expected params to be in ' \ - "[#{types.map(&:to_s).join(', ')}], got BadType.") - end -end - -module WhiteLabel - module Params - describe ListOfStrings do - include_examples 'validates params', Array - - let(:params) { %w[dank memes] } - - it 'builds an array of simple elements' do - data = ListOfStrings.build(params, context: 'params') - expect(data).to be_a(Array) - expect(data).to eq(params) - end - end - - describe ListOfStructs do - include_examples 'validates params', Array - - it 'builds an array of complex elements' do - params = [{}, {}] - data = ListOfStructs.build(params, context: 'params[:list_of_structs]') - expect(data).to be_a(Array) - expect(data).to all(be_a(Types::Struct)) - end - end - - describe MapOfStrings do - include_examples 'validates params', Hash - - let(:params) { { key: 'value', other_key: 'other value' } } - - it 'builds a map of simple values' do - data = MapOfStrings.build(params, context: 'params') - expect(data).to be_a(Hash) - expect(data).to eq(params) - end - end - - describe MapOfStructs do - include_examples 'validates params', Hash - - it 'builds a map of complex values' do - params = { key: {}, other_key: {} } - data = MapOfStructs.build(params, context: 'params[:map_of_structs]') - expect(data).to be_a(Hash) - expect(data.values).to all(be_a(Types::Struct)) - end - end - - describe KitchenSinkInput do - include_examples 'validates params', Hash, Types::KitchenSinkInput - - let(:params) do - { - string: 'simple string', - struct: { value: 'struct value' }, - document: { 'boolean' => true }, - list_of_strings: %w[dank memes], - list_of_structs: [{ value: 'struct value' }], - map_of_strings: { 'key' => 'value' }, - map_of_structs: { 'key' => { value: 'struct value' } }, - union: { string: 'simple string' } - } - end - - it 'builds all member input' do - data = KitchenSinkInput.build(params, context: 'params') - expect(data).to be_a(Types::KitchenSinkInput) - expect(data.struct).to be_a(Types::Struct) - expect(data.to_h).to eq(params) - end - end - - describe DefaultsTestInput do - include_examples 'validates params', Hash, Types::DefaultsTestInput - - let(:params) { { defaults: {} } } - - it 'builds with empty params input' do - data = DefaultsTestInput.build(params, context: 'params') - expect(data).to be_a(Types::DefaultsTestInput) - expected = { - number: 0, - bool: false, - hello: 'world', - simple_enum: 'YES', - valued_enum: 'no', - int_enum: 1, - string_document: 'some string document', - un_required_bool: false, - un_required_number: 0, - boolean_document: true, - numbers_document: 1.23, - list_document: [], - map_document: {}, - list_of_strings: [], - map_of_strings: {}, - epoch_timestamp: Time.at(1_515_531_081.1234), - iso8601_timestamp: Time.parse('1985-04-12T23:20:50.52Z') - } - expect(data.defaults.to_h).to eq(expected) - end - end - - describe Struct do - include_examples 'validates params', Hash, Types::Struct - - let(:params) { { value: 'simple' } } - - it 'builds a structure with params' do - data = Struct.build(params, context: 'params') - expect(data).to be_a(Types::Struct) - expect(data.to_h).to eq(params) - end - - it 'validates unknown params' do - expect do - Struct.build({ unknown: 'param' }, context: 'params') - end.to raise_error( - ArgumentError, - 'Unexpected members: [params[:unknown]]' - ) - end - end - - describe Union do - include_examples 'validates params', Hash, Types::Union - - it 'builds a union structure with simple data' do - params = { string: 'simple string' } - data = Union.build(params, context: 'params') - expect(data).to be_a(Types::Union) - expect(data.to_h).to eq(params) - end - - it 'builds a union structure with complex data' do - params = { struct: { value: 'simple struct' } } - data = Union.build(params, context: 'params[:union]') - expect(data).to be_a(Types::Union) - expect(data.to_h).to eq(params) - end - - it 'validates exactly one member' do - struct = Types::Struct.new - params = { string: 'simple string', struct: struct } - expect { Union.build(params, context: 'params') } - .to raise_error(ArgumentError, /exactly one member/) - end - - it 'validates against unknown members' do - params = { unknown: 'poop emoji' } - expect { Union.build(params, context: 'params') } - .to raise_error(ArgumentError, /Expected params to have one of/) - end - end - - describe StreamingInput do - it 'converts a string to StringIO' do - data = StreamingInput.build({ stream: 'string' }, context: 'params') - expect(data).to be_a(Types::StreamingInput) - expect(data.stream).to be_a(StringIO) - expect(data.stream.read).to eq('string') - end - - it 'converts a nil to an empty StringIO' do - data = StreamingInput.build({ stream: nil }, context: 'params') - expect(data).to be_a(Types::StreamingInput) - expect(data.stream).to be_a(StringIO) - expect(data.stream.read).to eq('') - end - - it 'does not convert a readable, io like object' do - stream = StringIO.new('chunk') - data = StreamingInput.build({ stream: stream }, context: 'params') - expect(data).to be_a(Types::StreamingInput) - expect(data.stream).to be(stream) - end - end - - describe MixinTestInput do - it 'expects mixins input operation generated' do - data = MixinTestInput.build({ user_id: 'abc123' }, context: 'params') - expect(data).to be_a(Types::MixinTestInput) - expect(data.user_id).to eq('abc123') - end - end - - describe MixinTestOutput do - it 'expects mixins output operation generated' do - data = MixinTestOutput.build({ username: 'ben', user_id: 'abc123' }, - context: 'params') - expect(data).to be_a(Types::MixinTestOutput) - expect(data.user_id).to eq('abc123') - expect(data.username).to eq('ben') - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/plugin_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/plugin_spec.rb deleted file mode 100644 index b89e51132..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/plugin_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - describe 'client class plugins' do - it 'applies plugins to modify config during initialize' do - config = Config.new - expect(config.test_config).to eq('default') - client = Client.new - expect(client.config.test_config).to eq('client_override') - end - end - - describe 'configured plugins' do - it 'applies user configured plugins after client class plugins' do - plugin_list = Hearth::PluginList.new - plugin_list << WhiteLabel::Plugins::TestPlugin.new( - override_value: 'user_override' - ) - client = Client.new(plugins: plugin_list) - expect(client.config.test_config).to eq('user_override') - end - end - - describe 'operation plugins' do - it 'applies operation plugins' do - client = Client.new(stub_responses: true) - output = client.kitchen_sink( - {}, - { plugins: [ - WhiteLabel::Plugins::TestPlugin.new( - override_value: 'operation_override' - ) - ] } - ) - expect(output.metadata[:test_config]).to eq('operation_override') - # does not modify client config - expect(client.config.test_config).to eq('client_override') - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/retry_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/retry_spec.rb deleted file mode 100644 index 52c1dd51d..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/retry_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - let(:client) { Client.new(stub_responses: true) } - - describe '#kitchen_sink' do - it 'does a retry' do - client.stub_responses( - :kitchen_sink, - { error: { class: Errors::ServerError } }, - { data: { string: 'ok' } } - ) - # Do not test fake protocol - expect(WhiteLabel::Stubs::ServerError) - .to receive(:stub).and_wrap_original do |_m, *args| - http_resp, = *args - http_resp.headers['x-smithy-error'] = 'ServerError' - end - - expect_any_instance_of(Hearth::Retry::Standard) - .to receive(:acquire_initial_retry_token).and_call_original - expect_any_instance_of(Hearth::Retry::Standard) - .to receive(:refresh_retry_token).and_call_original - expect_any_instance_of(Hearth::Retry::Standard) - .to receive(:record_success).and_call_original - expect(Kernel).to receive(:sleep).once - - client.kitchen_sink - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/spec_helper.rb b/codegen/smithy-ruby-codegen-test/integration-specs/spec_helper.rb deleted file mode 100644 index 364277ea4..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/spec_helper.rb +++ /dev/null @@ -1,102 +0,0 @@ -# frozen_string_literal: true - -require 'white_label' - -# This file was generated by the `rspec --init` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. -# -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. -# -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. - config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end - - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. - config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. - mocks.verify_partial_doubles = true - end - - # This option will default to `:apply_to_host_groups` in RSpec 4 (and will - # have no way to turn it off -- the option exists only for backwards - # compatibility in RSpec 3). It causes shared context metadata to be - # inherited by the metadata hash of host groups and examples, rather than - # triggering implicit auto-inclusion in groups with matching metadata. - config.shared_context_metadata_behavior = :apply_to_host_groups - - # The settings below are suggested to provide a good initial experience - # with RSpec, but feel free to customize to your heart's content. - # # This allows you to limit a spec run to individual examples or groups - # # you care about by tagging them with `:focus` metadata. When nothing - # # is tagged with `:focus`, all examples get run. RSpec also provides - # # aliases for `it`, `describe`, and `context` that include `:focus` - # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - # config.filter_run_when_matching :focus - # - # # Allows RSpec to persist some state between runs in order to support - # # the `--only-failures` and `--next-failure` CLI options. We recommend - # # you configure your source control system to ignore this file. - # config.example_status_persistence_file_path = "spec/examples.txt" - # - # # Limits the available syntax to the non-monkey patched syntax that is - # # recommended. For more details, see: - # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - # config.disable_monkey_patching! - # - # # This setting enables warnings. It's recommended, but in some cases may - # # be too noisy due to issues in dependencies. - # config.warnings = true - # - # # Many RSpec users commonly either run the entire suite or an individual - # # file, and it's useful to allow more verbose output when running an - # # individual spec file. - # if config.files_to_run.one? - # # Use the documentation formatter for detailed output, - # # unless a formatter has already been configured - # # (e.g. via a command-line flag). - # config.default_formatter = "doc" - # end - # - # # Print the 10 slowest examples and example groups at the - # # end of the spec run, to help surface which specs are running - # # particularly slow. - # config.profile_examples = 10 - # - # # Run specs in random order to surface order dependencies. If you find an - # # order dependency and want to debug it, you can fix the order by - # # providing the seed, which is printed after each run. - # # --seed 1234 - # config.order = :random - # - # # Seed global randomization in this process using the `--seed` CLI option. - # # Setting this allows you to use `--seed` to deterministically reproduce - # # test failures related to randomization by passing the same `--seed` - # # value as the one that triggered the failure. - # Kernel.srand config.seed -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/streaming_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/streaming_spec.rb deleted file mode 100644 index 53382e415..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/streaming_spec.rb +++ /dev/null @@ -1,144 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - let(:client) { Client.new(stub_responses: true) } - - describe '#streaming' do - let(:output) { 'test' } - - before do - client.stub_responses(:streaming, data: { stream: output }) - end - - context 'block is provided' do - let(:block_io) { Hearth::BlockIO.new(-> {}) } - - it 'creates and uses a blockIO as the body' do - expect(Hearth::BlockIO).to receive(:new).and_return(block_io) - expect(block_io).to receive(:write).with(output).and_return(0) - - expect(Hearth::HTTP::Response) - .to receive(:new) - .with(hash_including(body: block_io)) - .and_call_original - - client.streaming { |resp| resp } - end - end - - context 'output_stream is set' do - let(:output_stream) { StringIO.new } - - it 'uses the output_stream as the body' do - expect(Hearth::HTTP::Response) - .to receive(:new) - .with(hash_including(body: output_stream)) - .and_call_original - - expect(output_stream).to receive(:write).with(output).and_return(0) - client.streaming({}, output_stream: output_stream) - end - end - - context 'parsers' do - let(:output_stream) { StringIO.new } - - before do - expect(output_stream).to receive(:write).and_return(0) - end - - it 'does not read the body' do - expect(output_stream).not_to receive(:read) - client.streaming({}, output_stream: output_stream) - end - - it 'sets the field on the output' do - resp = client.streaming({}, output_stream: output_stream) - expect(resp.data.stream).to be(output_stream) - end - end - - context 'stubs' do - let(:output_stream) { StringIO.new } - - it 'copies the stub to the output stream' do - proc = proc do |context| - expect(context.response.body).to be(output_stream) - end - interceptor = Hearth::Interceptor.new(read_after_transmit: proc) - expect(output_stream).to receive(:write).with(output).and_return(0) - - client.streaming( - {}, - output_stream: output_stream, - interceptors: [interceptor] - ) - end - - context('nil stub value') do - let(:output) { nil } - - it 'streams an empty body' do - expect(output_stream).not_to receive(:write) - client.streaming({}, output_stream: output_stream) - end - end - end - - context 'builders' do - it 'sets the body to the streaming member' do - streaming_input = StringIO.new('test') - proc = proc do |context| - expect(context.request.body).to be(streaming_input) - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - expect(streaming_input).not_to receive(:read) - - client.streaming( - { stream: streaming_input }, - interceptors: [interceptor] - ) - end - - it 'sets Transfer-Encoding and does not set content length' do - streaming_input = StringIO.new('test') - proc = proc do |context| - expect(context.request.headers['Transfer-Encoding']) - .to eq('chunked') - expect(context.request.fields.key?('Content-Length')) - .to eq(false) - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - expect(streaming_input).not_to receive(:size) - - client.streaming( - { stream: streaming_input }, - interceptors: [interceptor] - ) - end - end - end - - describe '#streaming_with_length' do - let(:data) { 'test' } - - it 'sets content-length and does not set Transfer-Encoding' do - proc = proc do |context| - expect(context.request.headers['Content-Length']) - .to eq(data.length.to_s) - expect(context.request.fields.key?('Transfer-Encoding')) - .to eq(false) - end - interceptor = Hearth::Interceptor.new(read_before_transmit: proc) - - client.streaming_with_length( - { stream: data }, - interceptors: [interceptor] - ) - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/stubs_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/stubs_spec.rb deleted file mode 100644 index 4ec622d03..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/stubs_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - describe Client do - let(:client) { Client.new(stub_responses: true) } - let(:stub_error) { StandardError.new('Stubbed error') } - - describe '#initialize' do - it 'can configure stubs on initialize' do - client = Client.new( - stub_responses: true, - stubs: Hearth::Stubs.new(kitchen_sink: [stub_error]) - ) - expect do - client.kitchen_sink - end.to raise_error(stub_error) - end - end - - describe '#stub_responses' do - it 'can configure stubs with stub_responses' do - client.stub_responses(:kitchen_sink, [stub_error]) - expect do - client.kitchen_sink - end.to raise_error(stub_error) - end - end - - describe '#kitchen_sink' do - it 'configuring stubs on operations is not allowed' do - expect do - client.kitchen_sink({}, stubs: [stub_error]) - end.to raise_error(ArgumentError, /not allowed/) - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/telemetry_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/telemetry_spec.rb deleted file mode 100644 index af7ee3e74..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/telemetry_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' -require 'webmock/rspec' -require 'opentelemetry-sdk' - -module WhiteLabel - describe Config do - context 'telemetry_provider' do - let(:custom_class) do - Class.new(Hearth::Telemetry::TelemetryProviderBase) - end - - let(:custom_provider) { custom_class.new } - - it 'raises error when given an invalid input', rbs_test: :skip do - expect { Config.new(telemetry_provider: 'foo').validate! } - .to raise_error( - ArgumentError, - 'Expected config[:telemetry_provider] to be in ' \ - '[Hearth::Telemetry::TelemetryProviderBase], got String.' - ) - end - - it 'does not raise error when given an otel provider' do - otel_provider = Hearth::Telemetry::OTelProvider.new - expect { Config.new(telemetry_provider: otel_provider).validate! } - .not_to raise_error - end - - it 'does not raise error when given a custom provider' do - expect { Config.new(telemetry_provider: custom_provider).validate! } - .not_to raise_error - end - end - end - - describe Client do - context 'no-op telemetry provider' do - it 'does not raise error when calling an operation' do - client = Client.new(stub_responses: true) - expect { client.telemetry_test }.not_to raise_error - end - end - - context 'otel provider' do - let(:otel_provider) { Hearth::Telemetry::OTelProvider.new } - let(:otel_export) { OpenTelemetry::SDK::Trace::Export } - let(:otel_exporter) { otel_export::InMemorySpanExporter.new } - - before do - processor = otel_export::SimpleSpanProcessor.new(otel_exporter) - OpenTelemetry::SDK.configure do |c| - c.add_span_processor(processor) - end - end - - after { reset_opentelemetry_sdk } - - let(:client) do - Client.new( - telemetry_provider: otel_provider, - retry_strategy: Hearth::Retry::Standard.new(max_attempts: 0) - ) - end - - let(:body) { 'AAAAA' } - let(:finished_send_span) do - otel_exporter - .finished_spans - .find { |span| span.name == 'Middleware.Send' } - end - - let(:finished_op_span) do - otel_exporter - .finished_spans - .find { |span| span.name == 'WhiteLabel.TelemetryTest' } - end - - it 'raises error when an otel dependency was not required' do - allow_any_instance_of(Hearth::Telemetry::OTelProvider) - .to receive(:require).with('opentelemetry-sdk').and_raise(LoadError) - expect { otel_provider } - .to raise_error( - ArgumentError, - 'Requires the `opentelemetry-sdk` gem to use OTel Provider.' - ) - end - - it 'creates spans with all the supplied parameters' do - stub_request(:post, 'https://whitelabel.com') - client.telemetry_test - - expect(finished_send_span).not_to be_nil - expect(finished_op_span).not_to be_nil - expect(finished_send_span.attributes) - .to include( - 'http.method' => 'POST', - 'net.protocol.name' => 'http', - 'net.protocol.version' => '1.1', - 'net.peer.name' => 'whitelabel.com', - 'net.peer.port' => 443, - 'http.status_code' => 200 - ) - expect(finished_op_span.attributes) - .to include( - 'rpc.service' => 'WhiteLabel', - 'rpc.method' => 'TelemetryTest', - 'code.function' => 'telemetry_test', - 'code.namespace' => 'WhiteLabel::Telemetry' - ) - expect(finished_send_span.kind).to eq(:internal) - expect(finished_op_span.kind).to eq(:client) - expect(finished_send_span.parent_span_id) - .to eq(finished_op_span.span_id) - end - - it 'applies content-length span attributes when applicable' do - stub_request(:post, 'https://whitelabel.com') - .to_return( - body: body, - headers: { 'Content-Length' => body.size } - ) - client.telemetry_test(body: body) - - expect(finished_send_span.attributes) - .to include( - 'http.request_content_length' => body.size.to_s, - 'http.response_content_length' => body.size.to_s - ) - end - - it 'populates span data with error when it occurs' do - stub_request(:post, 'https://whitelabel.com') - .to_return(status: 500) - begin - client.telemetry_test - rescue WhiteLabel::Errors::ApiServerError - # Ignored - end - expect(finished_op_span.status.code).to eq(2) # err code - expect(finished_op_span.events[0].name).to eq('exception') - expect(finished_op_span.events[0].attributes['exception.type']) - .to eq('WhiteLabel::Errors::ApiServerError') - end - - context 'stub_responses' do - it 'creates a stub span with all the supplied parameters' do - client = Client.new( - stub_responses: true, - telemetry_provider: otel_provider - ) - client.telemetry_test - expect(finished_send_span).not_to be_nil - expect(finished_send_span.attributes) - .to include( - 'http.method' => 'POST', - 'net.protocol.name' => 'http', - 'net.protocol.version' => '1.1' - ) - expect(finished_send_span.kind).to eq(:internal) - expect(finished_send_span.parent_span_id) - .to eq(finished_op_span.span_id) - end - end - end - end -end - -# clears opentelemetry-sdk configuration state between specs -# https://github.com/open-telemetry/opentelemetry-ruby/blob/main/test_helpers/lib/opentelemetry/test_helpers.rb#L18 -def reset_opentelemetry_sdk - OpenTelemetry.instance_variable_set( - :@tracer_provider, - OpenTelemetry::Internal::ProxyTracerProvider.new - ) - OpenTelemetry.error_handler = nil - OpenTelemetry.propagation = nil -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/types_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/types_spec.rb deleted file mode 100644 index e603f6b19..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/types_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - module Types - describe KitchenSinkInput do - subject { KitchenSinkInput.new } - - it 'is a hearth structure' do - expect(subject).to be_a(Hearth::Structure) - end - - it 'has a MEMBERS constant' do - expect(KitchenSinkInput::MEMBERS).to be_a(Array) - end - end - - describe Union do - subject { Union.new(nil) } - let(:struct) { Types::Struct.new(value: 'struct value') } - - it 'is a hearth union' do - expect(subject).to be_a(Hearth::Union) - # implementation detail - expect(subject).to be_a(SimpleDelegator) - end - - it 'has subclasses' do - string_union = Union::String.new('simple string') - struct_union = Union::Struct.new(struct) - unknown_union = Union::Unknown.new(name: 'unknown', value: 'unknown') - expect(string_union).to be_a(Union) - expect(struct_union).to be_a(Union) - expect(unknown_union).to be_a(Union) - end - - it 'implements to_h for delegation' do - string_union = Union::String.new('simple string') - struct_union = Union::Struct.new(struct) - unknown_union = Union::Unknown.new(name: 'name', value: 'value') - expect(string_union.to_h).to eq({ string: 'simple string' }) - expect(struct_union.to_h).to eq({ struct: { value: 'struct value' } }) - expect(unknown_union.to_h).to eq({ unknown: { name: 'name', - value: 'value' } }) - end - end - - describe Defaults do - it 'has a default value for default_number' do - expect(subject.un_required_number).to be 0 - end - - it 'has a default value for default_bool' do - expect(subject.un_required_bool).to be false - end - end - - describe SimpleEnum do - it 'has typed enums' do - expect(Types::SimpleEnum::YES).to eq 'YES' - expect(Types::SimpleEnum::NO).to eq 'NO' - end - end - - describe ValuedEnum do - it 'has typed enums with new values' do - expect(Types::ValuedEnum::YES).to eq 'yes' - expect(Types::ValuedEnum::NO).to eq 'no' - end - end - - describe IntEnumType do - it 'has typed enums' do - expect(Types::IntEnumType::ONE).to eq 1 - expect(Types::IntEnumType::TWO).to eq 2 - expect(Types::IntEnumType::THREE).to eq 3 - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/validators_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/validators_spec.rb deleted file mode 100644 index 0a1102a48..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/validators_spec.rb +++ /dev/null @@ -1,258 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - module Validators - describe Document do - it 'validates against document types' do - expect { Document.validate!(Set.new, context: 'input') } - .to raise_error( - ArgumentError, - 'Expected input to be in ' \ - '[Hash, String, Array, TrueClass, FalseClass, Numeric], got Set.' - ) - end - - it 'validates a valid document' do - document = { - 'hash' => { 'key' => 'value' }, - 'array' => %w[dank memes], - 'string' => 'string', - 'boolean' => true, - 'integer' => 420, - 'float' => 69.69 - } - Document.validate!(document, context: 'input') - end - - it 'raises when hash values are not document types' do - document = { 'hash' => { 'key' => Set.new } } - expect { Document.validate!(document, context: 'input') } - .to raise_error( - ArgumentError, - "Expected input['hash']['key'] to be in " \ - '[Hash, String, Array, TrueClass, FalseClass, Numeric], got Set.' - ) - end - - it 'raises when array elements are not document types' do - document = { 'array' => [Set.new] } - expect { Document.validate!(document, context: 'input') } - .to raise_error( - ArgumentError, - "Expected input['array'][0] to be in " \ - '[Hash, String, Array, TrueClass, FalseClass, Numeric], got Set.' - ) - end - end - - describe ListOfStrings do - it 'validates an array' do - expect { ListOfStrings.validate!({}, context: 'input') } - .to raise_error(ArgumentError, - 'Expected input to be in [Array], got Hash.') - end - - it 'validates an array of simple elements' do - input = %w[dank memes] - ListOfStrings.validate!(input, context: 'input') - end - - it 'raises when element is not an expected type' do - input = ['dank', 'memes', 420] - expect { ListOfStrings.validate!(input, context: 'input') } - .to raise_error(ArgumentError, - 'Expected input[2] to be in [String], got Integer.') - end - end - - describe ListOfStructs do - let(:struct1) { Types::Struct.new } - let(:struct2) { Types::Struct.new } - - it 'validates an array' do - expect { ListOfStructs.validate!({}, context: 'input') } - .to raise_error(ArgumentError, - 'Expected input to be in [Array], got Hash.') - end - - it 'validates an array of complex elements' do - input = [struct1, struct2] - ListOfStructs.validate!(input, context: 'input') - end - - it 'raises when element is not an expected type' do - input = [struct1, struct2, 'struct_3'] - expect { ListOfStructs.validate!(input, context: 'input') } - .to raise_error(ArgumentError, - 'Expected input[2] to be in ' \ - '[WhiteLabel::Types::Struct], got String.') - end - end - - describe MapOfStrings do - it 'validates a hash' do - expect { MapOfStrings.validate!([], context: 'input') } - .to raise_error(ArgumentError, - 'Expected input to be in [Hash], got Array.') - end - - it 'validates a hash of simple values' do - input = { 'key' => 'value', 'other_key' => 'other value' } - MapOfStrings.validate!(input, context: 'input') - end - - it 'raises when key is not a String' do - input = { 'key' => 'value', 4 => 'other value' } - expect { MapOfStrings.validate!(input, context: 'input') } - .to raise_error(ArgumentError, - 'Expected input.keys to be in [String], got Integer.') - end - - it 'raises when value is not an expected type' do - input = { 'key' => 'value', 'other_key' => ['array element'] } - expect { MapOfStrings.validate!(input, context: 'input') } - .to raise_error(ArgumentError, - "Expected input['other_key'] to " \ - 'be in [String], got Array.') - end - end - - describe MapOfStructs do - let(:struct1) { Types::Struct.new } - let(:struct2) { Types::Struct.new } - - it 'validates a hash' do - expect { MapOfStructs.validate!([], context: 'input') } - .to raise_error(ArgumentError, - 'Expected input to be in [Hash], got Array.') - end - - it 'validates a hash of complex values' do - input = { 'key' => struct1, 'other_key' => struct2 } - MapOfStructs.validate!(input, context: 'input') - end - - it 'raises when key is not a string or symbol' do - input = { 'key' => struct1, 4 => struct2 } - expect { MapOfStructs.validate!(input, context: 'input') } - .to raise_error(ArgumentError, - 'Expected input.keys to be in [String], got Integer.') - end - - it 'raises when value is not an expected type' do - input = { 'key' => struct1, 'other_key' => 'struct_2' } - expect { MapOfStructs.validate!(input, context: 'input') } - .to raise_error(ArgumentError, - "Expected input['other_key'] to be in " \ - '[WhiteLabel::Types::Struct], got String.') - end - end - - describe KitchenSinkInput do - let(:params) do - { - string: 'simple string', - struct: { value: 'struct value' }, - document: { 'boolean' => true }, - list_of_strings: %w[dank memes], - list_of_structs: [{ value: 'struct value' }], - map_of_strings: { 'key' => 'value' }, - map_of_structs: { 'key' => { value: 'struct value' } }, - union: { string: 'simple string' } - } - end - - it 'validates all member input' do - input = Params::KitchenSinkInput.build(params, context: 'params') - KitchenSinkInput.validate!(input, context: 'input') - end - end - - describe Struct do - it 'validates the members' do - input = Types::Struct.new({ value: 'foo' }) - Struct.validate!(input, context: 'input') - end - end - - describe Union do - let(:struct) { Types::Struct.new(value: 'struct') } - - it 'validates simple members' do - expect do - Union.validate!(Types::Union::String.new({}), context: 'input') - end - .to raise_error(ArgumentError, - 'Expected input to be in [String], got Hash.') - end - - it 'validates complex members' do - expect do - Union.validate!(Types::Union::Struct.new('string'), context: 'input') - end - .to raise_error(ArgumentError, - 'Expected input to be in ' \ - '[WhiteLabel::Types::Struct], got String.') - end - - it 'validates unknown type' do - expect do - Union.validate!(Types::Union::Unknown.new(['some data']), - context: 'input') - end - .to raise_error(ArgumentError) - end - - it 'raises when input is not of Types::Union' do - expect { Union.validate!(struct, context: 'input') } - .to raise_error( - ArgumentError, - 'Expected input to be a union member of Types::Union, ' \ - 'got WhiteLabel::Types::Struct.' - ) - end - end - - describe StreamingInput do - it 'validates io like', rbs_test: :skip do - expect do - StreamingInput.validate!( - Types::StreamingInput.new(stream: ''), context: 'input' - ) - end - .to raise_error(ArgumentError, - 'Expected input to be an IO like object, got String') - end - end - - describe StreamingWithLengthInput do - it 'validates responds_to(:size)' do - rd, wr = IO.pipe - wr.puts 'data' - wr.close - expect do - StreamingWithLengthInput.validate!( - Types::StreamingWithLengthInput.new(stream: rd), context: 'input' - ) - end - .to raise_error(ArgumentError, - 'Expected input to respond_to(:size)') - rd.close - end - end - - describe EndpointWithHostLabelOperationInput do - let(:input) { Types::EndpointWithHostLabelOperationInput.new } - - it 'validates required', rbs_test: :skip do - expect do - EndpointWithHostLabelOperationInput.validate!(input, context: 'input') - end - .to raise_error(ArgumentError, - 'Expected input[:label_member] to be set.') - end - end - end -end diff --git a/codegen/smithy-ruby-codegen-test/integration-specs/waiters_spec.rb b/codegen/smithy-ruby-codegen-test/integration-specs/waiters_spec.rb deleted file mode 100644 index d4a2a5ccb..000000000 --- a/codegen/smithy-ruby-codegen-test/integration-specs/waiters_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec_helper' - -module WhiteLabel - module Waiters - describe ResourceExists do - let(:client) { Client.new } - let(:resource_waiter) { ResourceExists.new(client, max_wait_time: 9001) } - - it 'initializes a Hearth::Waiters::Waiter with min and max delays' do - waiter = resource_waiter.instance_variable_get(:@waiter) - expect(waiter).to be_a(Hearth::Waiters::Waiter) - expect(waiter.max_wait_time).to eq(9001) - # modeled min and max delay - expect(waiter.min_delay).to eq(10) - expect(waiter.max_delay).to eq(100) - end - - it 'initializes a Hearth::Waiters::Poller with operation and acceptors' do - waiter = resource_waiter.instance_variable_get(:@waiter) - poller = waiter.instance_variable_get(:@poller) - expect(poller).to be_a(Hearth::Waiters::Poller) - operation_name = poller.instance_variable_get(:@operation_name) - # modeled operation name - expect(operation_name).to eq(:waiters_test) - acceptors = poller.instance_variable_get(:@acceptors) - # modeled acceptors - expect(acceptors).to eq( - [ - { state: 'success', matcher: { success: true } }, - { state: 'retry', matcher: { errorType: 'NotFound' } }, - { - state: 'failure', - matcher: { - output: { - path: '"status"', - comparator: 'stringEquals', - expected: 'failed' - } - } - }, - { - state: 'failure', - matcher: { - inputOutput: { - path: '("input"."status" == `"failed"` || ' \ - '"output"."status" == `"failed"`)', - comparator: 'booleanEquals', - expected: 'true' - } - } - } - ] - ) - end - - it 'is taggable' do - expect(resource_waiter.tags).to eq(%w[waiter test]) - end - - it 'has a wait method that uses the waiter' do - params = { foo: 'bar' } - options = { stub_responses: true } - waiter = resource_waiter.instance_variable_get(:@waiter) - expect(waiter).to receive(:wait) - .with(client, params, options) - .and_return(true) - resource_waiter.wait(params, options) - end - end - end -end diff --git a/codegen/smithy-ruby-codegen/src/main/java/software/amazon/smithy/ruby/codegen/DirectedRubyCodegen.java b/codegen/smithy-ruby-codegen/src/main/java/software/amazon/smithy/ruby/codegen/DirectedRubyCodegen.java index 305aefce0..e435d701d 100644 --- a/codegen/smithy-ruby-codegen/src/main/java/software/amazon/smithy/ruby/codegen/DirectedRubyCodegen.java +++ b/codegen/smithy-ruby-codegen/src/main/java/software/amazon/smithy/ruby/codegen/DirectedRubyCodegen.java @@ -254,8 +254,11 @@ public void customizeBeforeIntegrations(CustomizeDirective indirectDependencies = new HashSet<>(); + rubyDependencies.forEach(rubyDependency -> { + indirectDependencies.addAll(rubyDependency.getRubyDependencies()); + }); + String fileName = settings.getGemName() + "/lib/" + settings.getGemName() + ".rb"; context.writerDelegator().useFileWriter(fileName, settings.getModule(), writer -> { writer.preamble().includeRequires(); - // determine set of indirect dependencies - covered by requiring another - Set indirectDependencies = new HashSet<>(); - rubyDependencies.forEach(rubyDependency -> { - indirectDependencies.addAll(rubyDependency.getRubyDependencies()); - }); rubyDependencies.forEach((rubyDependency -> { if (!indirectDependencies.contains(rubyDependency)) { writer.write("require '$L'", rubyDependency.getImportPath()); } })); - writer.write("\n"); for (String require : DEFAULT_REQUIRES) { writer.write("require_relative '$L/$L'", settings.getGemName(), require); @@ -78,6 +78,11 @@ public void render() { writer.write("require_relative '$L/event_stream'", settings.getGemName()); } + writer + .openBlock("begin") + .write("require_relative '$L/customizations'", settings.getGemName()) + .closeBlock("rescue LoadError; end"); + for (String require : additionalFiles) { writer.write("require_relative '$L'", require); } @@ -89,14 +94,12 @@ public void render() { .closeBlock("end"); }); LOGGER.fine("Wrote module file to " + fileName); - - renderRbs(); } /** * Render/generate the RBS types for the module. */ - private void renderRbs() { + public void renderRbs() { String fileName = settings.getGemName() + "/sig/" + settings.getGemName() + ".rbs"; @@ -107,5 +110,6 @@ private void renderRbs() { .write("VERSION: ::String") .closeBlock("end"); }); + LOGGER.fine("Wrote module rbs to " + fileName); } } diff --git a/hearth/spec/hearth/middleware/endpoint_spec.rb b/hearth/spec/hearth/middleware/endpoint_spec.rb index e54dff1a6..3e893df5b 100644 --- a/hearth/spec/hearth/middleware/endpoint_spec.rb +++ b/hearth/spec/hearth/middleware/endpoint_spec.rb @@ -59,7 +59,7 @@ class TestEndpointInput end let(:params) { double } - before(:each) do + before do expect(param_builder).to receive(:build) .with({ config1: config1, config2: config2 }, input, context).and_return(params)