syncano 3.1.4 → 4.0.0.alpha
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 +7 -0
- data/.gitignore +4 -1
- data/.rspec +2 -0
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +25 -1
- data/Guardfile +22 -4
- data/README.md +68 -447
- data/Rakefile +48 -5
- data/circle.yml +10 -0
- data/lib/active_attr/dirty.rb +3 -17
- data/lib/active_attr/typecasting/hash_typecaster.rb +34 -0
- data/lib/active_attr/typecasting_override.rb +29 -0
- data/lib/syncano.rb +53 -92
- data/lib/syncano/api.rb +13 -0
- data/lib/syncano/connection.rb +97 -0
- data/lib/syncano/model/associations.rb +121 -0
- data/lib/syncano/{active_record/association → model/associations}/base.rb +5 -5
- data/lib/syncano/{active_record/association → model/associations}/belongs_to.rb +6 -6
- data/lib/syncano/{active_record/association → model/associations}/has_many.rb +15 -9
- data/lib/syncano/{active_record/association → model/associations}/has_one.rb +4 -4
- data/lib/syncano/model/base.rb +257 -0
- data/lib/syncano/{active_record → model}/callbacks.rb +16 -13
- data/lib/syncano/{active_record → model}/scope_builder.rb +53 -69
- data/lib/syncano/query_builder.rb +19 -129
- data/lib/syncano/resources.rb +126 -0
- data/lib/syncano/resources/base.rb +304 -300
- data/lib/syncano/resources/collection.rb +19 -223
- data/lib/syncano/resources/space.rb +29 -0
- data/lib/syncano/schema.rb +86 -0
- data/lib/syncano/schema/attribute_definition.rb +83 -0
- data/lib/syncano/schema/resource_definition.rb +36 -0
- data/lib/syncano/scope.rb +10 -0
- data/lib/syncano/version.rb +3 -4
- data/spec/integration/syncano_spec.rb +228 -0
- data/spec/spec_helper.rb +15 -9
- data/spec/unit/api_spec.rb +5 -0
- data/spec/unit/connection_spec.rb +137 -0
- data/spec/unit/query_builder_spec.rb +75 -0
- data/spec/unit/resources/collection_spec.rb +36 -0
- data/spec/unit/resources/space_spec.rb +28 -0
- data/spec/unit/resources_base_spec.rb +185 -0
- data/spec/unit/schema/attribute_definition_spec.rb +18 -0
- data/spec/unit/schema/resource_definition_spec.rb +25 -0
- data/spec/unit/schema_spec.rb +3532 -0
- data/spec/unit/syncano_spec.rb +63 -0
- data/syncano.gemspec +8 -14
- metadata +85 -210
- data/lib/generators/syncano/install_generator.rb +0 -17
- data/lib/generators/syncano/templates/initializers/syncano.rb +0 -7
- data/lib/syncano/active_record/associations.rb +0 -112
- data/lib/syncano/active_record/base.rb +0 -318
- data/lib/syncano/batch_queue.rb +0 -58
- data/lib/syncano/batch_queue_element.rb +0 -33
- data/lib/syncano/clients/base.rb +0 -123
- data/lib/syncano/clients/rest.rb +0 -79
- data/lib/syncano/clients/sync.rb +0 -164
- data/lib/syncano/errors.rb +0 -17
- data/lib/syncano/jimson_client.rb +0 -66
- data/lib/syncano/packets/auth.rb +0 -27
- data/lib/syncano/packets/base.rb +0 -70
- data/lib/syncano/packets/call.rb +0 -34
- data/lib/syncano/packets/call_response.rb +0 -33
- data/lib/syncano/packets/error.rb +0 -19
- data/lib/syncano/packets/message.rb +0 -30
- data/lib/syncano/packets/notification.rb +0 -39
- data/lib/syncano/packets/ping.rb +0 -12
- data/lib/syncano/resources/admin.rb +0 -26
- data/lib/syncano/resources/api_key.rb +0 -108
- data/lib/syncano/resources/data_object.rb +0 -316
- data/lib/syncano/resources/folder.rb +0 -88
- data/lib/syncano/resources/notifications/base.rb +0 -103
- data/lib/syncano/resources/notifications/create.rb +0 -20
- data/lib/syncano/resources/notifications/destroy.rb +0 -20
- data/lib/syncano/resources/notifications/message.rb +0 -9
- data/lib/syncano/resources/notifications/update.rb +0 -24
- data/lib/syncano/resources/project.rb +0 -96
- data/lib/syncano/resources/role.rb +0 -11
- data/lib/syncano/resources/subscription.rb +0 -12
- data/lib/syncano/resources/user.rb +0 -65
- data/lib/syncano/response.rb +0 -22
- data/lib/syncano/sync_connection.rb +0 -133
- data/spec/admins_spec.rb +0 -16
- data/spec/api_keys_spec.rb +0 -34
- data/spec/collections_spec.rb +0 -67
- data/spec/data_objects_spec.rb +0 -113
- data/spec/folders_spec.rb +0 -39
- data/spec/notifications_spec.rb +0 -43
- data/spec/projects_spec.rb +0 -35
- data/spec/roles_spec.rb +0 -13
- data/spec/sync_resources_spec.rb +0 -35
- data/spec/syncano_spec.rb +0 -9
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Syncano
|
|
2
|
+
class Schema
|
|
3
|
+
class ResourceDefinition
|
|
4
|
+
attr_accessor :attributes
|
|
5
|
+
attr_accessor :name
|
|
6
|
+
|
|
7
|
+
def initialize(name, raw_defitnition)
|
|
8
|
+
@raw_definition = raw_defitnition
|
|
9
|
+
|
|
10
|
+
delete_colliding_links
|
|
11
|
+
|
|
12
|
+
self.name = name
|
|
13
|
+
|
|
14
|
+
self.attributes = raw_defitnition[:attributes].map do |name, raw_attribute_definition|
|
|
15
|
+
Syncano::Schema::AttributeDefinition.new name, raw_attribute_definition
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def [](key)
|
|
20
|
+
@raw_definition[key]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def delete_colliding_links
|
|
26
|
+
@raw_definition[:attributes].each do |k, v|
|
|
27
|
+
if @raw_definition[:associations]['links']
|
|
28
|
+
@raw_definition[:associations]['links'].delete_if do |link|
|
|
29
|
+
link['name'] == k
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/syncano/version.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
end
|
|
1
|
+
module Syncano
|
|
2
|
+
VERSION = '4.0.0.alpha'
|
|
3
|
+
end
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
|
|
3
|
+
WebMock.allow_net_connect!
|
|
4
|
+
|
|
5
|
+
describe Syncano do
|
|
6
|
+
before(:all) do
|
|
7
|
+
@api_key = ENV['INTEGRATION_TEST_API_KEY']
|
|
8
|
+
@api = Syncano.connect(api_key: @api_key)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
before(:each) do
|
|
12
|
+
@api.instances.all.each &:destroy
|
|
13
|
+
@instance = @api.instances.create(name: "a#{SecureRandom.hex(24)}")
|
|
14
|
+
@instance.classes.all.select { |c| c.name != 'user_profile'}.each &:destroy
|
|
15
|
+
@instance.groups.all.each &:destroy
|
|
16
|
+
@instance.users.all.each &:delete
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe 'working with instances' do
|
|
20
|
+
subject { @api.instances }
|
|
21
|
+
|
|
22
|
+
it 'should raise an error on not found instance' do
|
|
23
|
+
expect { subject.find('kaszanka') }.to raise_error(Syncano::ClientError)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
specify do
|
|
27
|
+
subject.create name: 'fafarafaa'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe 'working with classes' do
|
|
32
|
+
subject { @instance.classes }
|
|
33
|
+
|
|
34
|
+
specify do
|
|
35
|
+
expect { subject.create name: 'sausage', schema: [{name: 'name', type: 'string' }] }.to create_resource
|
|
36
|
+
|
|
37
|
+
new_klass = subject.last
|
|
38
|
+
|
|
39
|
+
expect(new_klass.name).to eq('sausage')
|
|
40
|
+
expect(new_klass.schema).to eq([{'name' => 'name', 'type' => 'string'}])
|
|
41
|
+
|
|
42
|
+
new_klass.description = 'salchichón'
|
|
43
|
+
new_klass.schema = [{name: 'nombre', type: 'string'}]
|
|
44
|
+
|
|
45
|
+
saved_class = new_klass.save
|
|
46
|
+
expect(resources_count).to eq(2)
|
|
47
|
+
expect(saved_class.schema).to eq([{'name' => 'nombre', 'type' => 'string'}])
|
|
48
|
+
expect(saved_class.description).to eq('salchichón')
|
|
49
|
+
|
|
50
|
+
from_database = subject.last
|
|
51
|
+
expect(from_database.schema).to eq([{'name' => 'nombre', 'type' => 'string'}])
|
|
52
|
+
expect(from_database.description).to eq('salchichón')
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe 'working with objects' do
|
|
57
|
+
before do
|
|
58
|
+
@class = @instance.classes.create name: 'account',
|
|
59
|
+
schema: [{name: 'currency', type: 'string', filter_index: true},
|
|
60
|
+
{name: 'ballance', type: 'integer', filter_index: true, order_index: true}]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
subject { @class.objects }
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
specify 'basic operations' do
|
|
67
|
+
expect { subject.create currency: 'USD', ballance: 1337 }.to create_resource
|
|
68
|
+
|
|
69
|
+
object = subject.first
|
|
70
|
+
|
|
71
|
+
expect(object.ballance).to eq(1337)
|
|
72
|
+
expect(object.currency).to eq('USD')
|
|
73
|
+
|
|
74
|
+
object.currency = 'GBP'
|
|
75
|
+
object.ballance = 54
|
|
76
|
+
object.save
|
|
77
|
+
|
|
78
|
+
expect(object.ballance).to eq(54)
|
|
79
|
+
expect(object.currency).to eq('GBP')
|
|
80
|
+
|
|
81
|
+
expect { object.destroy }.to destroy_resource
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
specify 'PATH and POST' do
|
|
86
|
+
initial_yuan = subject.create currency: 'CNY', ballance: 98123
|
|
87
|
+
|
|
88
|
+
yuan = subject.first
|
|
89
|
+
new_yuan = subject.first
|
|
90
|
+
|
|
91
|
+
yuan.ballance = 100000
|
|
92
|
+
yuan.save
|
|
93
|
+
|
|
94
|
+
new_yuan.currency = 'RMB'
|
|
95
|
+
new_yuan.save
|
|
96
|
+
|
|
97
|
+
yuan = subject.first
|
|
98
|
+
|
|
99
|
+
expect(yuan.currency).to eq('RMB')
|
|
100
|
+
expect(yuan.ballance).to eq(100000)
|
|
101
|
+
|
|
102
|
+
initial_yuan.save(overwrite: true)
|
|
103
|
+
yuan.reload!
|
|
104
|
+
|
|
105
|
+
expect(yuan.currency).to eq('CNY')
|
|
106
|
+
expect(yuan.ballance).to eq(98123)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
specify 'filtering and ordering' do
|
|
110
|
+
usd = subject.create(currency: 'USD', ballance: 400)
|
|
111
|
+
pln = subject.create(currency: 'PLN', ballance: 1600)
|
|
112
|
+
eur = subject.create(currency: 'EUR', ballance: 400)
|
|
113
|
+
gbp = subject.create(currency: 'GPB', ballance: 270)
|
|
114
|
+
chf = subject.create(currency: 'CHF', ballance: 390)
|
|
115
|
+
uah = subject.create(currency: 'UAH', ballance: 9100)
|
|
116
|
+
rub = subject.create(currency: 'RUB')
|
|
117
|
+
|
|
118
|
+
expect(subject.all(query: { ballance: { _exists: true }}).to_a).to_not include(rub)
|
|
119
|
+
expect(subject.all(query: { currency: { _in: %w[UAH USD PLN] } }).to_a).to match_array([pln, usd, uah])
|
|
120
|
+
expect(subject.all(query: { ballance: { _lt: 400, _gte: 270 }}, order_by: '-ballance').to_a).to eq([chf, gbp])
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
specify 'fetching only specific fields' do
|
|
124
|
+
subject.create(currency: 'USD', ballance: 400)
|
|
125
|
+
|
|
126
|
+
account = subject.all(fields: 'currency').first
|
|
127
|
+
expect { account.currency }.to_not raise_error
|
|
128
|
+
expect { account.ballance }.to raise_error(NoMethodError)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
account = subject.first(excluded_fields: 'currency')
|
|
132
|
+
expect { account.currency }.to raise_error(NoMethodError)
|
|
133
|
+
expect { account.ballance }.to_not raise_error
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
specify 'paging', slow: true do
|
|
137
|
+
104.times { subject.create }
|
|
138
|
+
|
|
139
|
+
total = 0
|
|
140
|
+
all = subject.all
|
|
141
|
+
|
|
142
|
+
loop do
|
|
143
|
+
total += all.count
|
|
144
|
+
|
|
145
|
+
if all.next?
|
|
146
|
+
all = subject.space(all.last).all
|
|
147
|
+
else
|
|
148
|
+
break
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
expect(total).to eq(104)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
describe 'working with codeboxes traces' do
|
|
157
|
+
subject { @instance.codeboxes }
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
specify 'basic operations' do
|
|
161
|
+
expect { subject.create name: 'df', source: 'puts 1337', runtime_name: 'ruby' }.to create_resource
|
|
162
|
+
|
|
163
|
+
codebox = subject.first
|
|
164
|
+
codebox.run
|
|
165
|
+
codebox.source = 'puts 123'
|
|
166
|
+
codebox.save
|
|
167
|
+
codebox.run
|
|
168
|
+
|
|
169
|
+
without_profiling { sleep 5 }
|
|
170
|
+
traces = codebox.traces.all
|
|
171
|
+
|
|
172
|
+
expect(traces.count).to eq(2)
|
|
173
|
+
|
|
174
|
+
first = traces[1]
|
|
175
|
+
|
|
176
|
+
expect(first.status).to eq('success')
|
|
177
|
+
expect(first.result).to eq('1337')
|
|
178
|
+
|
|
179
|
+
second = traces[0]
|
|
180
|
+
expect(second.status).to eq('success')
|
|
181
|
+
expect(second.result).to eq('123')
|
|
182
|
+
|
|
183
|
+
expect { @instance.schedules.create name: 'test', interval_sec: 30, codebox: codebox.primary_key }.
|
|
184
|
+
to change { @instance.schedules.all.count }.by(1)
|
|
185
|
+
|
|
186
|
+
expect { codebox.destroy }.to destroy_resource
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
describe 'working with webhooks' do
|
|
191
|
+
subject { @instance.webhooks }
|
|
192
|
+
|
|
193
|
+
let!(:codebox) { @instance.codeboxes.create name: 'wurst', source: 'puts "currywurst"', runtime_name: 'ruby' }
|
|
194
|
+
|
|
195
|
+
specify do
|
|
196
|
+
expect { subject.create slug: 'web-wurst', codebox: codebox.primary_key }.to create_resource
|
|
197
|
+
|
|
198
|
+
expect(subject.first.run['result']).to eq('currywurst')
|
|
199
|
+
|
|
200
|
+
expect { subject.first.destroy }.to destroy_resource
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def resources_count
|
|
205
|
+
subject.all.count
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def create_resource
|
|
209
|
+
change { resources_count }.by(1)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def destroy_resource
|
|
213
|
+
change { resources_count }.to(0)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def without_profiling
|
|
217
|
+
if defined? RubyProf
|
|
218
|
+
begin
|
|
219
|
+
RubyProf.pause if RubyProf.running?
|
|
220
|
+
yield
|
|
221
|
+
ensure
|
|
222
|
+
RubyProf.resume if RubyProf.running?
|
|
223
|
+
end
|
|
224
|
+
else
|
|
225
|
+
yield
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
require 'bundler'
|
|
2
|
+
Bundler.setup
|
|
3
|
+
|
|
4
|
+
require 'dotenv'
|
|
5
|
+
Dotenv.load
|
|
6
|
+
|
|
7
|
+
require 'rspec-prof' if ENV['SPEC_PROFILE']
|
|
1
8
|
require 'syncano'
|
|
2
|
-
require '
|
|
9
|
+
require 'webmock/rspec'
|
|
10
|
+
|
|
11
|
+
WebMock.disable_net_connect!
|
|
3
12
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@syncano_api_key = ENV['SYNCANO_API_KEY'] || raise('Set SYNCANO_API_KEY environment variable!')
|
|
8
|
-
@syncano_instance_name = ENV['SYNCANO_INSTANCE_NAME'] || raise('Set SYNCANO_INSTANCE_NAME environment variable!')
|
|
13
|
+
def generate_body(params)
|
|
14
|
+
JSON.generate(params)
|
|
15
|
+
end
|
|
9
16
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
end
|
|
17
|
+
def endpoint_uri(path)
|
|
18
|
+
[Syncano::Connection.api_root,"v1", path].join("/")
|
|
13
19
|
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
describe Syncano::Connection do
|
|
5
|
+
context 'api_key' do
|
|
6
|
+
specify { expect(described_class.new(api_key: 'fafarafa')).to be_authenticated }
|
|
7
|
+
specify { expect(described_class.new).to_not be_authenticated }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe '#request' do
|
|
11
|
+
let(:headers) { { 'X-Api-Key'=>'87a7da987da98sd7a98', 'User-Agent' => "Syncano Ruby Gem #{Syncano::VERSION}" } }
|
|
12
|
+
let(:api_key) { '87a7da987da98sd7a98' }
|
|
13
|
+
|
|
14
|
+
subject { described_class.new(api_key: api_key) }
|
|
15
|
+
|
|
16
|
+
context 'called with unsupported method' do
|
|
17
|
+
specify do
|
|
18
|
+
expect { subject.request :koza, 'fafarafa' }.
|
|
19
|
+
to raise_error(RuntimeError, 'Unsupported method "koza"')
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context 'called with supported method' do
|
|
24
|
+
before do
|
|
25
|
+
stub_request(:get, endpoint_uri('somepath/')).
|
|
26
|
+
with(headers: headers).
|
|
27
|
+
to_return(body: generate_body(some: 'response'))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
specify do
|
|
31
|
+
expect(subject.request(:get, 'somepath/')).to eq('some' => 'response')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'called with supported method returning a a client error' do
|
|
36
|
+
before do
|
|
37
|
+
stub_request(:post, endpoint_uri('instances/')).
|
|
38
|
+
with(body: { 'name' => 'koza' },
|
|
39
|
+
headers: headers).
|
|
40
|
+
to_return(body: generate_body({name: ['This field can not be "koza"']}),
|
|
41
|
+
status: 400)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
specify do
|
|
45
|
+
expect { subject.request(:post, '/v1/instances/', { name: "koza" }) }.
|
|
46
|
+
to raise_error(Syncano::ClientError)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context 'returning a server error' do
|
|
51
|
+
before do
|
|
52
|
+
stub_request(:get, endpoint_uri('error_prone/')).
|
|
53
|
+
to_return(body: 'An error occured', status: 500)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
specify do
|
|
57
|
+
expect { subject.request(:get, endpoint_uri('error_prone/'), nil) }.
|
|
58
|
+
to raise_error(Syncano::ServerError)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'returning unsupported status code' do
|
|
63
|
+
before do
|
|
64
|
+
stub_request(:get, endpoint_uri('weird/')).to_return(body: 'O HAI!', status: 101)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
specify do
|
|
68
|
+
expect { subject.request(:get, endpoint_uri('weird/')) }.to raise_error(Syncano::UnsupportedStatusError)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context 'successful returning empty body' do
|
|
73
|
+
before do
|
|
74
|
+
stub_request(:delete, endpoint_uri('instances/kiszonka/')).
|
|
75
|
+
with(headers: headers).
|
|
76
|
+
to_return(body: nil, status: 204)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
specify do
|
|
80
|
+
expect { subject.request(:delete, '/v1/instances/kiszonka/', {}) }.
|
|
81
|
+
to_not raise_error
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe '#authenticate' do
|
|
88
|
+
subject { described_class.new }
|
|
89
|
+
|
|
90
|
+
let(:authenticate_uri) { endpoint_uri('account/auth/') }
|
|
91
|
+
let(:email) { 'kiszka@koza.com' }
|
|
92
|
+
let(:password) { 'kiszonka' }
|
|
93
|
+
let(:success_status) { 200 }
|
|
94
|
+
let(:unauthorized_status) { 401 }
|
|
95
|
+
|
|
96
|
+
context 'successful' do
|
|
97
|
+
before do
|
|
98
|
+
stub_request(:post, authenticate_uri).
|
|
99
|
+
with(body: { 'email' => email, 'password' => password } ).
|
|
100
|
+
to_return(body: successful_body, status: success_status)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'should get an API key' do
|
|
104
|
+
expect { subject.authenticate(email, password) }.to change { subject.authenticated? }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def successful_body
|
|
108
|
+
generate_body id: 15,
|
|
109
|
+
email: email,
|
|
110
|
+
first_name: '',
|
|
111
|
+
last_name: '',
|
|
112
|
+
account_key: 'kozakoza123'
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
context 'failed' do
|
|
117
|
+
before do
|
|
118
|
+
stub_request(:post, authenticate_uri).
|
|
119
|
+
with(body: { 'email' => email, 'password' => password }).
|
|
120
|
+
to_return(body: failed_body, status: unauthorized_status)
|
|
121
|
+
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'should raise an exception' do
|
|
125
|
+
expect { subject.authenticate(email, password) }.to raise_error(Syncano::ClientError)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def failed_body
|
|
129
|
+
generate_body detail: 'Invalid email or password.'
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def generate_body(params)
|
|
135
|
+
JSON.generate params
|
|
136
|
+
end
|
|
137
|
+
end
|