From c5958990d83a7c7b06121430a81094e1292ad902 Mon Sep 17 00:00:00 2001 From: Zakir Dzhamaliddinov Date: Fri, 19 Jul 2024 03:24:56 +0300 Subject: [PATCH] Introduce stub_env helper (#210) --- spec/command/copy_image_from_upstream_spec.rb | 10 ++-- spec/command/deploy_image_spec.rb | 4 +- .../command/promote_app_from_upstream_spec.rb | 16 +++--- spec/command/setup_app_spec.rb | 3 +- spec/core/controlplane_api_direct_spec.rb | 10 ++-- spec/core/controlplane_spec.rb | 6 +-- spec/spec_helper.rb | 2 + spec/support/stub_env.rb | 54 +++++++++++++++++++ spec/support_specs/stub_env_spec.rb | 28 ++++++++++ 9 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 spec/support/stub_env.rb create mode 100644 spec/support_specs/stub_env_spec.rb diff --git a/spec/command/copy_image_from_upstream_spec.rb b/spec/command/copy_image_from_upstream_spec.rb index e856c4c9..8d1f0fd0 100644 --- a/spec/command/copy_image_from_upstream_spec.rb +++ b/spec/command/copy_image_from_upstream_spec.rb @@ -46,7 +46,7 @@ let!(:app) { dummy_test_app } before do - ENV["CPLN_UPSTREAM"] = upstream_app + stub_env("CPLN_UPSTREAM", upstream_app) end it "raises error" do @@ -62,9 +62,9 @@ let!(:app) { dummy_test_app } before do - ENV["CPLN_UPSTREAM"] = upstream_app + stub_env("CPLN_UPSTREAM", upstream_app) # Ideally, we should have a different org, but for testing purposes, this works - ENV["CPLN_ORG_UPSTREAM"] = dummy_test_org + stub_env("CPLN_ORG_UPSTREAM", dummy_test_org) run_cpflow_command!("apply-template", "app", "-a", upstream_app) run_cpflow_command!("apply-template", "app", "-a", app) @@ -93,9 +93,9 @@ let!(:app) { dummy_test_app } before do - ENV["CPLN_UPSTREAM"] = upstream_app + stub_env("CPLN_UPSTREAM", upstream_app) # Ideally, we should have a different org, but for testing purposes, this works - ENV["CPLN_ORG_UPSTREAM"] = dummy_test_org + stub_env("CPLN_ORG_UPSTREAM", dummy_test_org) run_cpflow_command!("apply-template", "app", "-a", upstream_app) run_cpflow_command!("apply-template", "app", "-a", app) diff --git a/spec/command/deploy_image_spec.rb b/spec/command/deploy_image_spec.rb index 0b270908..ff06a502 100644 --- a/spec/command/deploy_image_spec.rb +++ b/spec/command/deploy_image_spec.rb @@ -62,7 +62,7 @@ let!(:app) { dummy_test_app("invalid-release-script") } before do - ENV["APP_NAME"] = app + stub_env("APP_NAME", app) allow(Kernel).to receive(:sleep) @@ -92,7 +92,7 @@ let!(:app) { dummy_test_app("rails-non-app-image", create_if_not_exists: true) } before do - ENV["APP_NAME"] = app + stub_env("APP_NAME", app) allow(Kernel).to receive(:sleep) diff --git a/spec/command/promote_app_from_upstream_spec.rb b/spec/command/promote_app_from_upstream_spec.rb index 15617c70..3ae015cc 100644 --- a/spec/command/promote_app_from_upstream_spec.rb +++ b/spec/command/promote_app_from_upstream_spec.rb @@ -9,9 +9,9 @@ let!(:app) { dummy_test_app("nothing") } before do - ENV["CPLN_UPSTREAM"] = upstream_app + stub_env("CPLN_UPSTREAM", upstream_app) # Ideally, we should have a different org, but for testing purposes, this works - ENV["CPLN_ORG_UPSTREAM"] = dummy_test_org + stub_env("CPLN_ORG_UPSTREAM", dummy_test_org) run_cpflow_command!("apply-template", "app", "-a", upstream_app) run_cpflow_command!("apply-template", "app", "rails", "-a", app) @@ -40,10 +40,10 @@ let!(:app) { dummy_test_app("invalid-release-script") } before do - ENV["CPLN_UPSTREAM"] = upstream_app + stub_env("CPLN_UPSTREAM", upstream_app) # Ideally, we should have a different org, but for testing purposes, this works - ENV["CPLN_ORG_UPSTREAM"] = dummy_test_org - ENV["APP_NAME"] = app + stub_env("CPLN_ORG_UPSTREAM", dummy_test_org) + stub_env("APP_NAME", app) run_cpflow_command!("apply-template", "app", "-a", upstream_app) run_cpflow_command!("apply-template", "app", "rails", "postgres", "-a", app) @@ -77,10 +77,10 @@ let!(:app) { dummy_test_app } before do - ENV["CPLN_UPSTREAM"] = upstream_app + stub_env("CPLN_UPSTREAM", upstream_app) # Ideally, we should have a different org, but for testing purposes, this works - ENV["CPLN_ORG_UPSTREAM"] = dummy_test_org - ENV["APP_NAME"] = app + stub_env("CPLN_ORG_UPSTREAM", dummy_test_org) + stub_env("APP_NAME", app) run_cpflow_command!("apply-template", "app", "-a", upstream_app) run_cpflow_command!("apply-template", "app", "rails", "postgres", "-a", app) diff --git a/spec/command/setup_app_spec.rb b/spec/command/setup_app_spec.rb index 1037c02c..2e1e972d 100644 --- a/spec/command/setup_app_spec.rb +++ b/spec/command/setup_app_spec.rb @@ -162,8 +162,7 @@ let!(:app) { dummy_test_app("undefined-org") } before do - allow(ENV).to receive(:fetch).and_call_original - allow(ENV).to receive(:fetch).with("CPLN_ORG", nil).and_return(nil) + stub_env("CPLN_ORG", nil) end after do diff --git a/spec/core/controlplane_api_direct_spec.rb b/spec/core/controlplane_api_direct_spec.rb index 59884c76..3f36fb7c 100644 --- a/spec/core/controlplane_api_direct_spec.rb +++ b/spec/core/controlplane_api_direct_spec.rb @@ -7,7 +7,7 @@ describe "#api_host" do it "returns correct host for 'api' when CPLN_ENDPOINT is not set" do - allow(ENV).to receive(:fetch).with("CPLN_ENDPOINT", "https://api.cpln.io").and_return("https://api.cpln.io") + stub_env("CPLN_ENDPOINT", nil) host = described_instance.api_host(:api) @@ -15,7 +15,7 @@ end it "returns correct host for 'api' when CPLN_ENDPOINT is set" do - allow(ENV).to receive(:fetch).with("CPLN_ENDPOINT", "https://api.cpln.io").and_return("http://api.cpln.io") + stub_env("CPLN_ENDPOINT", "http://api.cpln.io") host = described_instance.api_host(:api) @@ -39,7 +39,7 @@ end it "returns token from CPLN_TOKEN" do - allow(ENV).to receive(:fetch).with("CPLN_TOKEN", nil).and_return("token_1") + stub_env("CPLN_TOKEN", "token_1") result = described_instance.api_token @@ -48,7 +48,7 @@ end it "returns token from 'cpln profile token'" do - allow(ENV).to receive(:fetch).with("CPLN_TOKEN", nil).and_return(nil) + stub_env("CPLN_TOKEN", nil) allow(Shell).to receive(:cmd).with("cpln", "profile", "token").and_return({ output: "token_2" }) result = described_instance.api_token @@ -58,7 +58,7 @@ end it "raises error if token is not found" do - allow(ENV).to receive(:fetch).with("CPLN_TOKEN", nil).and_return(nil) + stub_env("CPLN_TOKEN", nil) allow(Shell).to receive(:cmd).with("cpln", "profile", "token").and_return({ output: "" }) message = "Unknown API token format. " \ diff --git a/spec/core/controlplane_spec.rb b/spec/core/controlplane_spec.rb index 88218aca..226270b8 100644 --- a/spec/core/controlplane_spec.rb +++ b/spec/core/controlplane_spec.rb @@ -19,7 +19,7 @@ let!(:original_cmd) { "cmd" } before do - allow(ENV).to receive(:fetch).with("HIDE_COMMAND_OUTPUT", nil).and_return(nil) + stub_env("HIDE_COMMAND_OUTPUT", nil) allow(Shell).to receive(:should_hide_output?).and_return(false) end @@ -48,7 +48,7 @@ end it "hides everything when 'HIDE_COMMAND_OUTPUT' env var is set to 'true'" do - allow(ENV).to receive(:fetch).with("HIDE_COMMAND_OUTPUT", nil).and_return("true") + stub_env("HIDE_COMMAND_OUTPUT", "true") cmd = described_instance.send(:build_command, original_cmd) @@ -56,7 +56,7 @@ end it "provided 'output_mode' overrides 'HIDE_COMMAND_OUTPUT' env var" do - allow(ENV).to receive(:fetch).with("HIDE_COMMAND_OUTPUT", nil).and_return("true") + stub_env("HIDE_COMMAND_OUTPUT", "true") cmd = described_instance.send(:build_command, original_cmd, output_mode: :all) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 61532d2f..7409c390 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -31,6 +31,7 @@ require_relative "support/dummy_app_setup" require_relative "support/command_helpers" require_relative "support/date_time_helpers" +require_relative "support/stub_env" # This file was generated by the `rspec --init` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. @@ -130,6 +131,7 @@ config.include CommandHelpers config.include DateTimeHelpers + config.include StubENV config.verbose_retry = true config.display_try_failure_messages = true diff --git a/spec/support/stub_env.rb b/spec/support/stub_env.rb new file mode 100644 index 00000000..210f9628 --- /dev/null +++ b/spec/support/stub_env.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# Copied from https://gitlab.com/gitlab-org/gitlab/-/blob/master/gems/gitlab-rspec/lib/gitlab/rspec/stub_env.rb +module StubENV + # Stub ENV variables + # + # You can provide either a key and value as separate params or both in a Hash format + # + # Keys and values will always be converted to String, to comply with how ENV behaves + # + # @param key_or_hash [String, Hash] + # @param value [String] + def stub_env(key_or_hash, value = nil) + init_stub unless env_stubbed? + + if key_or_hash.is_a? Hash + key_or_hash.each do |key, value| + add_stubbed_value(key, ensure_env_type(value)) + end + else + add_stubbed_value key_or_hash, ensure_env_type(value) + end + end + + private + + STUBBED_KEY = "__STUBBED__" + + def add_stubbed_value(key, value) + allow(ENV).to receive(:[]).with(key).and_return(value) + allow(ENV).to receive(:key?).with(key).and_return(true) + allow(ENV).to receive(:fetch).with(key) do |_| + value || raise(KeyError, "key not found: \"#{key}\"") + end + allow(ENV).to receive(:fetch).with(key, anything) do |_, default_val| + value || default_val + end + end + + def env_stubbed? + ENV.fetch(STUBBED_KEY, false) + end + + def init_stub + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:key?).and_call_original + allow(ENV).to receive(:fetch).and_call_original + add_stubbed_value(STUBBED_KEY, true) + end + + def ensure_env_type(value) + value.nil? ? value : value.to_s + end +end diff --git a/spec/support_specs/stub_env_spec.rb b/spec/support_specs/stub_env_spec.rb new file mode 100644 index 00000000..999b469d --- /dev/null +++ b/spec/support_specs/stub_env_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require "support/stub_env" + +# Copied from https://gitlab.com/gitlab-org/gitlab/-/blob/master/gems/gitlab-rspec/lib/gitlab/rspec/stub_env.rb +RSpec.describe "StubENV" do + include StubENV + + describe "#stub_env" do + it "stubs the environment variable for all ways to read it" do + stub_env("MY_TEST_ENV_VAR", "the value") + + expect(ENV["MY_TEST_ENV_VAR"]).to eq("the value") # rubocop:disable Style/FetchEnvVar + expect(ENV.key?("MY_TEST_ENV_VAR")).to be(true) + expect(ENV.fetch("MY_TEST_ENV_VAR")).to eq("the value") + expect(ENV.fetch("MY_TEST_ENV_VAR", "some default")).to eq("the value") + end + + context "when stubbed to be nil" do + it "uses a default value for fetch and raises if no default given" do + stub_env("MY_TEST_ENV_VAR", nil) + + expect(ENV.fetch("MY_TEST_ENV_VAR", "some default")).to eq("some default") + expect { ENV.fetch("MY_TEST_ENV_VAR") }.to raise_error(KeyError) + end + end + end +end