wcc-data 0.3.9 → 0.4.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,219 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe WCC::Data::RackClientAppTokenAuth do
4
+
5
+ describe WCC::Data::RackClientAppTokenAuth::RedisCache do
6
+ let(:connection) { instance_spy(Redis) }
7
+ let(:connection_lambda) { -> (&blk) { blk.call(connection) } }
8
+
9
+ describe "#initialize" do
10
+ it "requires a callable for Redis connection" do
11
+ expect { described_class.new }.to raise_error(ArgumentError)
12
+ obj = described_class.new(connection_lambda)
13
+ expect(obj.connection).to eq(connection_lambda)
14
+ end
15
+
16
+ it "allows setting a :cache_key option to change the token store" do
17
+ obj = described_class.new(connection_lambda, cache_key: "store")
18
+ expect(obj.cache_key).to eq("store")
19
+ end
20
+
21
+ it "allows setting the :cache_length" do
22
+ obj = described_class.new(connection_lambda, cache_length: 5)
23
+ expect(obj.cache_length).to eq(5)
24
+ end
25
+
26
+ it "defaults :cache_key to the value of the DEFAULT_CACHE_KEY constant" do
27
+ obj = described_class.new(connection_lambda)
28
+ expect(obj.cache_key).to eq(described_class::DEFAULT_CACHE_KEY)
29
+ end
30
+
31
+ it "defaults :cache_length to the value of DEFAULT_CACHE_LENGTH constant" do
32
+ obj = described_class.new(connection_lambda)
33
+ expect(obj.cache_length).to eq(described_class::DEFAULT_CACHE_LENGTH)
34
+ end
35
+ end
36
+
37
+ describe "#<<" do
38
+ subject(:auth) { described_class.new(connection_lambda, cache_key: "test", cache_length: 123) }
39
+
40
+ it "calls SET with @cache_key joined to token by a dot and set to '1'" do
41
+ auth << "token"
42
+ expect(connection).to have_received(:set).with("test.token", "1")
43
+ end
44
+
45
+ it "calls EXPIRE with the configured cache length" do
46
+ auth << "token"
47
+ expect(connection).to have_received(:expire).with("test.token", 123)
48
+ end
49
+ end
50
+
51
+ describe "#find" do
52
+ subject(:auth) { described_class.new(connection_lambda, cache_key: "test") }
53
+
54
+ it "returns the value from GET on the joined token key" do
55
+ expect(connection).to receive(:get).with("test.token").and_return("1")
56
+ expect(auth.find("token")).to eq("1")
57
+ end
58
+ end
59
+ end
60
+
61
+ describe "#initialize" do
62
+ it "takes an app argument and sets to @app" do
63
+ obj = described_class.new(:app)
64
+ expect(obj.app).to eq(:app)
65
+ end
66
+
67
+ it "takes a :cache option and sets to @cache" do
68
+ obj = described_class.new(:app, cache: :cache)
69
+ expect(obj.cache).to eq(:cache)
70
+ end
71
+
72
+ it "takes a :lookup_token and sets to @lookup_token" do
73
+ obj = described_class.new(:app, lookup_token: :lookup)
74
+ expect(obj.lookup_token).to eq(:lookup)
75
+ end
76
+
77
+ it "defaults :cache option to an instance of RedisCache" do
78
+ obj = described_class.new(:app)
79
+ expect(obj.cache).to be_a(described_class::RedisCache)
80
+ expect(obj.cache.connection).to eq(Sidekiq.method(:redis))
81
+ end
82
+
83
+ describe "default :lookup_token value" do
84
+ it "tries to fetch a token with the given value" do
85
+ expect(WCC::Data::Nucleus::ClientAppToken)
86
+ .to receive(:find).with("abc123").and_return(:val)
87
+ expect(described_class.new(:app).lookup_token.("abc123"))
88
+ .to eq(:val)
89
+ end
90
+
91
+ it "returns nil when InvalidResponse raised" do
92
+ allow(WCC::Data::Nucleus::ClientAppToken)
93
+ .to receive(:find).and_raise(WCC::Data::Mapper::InvalidResponse)
94
+ expect(described_class.new(:app).lookup_token.("abc123"))
95
+ .to be_nil
96
+ end
97
+
98
+ it "returns nil when RecordNotFound raised" do
99
+ allow(WCC::Data::Nucleus::ClientAppToken)
100
+ .to receive(:find).and_raise(WCC::Data::Mapper::RecordNotFound)
101
+ expect(described_class.new(:app).lookup_token.("abc123"))
102
+ .to be_nil
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ describe "#find" do
109
+ let(:cache) { instance_spy(described_class::RedisCache) }
110
+ subject(:auth) { described_class.new(:app, cache: cache) }
111
+
112
+ context "with token in the cache" do
113
+ before do
114
+ allow(auth.cache).to receive(:find).with("abc123").and_return("1")
115
+ end
116
+
117
+ it "calls find with token on the cache and then returns cached value" do
118
+ expect(auth.find("abc123"))
119
+ .to eq("1")
120
+ end
121
+
122
+ it "does not call lookup_token" do
123
+ expect(auth.lookup_token).to_not receive(:call)
124
+ auth.find("abc123")
125
+ end
126
+ end
127
+
128
+ context "with an empty cache" do
129
+ before do
130
+ allow(cache).to receive(:find).and_return(nil)
131
+ end
132
+
133
+ it "calls lookup_token with the token" do
134
+ expect(auth.lookup_token)
135
+ .to receive(:call).with("abc123").and_return(true)
136
+ expect(auth.find("abc123")).to eq(true)
137
+ end
138
+
139
+ context "with a valid token" do
140
+ before do
141
+ allow(auth.lookup_token).to receive(:call).and_return(true)
142
+ end
143
+
144
+ it "shovels the value into the cache" do
145
+ expect(cache).to receive(:<<).with("abc123")
146
+ auth.find("abc123")
147
+ end
148
+
149
+ it "returns a truthy value" do
150
+ expect(auth.find("abc123")).to be_truthy
151
+ end
152
+ end
153
+
154
+ context "with an invalid token" do
155
+ before do
156
+ allow(auth.lookup_token).to receive(:call).and_return(false)
157
+ end
158
+
159
+ it "does not shovel value into the cache" do
160
+ expect(auth.cache).to_not receive(:<<)
161
+ auth.find("abc123")
162
+ end
163
+
164
+ it "returns a falsey value" do
165
+ expect(auth.find("abc123")).to be_falsey
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ describe "#call" do
172
+ subject(:auth) { described_class.new(-> (env) {}, cache: cache) }
173
+ let(:cache) { instance_spy(described_class::RedisCache) }
174
+ let(:env) {
175
+ {
176
+ "HTTP_AUTHORIZATION" => "Bearer abc123",
177
+ }
178
+ }
179
+
180
+
181
+ it "passes the bearer token onto the find method" do
182
+ expect(auth).to receive(:find).with("abc123")
183
+ auth.call(env)
184
+ end
185
+
186
+ context "truthy find result" do
187
+ before do
188
+ allow(auth).to receive(:find).and_return(true)
189
+ end
190
+
191
+ it "passes the request on to the app" do
192
+ expect(auth.app).to receive(:call).with(env)
193
+ auth.call(env)
194
+ end
195
+
196
+ it "returns the value of app" do
197
+ allow(auth.app).to receive(:call).and_return(:value)
198
+ expect(auth.call(env)).to eq(:value)
199
+ end
200
+ end
201
+
202
+ context "falsey find result" do
203
+ before do
204
+ allow(auth).to receive(:find).and_return(false)
205
+ end
206
+
207
+ it "does not call app" do
208
+ expect(auth.app).to_not receive(:call)
209
+ auth.call(env)
210
+ end
211
+
212
+ it "returns a 403 response" do
213
+ response = auth.call(env)
214
+
215
+ expect(response).to eq([403, {}, ['{"error":"Invalid Bearer Token"}']])
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe WCC::Data::Response do
4
+ let(:unit) { WCC::Data::Response }
5
+ let(:raw) { double(:faraday_response) }
6
+ subject { unit.new(raw) }
7
+
8
+ describe "#initialize" do
9
+ it "takes a Faraday response object and sets it to @raw" do
10
+ expect(subject.raw).to eq(raw)
11
+ end
12
+ end
13
+
14
+ describe "method delegation" do
15
+ it "delegates `body` to @raw" do
16
+ expect(raw).to receive(:body).and_return(:value)
17
+ expect(subject.body).to eq(:value)
18
+ expect(subject.respond_to?(:body)).to be_truthy
19
+ end
20
+
21
+ it "delegates `headers` to @raw" do
22
+ expect(raw).to receive(:headers).and_return(:value)
23
+ expect(subject.headers).to eq(:value)
24
+ expect(subject.respond_to?(:headers)).to be_truthy
25
+ end
26
+
27
+ it "delegates `status` to @raw" do
28
+ expect(raw).to receive(:status).and_return(:value)
29
+ expect(subject.status).to eq(:value)
30
+ expect(subject.respond_to?(:status)).to be_truthy
31
+ end
32
+
33
+ it "delegates `success?` to @raw" do
34
+ expect(raw).to receive(:success?).and_return(:value)
35
+ expect(subject.success?).to eq(:value)
36
+ expect(subject.respond_to?(:success?)).to be_truthy
37
+ end
38
+ end
39
+
40
+ describe "#json" do
41
+ it "returns JSON deserialized body" do
42
+ expect(raw).to receive(:body) {
43
+ %[{"name":"Bob","interests":["Fishing","Rowing","Golfing"]}]
44
+ }
45
+ expect(subject.json).to eq({
46
+ "name" => "Bob",
47
+ "interests" => ["Fishing", "Rowing", "Golfing"],
48
+ })
49
+ end
50
+
51
+ it "returns nil if body is not valid JSON" do
52
+ expect(raw).to receive(:body) { "" }
53
+ expect(subject.json).to be_nil
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe WCC::Data::RESTEndpoint do
4
+ let(:service) { WCC::Data::Service.new }
5
+ subject { described_class.new(service: service) }
6
+
7
+ describe "#initialize" do
8
+ subject { described_class }
9
+ it "sets @service from :service option" do
10
+ obj = subject.new(service: service)
11
+ expect(obj.service).to eq(service)
12
+ end
13
+ end
14
+
15
+ shared_examples_for :rest_method_general_options do |method, verb, args|
16
+ let(:test_args) {
17
+ { foo: "bar", baz: "bing" }
18
+ }
19
+ it "takes a hash as last argument and passes to underlying service" do
20
+ args = Array(args)
21
+ expect(service).to receive(verb).with(hash_including(test_args))
22
+ subject.public_send(method, *args, test_args)
23
+ end
24
+ end
25
+
26
+ describe "#index" do
27
+ it_behaves_like :rest_method_general_options, :index, :get
28
+
29
+ it "calls #get directly on service" do
30
+ expect(service).to receive(:get).and_return("hi there")
31
+ expect(subject.index).to eq("hi there")
32
+ end
33
+ end
34
+
35
+ describe "#show" do
36
+ it_behaves_like :rest_method_general_options, :show, :get, 1
37
+
38
+ it "calls #get on service adding the id param to the URI" do
39
+ expect(service).to receive(:get).with(uri: "123").and_return("yo")
40
+ expect(subject.show(123)).to eq("yo")
41
+ end
42
+ end
43
+
44
+ describe "#create" do
45
+ it_behaves_like :rest_method_general_options, :create, :post, { test: 1 }
46
+
47
+ it "calls #post on service with attrs hash as body" do
48
+ expect(service).to receive(:post).with(body: { foo: "bar" }).and_return("hey bra")
49
+ expect(subject.create(foo: "bar")).to eq("hey bra")
50
+ end
51
+ end
52
+
53
+ describe "#update" do
54
+ it_behaves_like :rest_method_general_options, :update, :patch, [1, { test: 1 }]
55
+
56
+ it "calls #patch on service with id as URI and attrs as body" do
57
+ expect(service).to receive(:patch).with(uri: "123", body: {}).and_return("sup")
58
+ expect(subject.update(123, {})).to eq("sup")
59
+ end
60
+ end
61
+
62
+ describe "#destroy" do
63
+ it_behaves_like :rest_method_general_options, :destroy, :delete, 1
64
+
65
+ it "calls #delete on service with id as URI" do
66
+ expect(service).to receive(:delete).with(uri: "123").and_return("oh noes!")
67
+ expect(subject.destroy(123)).to eq("oh noes!")
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ describe WCC::Data::Service do
4
+ let(:unit) { WCC::Data::Service }
5
+ let(:connection) { double() }
6
+ let(:default_args) {
7
+ {
8
+ uri: "http://test.com/foo/",
9
+ connection: connection,
10
+ }
11
+ }
12
+ subject { unit.new(default_args) }
13
+
14
+ describe "#initialize" do
15
+ it "sets :uri to @uri" do
16
+ expect(subject.uri).to eq(URI(default_args[:uri]))
17
+ end
18
+
19
+ it "sets :connection to @connection" do
20
+ expect(subject.connection).to eq(default_args[:connection])
21
+ end
22
+ end
23
+
24
+ describe "#merge" do
25
+ it "returns a new instance" do
26
+ merged = subject.merge
27
+ expect(merged).to be_a(unit)
28
+ expect(merged.object_id).to_not eq(subject.object_id)
29
+ end
30
+
31
+ it "merges the URI params" do
32
+ merged = subject.merge(uri: "bar/baz?query")
33
+ expect(merged.uri.path).to eq("/foo/bar/baz")
34
+ expect(merged.uri.query).to eq("query")
35
+ end
36
+
37
+ it "sets to the right instance's @connection" do
38
+ connection = :bar
39
+ merged = subject.merge(connection: connection)
40
+ expect(merged.connection).to eq(connection)
41
+ end
42
+
43
+ it "accepts a hash of arguments as well as an instance" do
44
+ right = unit.new(uri: "bar", connection: double())
45
+ merged = subject.merge(right)
46
+ expect(merged.uri).to eq(URI("http://test.com/foo/bar"))
47
+ expect(merged.connection).to eq(right.connection)
48
+ end
49
+
50
+ end
51
+
52
+ shared_examples_for :http_verb_methods do
53
+ it "request verb matches the method name" do
54
+ expect(connection).to receive(:run_request) do |verb, _, _, _|
55
+ expect(verb).to eq(method)
56
+ end
57
+ subject.send(method, {})
58
+ end
59
+
60
+ it "returns a WCC::Data::Response instance" do
61
+ expect(connection).to receive(:run_request) {}
62
+ expect(subject.send(method, {})).to be_a(WCC::Data::Response)
63
+ end
64
+
65
+ it "merges :uri arg onto @uri" do
66
+ expect(connection).to receive(:run_request) do |_, url, _, _|
67
+ expect(url).to eq(URI("http://test.com/foo/bar"))
68
+ end
69
+ subject.send(method, uri: "bar")
70
+ end
71
+
72
+ it "sets the request body with :body arg" do
73
+ expect(connection).to receive(:run_request) do |_, _, body, _|
74
+ expect(body).to eq("a string")
75
+ end
76
+ subject.send(method, body: "a string")
77
+ end
78
+
79
+ it "provides request headers with :headers arg" do
80
+ expect(connection).to receive(:run_request) do |_, _, _, headers|
81
+ expect(headers).to eq(:foo)
82
+ end
83
+ subject.send(method, headers: :foo)
84
+ end
85
+
86
+ it "updates the params on the request if :params argument provided" do
87
+ params = { foo: "bar" }
88
+ request = double(params: double(:params))
89
+ expect(connection).to receive(:run_request).and_yield(request)
90
+
91
+ expect(request.params).to receive(:update).with(params)
92
+ subject.send(method, params: params)
93
+ end
94
+
95
+ it "does not update the params on the request if :params is nil" do
96
+ request = double(params: double(:params))
97
+ expect(connection).to receive(:run_request).and_yield(request)
98
+ expect(request.params).to_not receive(:update)
99
+ subject.send(method, {})
100
+ end
101
+ end
102
+
103
+ describe "#get" do
104
+ let(:method) { :get }
105
+ it_behaves_like :http_verb_methods
106
+ end
107
+
108
+ describe "#post" do
109
+ let(:method) { :post }
110
+ it_behaves_like :http_verb_methods
111
+ end
112
+
113
+ describe "#put" do
114
+ let(:method) { :put }
115
+ it_behaves_like :http_verb_methods
116
+ end
117
+
118
+ describe "#patch" do
119
+ let(:method) { :patch }
120
+ it_behaves_like :http_verb_methods
121
+ end
122
+
123
+ describe "#delete" do
124
+ let(:method) { :delete }
125
+ it_behaves_like :http_verb_methods
126
+ end
127
+
128
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe WCC::Data do
4
+
5
+ describe "::config" do
6
+ it "returns a cached instance of Config" do
7
+ config = WCC::Data.config
8
+ expect(config).to be_a(WCC::Data::Config)
9
+ expect(WCC::Data.config).to eq(config)
10
+ end
11
+ end
12
+
13
+ describe "::setup" do
14
+ it "yields to the provided block with config" do
15
+ config = WCC::Data.config
16
+ called = false
17
+ WCC::Data.setup do |passed_config|
18
+ called = true
19
+ expect(passed_config).to eq(config)
20
+ end
21
+ expect(called).to be_truthy
22
+ end
23
+ end
24
+
25
+ end
data/wcc-data.gemspec CHANGED
@@ -13,13 +13,15 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
15
 
16
- spec.files = Dir['lib/**/*'] + %w[LICENSE.txt README.md wcc-data.gemspec]
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ['lib']
19
+ spec.require_paths = ["lib"]
19
20
 
20
21
  spec.required_ruby_version = '~> 2.2'
21
22
 
22
- spec.add_dependency "faraday", "~> 0.8"
23
+ # Required if you use faraday_client_app_token_auth but must be included separately
24
+ spec.add_development_dependency "faraday", "~> 0.8"
23
25
 
24
26
  spec.add_development_dependency "bundler", "~> 1.3"
25
27
  spec.add_development_dependency "dotenv", "~> 0.10.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wcc-data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.4.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Watermark Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-03 00:00:00.000000000 Z
11
+ date: 2021-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -17,7 +17,7 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0.8'
20
- type: :runtime
20
+ type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
@@ -97,12 +97,20 @@ dependencies:
97
97
  description: Watermark's library for interapp communication via APIs
98
98
  email:
99
99
  - dev@watermark.org
100
- executables: []
100
+ executables:
101
+ - rspec
101
102
  extensions: []
102
103
  extra_rdoc_files: []
103
104
  files:
105
+ - ".env.example"
106
+ - ".gitignore"
107
+ - ".rspec"
108
+ - Gemfile
104
109
  - LICENSE.txt
105
110
  - README.md
111
+ - Rakefile
112
+ - bin/rspec
113
+ - circle.yml
106
114
  - lib/wcc/data.rb
107
115
  - lib/wcc/data/config.rb
108
116
  - lib/wcc/data/enumerated_type.rb
@@ -128,6 +136,22 @@ files:
128
136
  - lib/wcc/data/rest_endpoint.rb
129
137
  - lib/wcc/data/service.rb
130
138
  - lib/wcc/data/version.rb
139
+ - spec/spec_helper.rb
140
+ - spec/support/inheritable_class_attribute_examples.rb
141
+ - spec/wcc/data/config_spec.rb
142
+ - spec/wcc/data/enumerated_type_spec.rb
143
+ - spec/wcc/data/faraday_client_app_token_auth_spec.rb
144
+ - spec/wcc/data/mapper/attributes_spec.rb
145
+ - spec/wcc/data/mapper/json_response_spec.rb
146
+ - spec/wcc/data/mapper/rest_configuration_spec.rb
147
+ - spec/wcc/data/mapper/rest_query_spec.rb
148
+ - spec/wcc/data/model_spec.rb
149
+ - spec/wcc/data/nucleus/campus_spec.rb
150
+ - spec/wcc/data/rack_client_app_token_auth_spec.rb
151
+ - spec/wcc/data/response_spec.rb
152
+ - spec/wcc/data/rest_endpoint_spec.rb
153
+ - spec/wcc/data/service_spec.rb
154
+ - spec/wcc/data_spec.rb
131
155
  - wcc-data.gemspec
132
156
  homepage: ''
133
157
  licenses:
@@ -144,13 +168,29 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
168
  version: '2.2'
145
169
  required_rubygems_version: !ruby/object:Gem::Requirement
146
170
  requirements:
147
- - - ">="
171
+ - - ">"
148
172
  - !ruby/object:Gem::Version
149
- version: '0'
173
+ version: 1.3.1
150
174
  requirements: []
151
175
  rubyforge_project:
152
176
  rubygems_version: 2.5.2.3
153
177
  signing_key:
154
178
  specification_version: 4
155
179
  summary: Watermark's library for interapp communication via APIs
156
- test_files: []
180
+ test_files:
181
+ - spec/spec_helper.rb
182
+ - spec/support/inheritable_class_attribute_examples.rb
183
+ - spec/wcc/data/config_spec.rb
184
+ - spec/wcc/data/enumerated_type_spec.rb
185
+ - spec/wcc/data/faraday_client_app_token_auth_spec.rb
186
+ - spec/wcc/data/mapper/attributes_spec.rb
187
+ - spec/wcc/data/mapper/json_response_spec.rb
188
+ - spec/wcc/data/mapper/rest_configuration_spec.rb
189
+ - spec/wcc/data/mapper/rest_query_spec.rb
190
+ - spec/wcc/data/model_spec.rb
191
+ - spec/wcc/data/nucleus/campus_spec.rb
192
+ - spec/wcc/data/rack_client_app_token_auth_spec.rb
193
+ - spec/wcc/data/response_spec.rb
194
+ - spec/wcc/data/rest_endpoint_spec.rb
195
+ - spec/wcc/data/service_spec.rb
196
+ - spec/wcc/data_spec.rb