wcc-data 0.3.9 → 0.4.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 39ee71b24991611f222411ff406d9d5b8bda3f0b
4
- data.tar.gz: 38c06caa2ebd8c97866dc5fdacdfe40c1140ed41
3
+ metadata.gz: 82f9b734e798bdb01d28323037ba25ea1a87a831
4
+ data.tar.gz: 46b3020ff169cdfa6e687c9933b765a5f7ed26a6
5
5
  SHA512:
6
- metadata.gz: 7dabe6eed115fcd58fd4c6b0c450b4caa70ba8778a2c14ffdff4eb0ecfc2dcb21b65259763a3ccc6e4805d2066c230073d56faabea8836a1ac82228aedf4e1f7
7
- data.tar.gz: 187c70f79ed1b2e9251f37d3d42efa032a5ce38aaef61aabc9df5232eb623be361630a398c123090f06212bab81152b8141fd7edd4cc87f4806d29b12d76a6ff
6
+ metadata.gz: b527b25651b9e1e0930ba6c0f4c4b816e929b9efc664910d1b5dd7ce42936840f2b1ab46e1489654c05490a145426bf3121fb9efd236e4cf03d4d596f8f582d5
7
+ data.tar.gz: 4cf4c852f51a72b46ff553539a72903ef218e314eaafe70651b6945c587efececd064e0f222f2508ba75e6825884954eec81fbf5fc1b64f733ec3e82be292483
data/.env.example ADDED
@@ -0,0 +1,3 @@
1
+ NUCLEUS_CLIENT_ID=client-id-3
2
+ NUCLEUS_CLIENT_SECRET=client-secret-3
3
+ NUCLEUS_URL=http://login.wcc/
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .env*.local
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wcc-data.gemspec
4
+ gemspec
5
+
6
+ gem 'rack', '~>1.6.5'
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'dotenv/tasks'
3
+
4
+ PROJECT_PATH = File.dirname(__FILE__)
5
+ LIB_PATH = File.join(PROJECT_PATH, "lib")
6
+
7
+ task :default => :test
8
+
9
+ desc 'run test examples'
10
+ task :test do
11
+ exec 'rspec .'
12
+ end
13
+
14
+ task :environment => :dotenv do
15
+ $LOAD_PATH.unshift(LIB_PATH)
16
+ require 'wcc/data'
17
+ end
18
+
19
+ task :development => [:environment] do
20
+ WCC::Data.setup do |config|
21
+ conn = config.applications[:nucleus].connection
22
+ conn.use Faraday::Response::Logger
23
+ conn.basic_auth(ENV['NUCLEUS_CLIENT_ID'], ENV['NUCLEUS_CLIENT_SECRET'])
24
+ end
25
+ end
26
+
27
+ desc 'launch IRB shell with base environment loaded'
28
+ task :irb => :environment do
29
+ require 'irb'
30
+ ARGV.clear
31
+ IRB.start
32
+ end
33
+
34
+ desc 'launch IRB shell with development environment loaded'
35
+ task :console => [:development, :irb]
36
+
data/bin/rspec ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'rspec' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("rspec-core", "rspec")
data/circle.yml ADDED
@@ -0,0 +1,6 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.2.2
4
+ dependencies:
5
+ pre:
6
+ - cp .env.example .env
@@ -1,64 +1,83 @@
1
+
2
+ begin
3
+ gem 'faraday'
4
+ require 'faraday'
5
+ rescue Gem::LoadError
6
+ # suppress
7
+ end
8
+
9
+
1
10
  module WCC::Data
2
- class FaradayClientAppTokenAuth < Faraday::Middleware
3
- class RedisCache
4
- DEFAULT_CACHE_KEY = "org.watermark.data.client-app-token-cache-store"
5
- attr_reader :connection, :cache_key
11
+ if defined?(Faraday)
12
+ class FaradayClientAppTokenAuth < Faraday::Middleware
13
+ class RedisCache
14
+ DEFAULT_CACHE_KEY = "org.watermark.data.client-app-token-cache-store"
15
+ attr_reader :connection, :cache_key
6
16
 
7
- def initialize(connection, cache_key: DEFAULT_CACHE_KEY)
8
- @connection = connection
9
- @cache_key = cache_key
10
- end
17
+ def initialize(connection, cache_key: DEFAULT_CACHE_KEY)
18
+ @connection = connection
19
+ @cache_key = cache_key
20
+ end
11
21
 
12
- def [](hostname)
13
- connection.call { |r| r.hget cache_key, hostname }
14
- end
22
+ def [](hostname)
23
+ connection.call { |r| r.hget cache_key, hostname }
24
+ end
15
25
 
16
- def []=(hostname, token)
17
- if token
18
- connection.call { |r| r.hset cache_key, hostname, token }
19
- else
20
- connection.call { |r| r.hdel cache_key, hostname }
26
+ def []=(hostname, token)
27
+ if token
28
+ connection.call { |r| r.hset cache_key, hostname, token }
29
+ else
30
+ connection.call { |r| r.hdel cache_key, hostname }
31
+ end
21
32
  end
22
33
  end
23
- end
24
34
 
25
- attr_reader :cache, :token_factory
35
+ attr_reader :cache, :token_factory
26
36
 
27
- def initialize(app, cache: default_cache, token_factory: method(:default_token_factory))
28
- super(app)
29
- @cache = cache
30
- @token_factory = token_factory
31
- end
37
+ def initialize(app, cache: default_cache, token_factory: method(:default_token_factory))
38
+ super(app)
39
+ @cache = cache
40
+ @token_factory = token_factory
41
+ end
32
42
 
33
- def token_for(host)
34
- @cache[host] ||= token_factory.(host)
35
- end
43
+ def token_for(host)
44
+ @cache[host] ||= token_factory.(host)
45
+ end
36
46
 
37
- def call(env, retry_on_forbidden: true)
38
- request_body = env[:body]
39
- host = env[:url].host
40
- env[:request_headers]["Authorization"] = "Bearer #{token_for(host)}"
41
- @app.call(env).on_complete do |response_env|
42
- response = Faraday::Response.new(response_env)
43
- cache[host] = nil unless response.success?
44
- if response.status == 403 && retry_on_forbidden
45
- env[:body] = request_body
46
- call(env, retry_on_forbidden: false)
47
+ def call(env, retry_on_forbidden: true)
48
+ request_body = env[:body]
49
+ host = env[:url].host
50
+ env[:request_headers]["Authorization"] = "Bearer #{token_for(host)}"
51
+ @app.call(env).on_complete do |response_env|
52
+ response = Faraday::Response.new(response_env)
53
+ cache[host] = nil unless response.success?
54
+ if response.status == 403 && retry_on_forbidden
55
+ env[:body] = request_body
56
+ call(env, retry_on_forbidden: false)
57
+ end
47
58
  end
48
59
  end
49
- end
50
60
 
51
- private
61
+ private
52
62
 
53
- def default_token_factory(host)
54
- WCC::Data::Nucleus::ClientAppToken.create(hostname: host).token
55
- end
63
+ def default_token_factory(host)
64
+ WCC::Data::Nucleus::ClientAppToken.create(hostname: host).token
65
+ end
56
66
 
57
- def default_cache
58
- RedisCache.new(Sidekiq.method(:redis))
67
+ def default_cache
68
+ RedisCache.new(Sidekiq.method(:redis))
69
+ end
70
+ end
71
+ else
72
+ class FaradayClientAppTokenAuth
73
+ def initialize(app, cache: default_cache, token_factory: method(:default_token_factory))
74
+ raise NotSupportedError, 'Please include the "faraday" gem to use this authentication method'
75
+ end
59
76
  end
60
77
  end
61
78
  end
62
79
 
63
- Faraday::Middleware.register_middleware :client_app_token => lambda { WCC::Data::FaradayClientAppTokenAuth }
80
+ if defined?(Faraday)
81
+ Faraday::Middleware.register_middleware :client_app_token => lambda { WCC::Data::FaradayClientAppTokenAuth }
82
+ end
64
83
 
@@ -27,11 +27,11 @@ module WCC::Data::Nucleus
27
27
  code: 'FTW',
28
28
  name: 'Fort Worth',
29
29
  key: :ft_worth,
30
- street: '8000 Western Hills Blvd',
30
+ street: '3345 Winthrop Avenue',
31
31
  city: 'Fort Worth',
32
32
  state: 'TX',
33
- zip: '76108',
34
- geo: [32.739972, -97.455414]
33
+ zip: '76116',
34
+ geo: [32.7280064, -97.4146727]
35
35
  },
36
36
  {
37
37
  id: 3,
@@ -54,28 +54,6 @@ module WCC::Data::Nucleus
54
54
  state: 'TX',
55
55
  zip: '75034',
56
56
  geo: [33.130761, -96.822322]
57
- },
58
- {
59
- id: 5,
60
- code: 'SDL',
61
- name: 'South Dallas',
62
- key: :south_dallas,
63
- street: '3400 Garden Ln',
64
- city: 'Dallas',
65
- state: 'TX',
66
- zip: '75215',
67
- geo: [32.758418, -96.743966]
68
- },
69
- {
70
- id: 6,
71
- code: 'ROC',
72
- name: 'Rockwall',
73
- key: :rockwall,
74
- street: '1565 Airport Rd',
75
- city: 'Rockwall',
76
- state: 'TX',
77
- zip: '75087',
78
- geo: [32.926936, -96.439255]
79
57
  }
80
58
  ]
81
59
  end
@@ -1,5 +1,5 @@
1
1
  module WCC
2
2
  module Data
3
- VERSION = '0.3.9'.freeze
3
+ VERSION = '0.4.0.pre'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,24 @@
1
+ SPEC_DIR = File.dirname(__FILE__)
2
+ FIXTURES_DIR = File.join(SPEC_DIR, "fixtures")
3
+
4
+ $LOAD_PATH.unshift File.join(SPEC_DIR, "..", "lib")
5
+ $LOAD_PATH.unshift SPEC_DIR
6
+
7
+ require 'dotenv'
8
+ Dotenv.load
9
+
10
+ require 'wcc/data'
11
+ require 'sidekiq'
12
+
13
+ Dir[File.join(SPEC_DIR, "support", "*.rb")].each do |support_file|
14
+ require "support/#{File.basename(support_file, ".rb")}"
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+ config.run_all_when_everything_filtered = true
19
+ config.filter_run :focus
20
+
21
+ config.order = 'random'
22
+
23
+ ENV['NUCLEUS_URL'] ||= 'http://login.wcc'
24
+ end
@@ -0,0 +1,16 @@
1
+ shared_examples_for :inheritable_class_attributes do |name|
2
+ let(:subclass) { Class.new(subject) }
3
+
4
+ it "inherited value is the same as parent class" do
5
+ subject.send(:instance_variable_set, :"@#{name}", foo: :bar)
6
+ expect(subject.send(name)).to eq(foo: :bar)
7
+ expect(subclass.send(name)).to eq(foo: :bar)
8
+ end
9
+
10
+ it "inherited reference is unique from the parent class" do
11
+ subject.send(:instance_variable_set, :"@#{name}", foo: :bar)
12
+ subclass.send(name)[:bar] = :baz
13
+ expect(subject.send(name)).to eq(foo: :bar)
14
+ end
15
+ end
16
+
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ describe WCC::Data::Config::Application do
4
+ let(:unit) { WCC::Data::Config::Application }
5
+ subject { unit.new(:name) }
6
+
7
+ describe "#initialize" do
8
+ it "takes a single name symbol and stores in @name" do
9
+ obj = unit.new(:name)
10
+ expect(obj.name).to eq(:name)
11
+ end
12
+
13
+ it "takes a connection option and stores it in @connection" do
14
+ obj = unit.new(:name, connection: "foo")
15
+ expect(obj.connection).to eq("foo")
16
+ end
17
+
18
+ it "sets to a blank Faraday::Connection" do
19
+ obj = unit.new(:name)
20
+ expect(obj.connection).to be_a(Faraday::Connection)
21
+ end
22
+ end
23
+
24
+ describe "#uri=" do
25
+ it "converts a string to a URI and stores in @uri" do
26
+ subject.uri = "http://test"
27
+ expect(subject.uri).to be_a(URI)
28
+ expect(subject.uri.scheme).to eq("http")
29
+ end
30
+
31
+ it "uses the URI object if set with a URI" do
32
+ subject.uri = test_value = URI("http://test")
33
+ expect(subject.uri).to eq(test_value)
34
+ end
35
+ end
36
+
37
+ describe "#service" do
38
+ before(:each) do
39
+ subject.uri = "http://test.com/"
40
+ end
41
+
42
+ it "returns a service object based on the URI" do
43
+ obj = subject.service
44
+ expect(obj).to be_a(WCC::Data::Service)
45
+ expect(obj.uri).to eq(subject.uri)
46
+ end
47
+
48
+ it "passes the application connection through to the service" do
49
+ obj = subject.service
50
+ expect(obj.connection).to eq(subject.connection)
51
+ end
52
+ end
53
+
54
+ describe "@connection" do
55
+ it "gets and sets" do
56
+ subject.connection = "foo"
57
+ expect(subject.connection).to eq("foo")
58
+ end
59
+ end
60
+ end
61
+
62
+ describe WCC::Data::Config do
63
+ let(:unit) { WCC::Data::Config }
64
+ subject { unit.new }
65
+
66
+
67
+ describe "#applications" do
68
+ it "returns a hash" do
69
+ expect(subject.applications).to be_a(Hash)
70
+ end
71
+
72
+ it "defaults empty keys to an application" do
73
+ expect(subject.applications[:foo]).to be_a(WCC::Data::Config::Application)
74
+ end
75
+
76
+ it "contains a default entry for :nucleus" do
77
+ expect(subject.applications[:nucleus].uri).to eq(
78
+ URI(ENV['NUCLEUS_URL'])
79
+ )
80
+ end
81
+
82
+ context "with APP_CLIENT_ID and APP_CLIENT_SECRET ENV vars set" do
83
+ after do
84
+ ENV['APP_CLIENT_ID'] = ENV['APP_CLIENT_SECRET'] = nil
85
+ end
86
+
87
+ it "sets the connection's basic auth for nucleus" do
88
+ ENV['APP_CLIENT_ID'] = "test"
89
+ ENV['APP_CLIENT_SECRET'] = "value"
90
+
91
+ header = subject.applications[:nucleus].connection.headers["Authorization"]
92
+
93
+ expect(header)
94
+ .to eq(Faraday::Request::BasicAuthentication.header("test", "value"))
95
+ end
96
+ end
97
+
98
+ context "with APP_CLIENT_ID and APP_CLIENT_SECRET not both set" do
99
+ it "does not set the basic auth for nucleus" do
100
+ header = subject.applications[:nucleus].connection.headers["Authorization"]
101
+
102
+ expect(header).to be_nil
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "#apps alias" do
108
+ it "aliases to #applications" do
109
+ expect(subject.apps).to eq(subject.applications)
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,176 @@
1
+ require "spec_helper"
2
+
3
+ describe WCC::Data::EnumeratedType do
4
+
5
+ context "with configured attributes" do
6
+ let(:type) {
7
+ Class.new(described_class) do
8
+ attributes :test1, :test2
9
+ end
10
+ }
11
+ let(:object) { type.new(data) }
12
+ let(:data) {
13
+ {
14
+ test1: "test data 1",
15
+ test2: "test data 2",
16
+ ignored: "",
17
+ }
18
+ }
19
+
20
+ it "adds a method for all arguments passed" do
21
+ expect(object).to respond_to(:test1)
22
+ expect(object).to respond_to(:test2)
23
+ end
24
+
25
+ it "sets values from initialize hash" do
26
+ expect(object.test1).to eq("test data 1")
27
+ expect(object.test2).to eq("test data 2")
28
+ end
29
+
30
+ describe "::defined_attributes" do
31
+ it "should return attributes" do
32
+ expect(type.defined_attributes).to eq([:test1, :test2])
33
+ end
34
+ end
35
+ end
36
+
37
+ context "with child classes" do
38
+ let(:parent) {
39
+ Class.new(described_class) do
40
+ attributes :attr1
41
+ attributes :attr2
42
+ end
43
+ }
44
+ let(:child) {
45
+ Class.new(parent) do
46
+ attributes :attr3, :attr4
47
+ end
48
+ }
49
+ let(:parent_object) { parent.new(data) }
50
+ let(:child_object) { child.new(data) }
51
+ let(:data) {
52
+ {
53
+ attr1: "data1",
54
+ attr2: "data2",
55
+ attr3: "data3",
56
+ attr4: "data4",
57
+ }
58
+ }
59
+
60
+ describe "parent class" do
61
+ it "does not include child attributes" do
62
+ expect(parent_object).to_not respond_to(:attr3)
63
+ expect(parent_object).to_not respond_to(:attr4)
64
+ end
65
+
66
+ it "includes both attributes" do
67
+ expect(parent_object).to respond_to(:attr1)
68
+ expect(parent_object).to respond_to(:attr2)
69
+ end
70
+
71
+ it "sets both attributes on initialize" do
72
+ expect(parent_object.attr1).to eq("data1")
73
+ expect(parent_object.attr2).to eq("data2")
74
+ end
75
+ end
76
+
77
+ describe "child class" do
78
+ it "includes all defined_attributes" do
79
+ expect(child.defined_attributes).to eq([:attr1, :attr2, :attr3, :attr4])
80
+ end
81
+
82
+ it "includes parent attributes and child attributes readers" do
83
+ expect(child_object.attr1).to eq("data1")
84
+ expect(child_object.attr2).to eq("data2")
85
+ expect(child_object.attr3).to eq("data3")
86
+ expect(child_object.attr4).to eq("data4")
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ context "with db, matches?, and attributes configured" do
93
+ let(:type) {
94
+ Class.new(described_class) do
95
+ attributes :id, :name, :key
96
+
97
+ def matches?(value)
98
+ [id, key].include?(value)
99
+ end
100
+
101
+ def self.db
102
+ [
103
+ { id: 1, name: "One", key: :one },
104
+ { id: 2, name: "Two", key: :two },
105
+ { id: 3, name: "Three", key: :three },
106
+ { id: 4, name: "Four", key: :three },
107
+ ]
108
+ end
109
+ end
110
+ }
111
+
112
+ describe "::[]" do
113
+ it "returns an instance of type if match found" do
114
+ expect(type[1]).to be_a(type)
115
+ end
116
+
117
+ it "returns nil if no match found" do
118
+ expect(type[:nil]).to be_nil
119
+ end
120
+
121
+ it "returns first match when multiple matches present" do
122
+ expect(type[:three]).to eq(type.all[2])
123
+ end
124
+ end
125
+
126
+ describe "::all" do
127
+ it "returns instances of EnumeratedType for each item in db" do
128
+ expect(type.all.size).to eq(4)
129
+ expect(type.all[0]).to be_a(type)
130
+ expect(type.all[1]).to be_a(type)
131
+ expect(type.all[2]).to be_a(type)
132
+ expect(type.all[3]).to be_a(type)
133
+ end
134
+
135
+ it "sets attributes for each record properly" do
136
+ expect(type.all[0].id).to eq(1)
137
+ expect(type.all[0].name).to eq("One")
138
+ expect(type.all[0].key).to eq(:one)
139
+ expect(type.all[1].key).to eq(:two)
140
+ expect(type.all[2].key).to eq(:three)
141
+ end
142
+
143
+ it "caches the results" do
144
+ expect(type.all[0].object_id).to eq(type.all[0].object_id)
145
+ end
146
+ end
147
+
148
+ describe "::reset" do
149
+ it "clears out all and forces new object creation" do
150
+ first_id = type.all[0].object_id
151
+ type.reset
152
+ expect(type.all[0].object_id).to_not eq(first_id)
153
+ end
154
+ end
155
+ end
156
+
157
+ describe "#initialize" do
158
+ it "allows passing no argument" do
159
+ expect { described_class.new }.to_not raise_error
160
+ end
161
+ end
162
+
163
+ describe "::db" do
164
+ it "raises NotImplementedError with instructions" do
165
+ expect { described_class.db }.to raise_error(NotImplementedError, /subclass/i)
166
+ end
167
+ end
168
+
169
+ describe "#matches?" do
170
+ it "raises NotImplementedError with instructions" do
171
+ object = described_class.new({})
172
+ expect { object.matches?(:val) }.to raise_error(NotImplementedError, /subclass/i)
173
+ end
174
+ end
175
+
176
+ end