Refactor and add some specs

This commit is contained in:
Andrew Tomaka 2018-03-28 21:51:39 -04:00
parent 84383e8911
commit abf0f6c2b3
Signed by: atomaka
GPG key ID: 61209BF70A5B18BE
9 changed files with 232 additions and 22 deletions

View file

@ -28,6 +28,8 @@ GEM
i18n (~> 0.7) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
aws-partitions (1.71.0) aws-partitions (1.71.0)
aws-sdk-core (3.17.1) aws-sdk-core (3.17.1)
aws-partitions (~> 1.0) aws-partitions (~> 1.0)
@ -39,9 +41,12 @@ GEM
aws-sigv4 (1.0.2) aws-sigv4 (1.0.2)
builder (3.2.3) builder (3.2.3)
concurrent-ruby (1.0.5) concurrent-ruby (1.0.5)
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.3) crass (1.0.3)
diff-lcs (1.3) diff-lcs (1.3)
erubi (1.7.1) erubi (1.7.1)
hashdiff (0.3.7)
i18n (0.9.5) i18n (0.9.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
jmespath (1.3.1) jmespath (1.3.1)
@ -53,6 +58,7 @@ GEM
minitest (5.11.3) minitest (5.11.3)
nokogiri (1.8.2) nokogiri (1.8.2)
mini_portile2 (~> 2.3.0) mini_portile2 (~> 2.3.0)
public_suffix (3.0.2)
rack (2.0.4) rack (2.0.4)
rack-test (0.8.3) rack-test (0.8.3)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
@ -81,10 +87,15 @@ GEM
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0) rspec-support (~> 3.7.0)
rspec-support (3.7.1) rspec-support (3.7.1)
safe_yaml (1.0.4)
thor (0.20.0) thor (0.20.0)
thread_safe (0.3.6) thread_safe (0.3.6)
tzinfo (1.2.5) tzinfo (1.2.5)
thread_safe (~> 0.1) thread_safe (~> 0.1)
webmock (3.3.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
PLATFORMS PLATFORMS
ruby ruby
@ -95,6 +106,7 @@ DEPENDENCIES
psenv-rails! psenv-rails!
rake (~> 10.0) rake (~> 10.0)
rspec (~> 3.0) rspec (~> 3.0)
webmock (~> 3.3)
BUNDLED WITH BUNDLED WITH
1.16.1 1.16.1

View file

@ -6,15 +6,15 @@ if defined?(Rake.application)
end end
module Psenv module Psenv
class Railtie < Rails::Railtie class Railtie < Rails::Railtie
def load def load
Psenv.load Psenv.load
end end
def self.load def self.load
instance.load instance.load
end end
config.before_configuration { load } config.before_configuration { load }
end end
end end

View file

@ -1,3 +1,5 @@
require "psenv/environment"
require "psenv/retriever"
require "psenv/version" require "psenv/version"
require "aws-sdk-ssm" require "aws-sdk-ssm"
@ -5,19 +7,17 @@ require "aws-sdk-ssm"
module Psenv module Psenv
module_function module_function
def load def load(*paths)
if ENV["PARAMETER_STORE_PATH"] != nil paths.unshift(ENV["PARAMETER_STORE_PATH"]) if ENV["PARAMETER_STORE_PATH"]
ssm = Aws::SSM::Client.new Environment.create(*paths.map { |path| retrieve_variables(path) }).apply
end
ssm. def overload(*paths)
get_parameters_by_path( paths.unshift(ENV["PARAMETER_STORE_PATH"]) if ENV["PARAMETER_STORE_PATH"]
path: ENV["PARAMETER_STORE_PATH"], Environment.create(*paths.map { |path| retrieve_variables(path) }).apply!
with_decryption: true, end
).
parameters. def retrieve_variables(path)
each do |param| Retriever.new(path).call
ENV.store(param.name.split("/").last, param.value)
end
end
end end
end end

15
lib/psenv/environment.rb Normal file
View file

@ -0,0 +1,15 @@
module Psenv
class Environment < Hash
def apply
each { |k, v| ENV.store(k, v) unless ENV.has_key?(k) }
end
def apply!
each { |k, v| ENV.store(k, v) }
end
def self.create(*variables)
Environment[variables.reverse.reduce({}, :merge)]
end
end
end

48
lib/psenv/retriever.rb Normal file
View file

@ -0,0 +1,48 @@
require "aws-sdk-ssm"
module Psenv
class RetrieveError < StandardError; end
class Parameter
attr_reader :name, :value
def initialize(parameter)
@name = parameter[:name].split("/").last
@value = parameter[:value]
@type = parameter[:type]
@version = parameter[:version]
end
end
class Retriever
def initialize(path)
@path = path
end
def call
Hash[
parameters.
map { |parameter| Parameter.new(parameter) }.
map { |parameter| [parameter.name, parameter.value] }
]
end
def self.call(path)
new(path).call
end
private
def ssm
@ssm ||= Aws::SSM::Client.new
end
def parameters
ssm.
get_parameters_by_path(path: @path, with_decryption: true).
parameters
rescue StandardError => error
raise RetrieveError, error
end
end
end

View file

@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "bundler", "~> 1.16" spec.add_development_dependency "bundler", "~> 1.16"
spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "~> 3.0" spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency "webmock", "~> 3.3"
spec.add_dependency "aws-sdk-ssm", "~> 1" spec.add_dependency "aws-sdk-ssm", "~> 1"
end end

24
spec/psenv_rails_spec.rb Normal file
View file

@ -0,0 +1,24 @@
require "spec_helper"
require "rails"
require "psenv-rails"
RSpec.describe Psenv::Railtie do
before(:each) do
Rails.env = "test"
Rails.application = double(:application)
end
context "before_configuration" do
it "calls #load" do
expect(Psenv::Railtie.instance).to receive(:load)
ActiveSupport.run_load_hooks(:before_configuration)
end
end
context ".load" do
it "calls Psenv.load" do
expect(Psenv).to receive(:load)
Psenv::Railtie.load
end
end
end

View file

@ -1,7 +1,114 @@
require "spec_helper"
RSpec.describe Psenv do RSpec.describe Psenv do
let(:env_path) { "/env/" }
let(:arg_paths) { ["/arg1/", "/arg2"] }
let(:env_variables) { { TEST: "env", ANOTHER: "env" } }
let(:arg_variables) do
[{ ONE: "arg1", TWO: "arg1" }, { TWO: "arg2", THREE: "arg2" }]
end
let(:retriever1) { double(:retriever) }
let(:retriever2) { double(:retriever) }
let(:retriever3) { double(:retriever) }
let(:environment) { double(:environment) }
before(:each) do
allow(Psenv::Retriever).to receive(:new).with(env_path) { retriever1 }
allow(Psenv::Retriever).to receive(:new).with(arg_paths[0]) { retriever2 }
allow(Psenv::Retriever).to receive(:new).with(arg_paths[1]) { retriever3 }
allow(retriever1).to receive(:call) { env_variables }
allow(retriever2).to receive(:call) { arg_variables[0] }
allow(retriever3).to receive(:call) { arg_variables[1] }
allow(Psenv::Environment).to receive(:create) { environment }
allow(environment).to receive(:apply)
allow(environment).to receive(:apply!)
ENV.store("PARAMETER_STORE_PATH", nil)
end
it "has a version number" do it "has a version number" do
expect(Psenv::VERSION).not_to be nil expect(Psenv::VERSION).not_to be nil
end end
it "tests something useful" context ".load" do
context "when PARAMETER_STORE_PATH is set" do
before(:each) do
ENV.store("PARAMETER_STORE_PATH", env_path)
Psenv.load
end
it "retrieves the correct path" do
expect(Psenv::Retriever).to have_received(:new).with(env_path)
end
it "creates the environment with the correct variables" do
expect(Psenv::Environment).
to have_received(:create).with(env_variables)
end
it "applies the environment" do
expect(environment).to have_received(:apply)
end
end
context "when paths are passed in" do
before(:each) { Psenv.load(*arg_paths) }
it "retrieves the correct paths" do
arg_paths.each do |path|
expect(Psenv::Retriever).to have_received(:new).with(path)
end
end
it "creates the environment with the correct variables" do
expect(Psenv::Environment).
to have_received(:create).with(*arg_variables)
end
it "apples the environment" do
expect(environment).to have_received(:apply)
end
end
end
context ".overload" do
context "when PARAMETER_STORE_PATH is set" do
before(:each) do
ENV.store("PARAMETER_STORE_PATH", env_path)
Psenv.overload
end
it "retrieves the correct path" do
expect(Psenv::Retriever).to have_received(:new).with(env_path)
end
it "creates the environment with the correct variables" do
expect(Psenv::Environment).
to have_received(:create).with(env_variables)
end
it "applies the environment" do
expect(environment).to have_received(:apply!)
end
end
context "when paths are passed in" do
before(:each) { Psenv.overload(*arg_paths) }
it "retrieves the correct paths" do
arg_paths.each do |path|
expect(Psenv::Retriever).to have_received(:new).with(path)
end
end
it "creates the environment with the correct variables" do
expect(Psenv::Environment).
to have_received(:create).with(*arg_variables)
end
it "apples the environment" do
expect(environment).to have_received(:apply!)
end
end
end
end end

View file

@ -1,6 +1,9 @@
require "bundler/setup" require "bundler/setup"
require 'webmock/rspec'
require "psenv" require "psenv"
WebMock.disable_net_connect!(allow_localhost: true)
RSpec.configure do |config| RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure # Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status" config.example_status_persistence_file_path = ".rspec_status"