···114114 did.to_s.should == plc_did
115115 end
116116 end
117117+118118+ describe 'account status' do
119119+ let(:document) { stub(:pds_endpoint => 'https://pds.ruby.space') }
120120+ let(:did) { subject.new(plc_did) }
121121+122122+ before do
123123+ did.stubs(:document).returns(document)
124124+125125+ stub_request(:get, 'https://pds.ruby.space/xrpc/com.atproto.sync.getRepoStatus')
126126+ .with(query: { did: plc_did })
127127+ .to_return(http_response) if defined?(http_response)
128128+ end
129129+130130+ context 'when repo is active' do
131131+ let(:http_response) {
132132+ { body: { active: true }.to_json, headers: { 'Content-Type' => 'application/json' }}
133133+ }
134134+135135+ it 'should report active account state' do
136136+ did.account_status.should == :active
137137+ did.account_active?.should == true
138138+ did.account_exists?.should == true
139139+ end
140140+ end
141141+142142+ context 'when repo is inactive' do
143143+ let(:http_response) {
144144+ { body: { active: false, status: 'takendown' }.to_json, headers: { 'Content-Type' => 'application/json' }}
145145+ }
146146+147147+ it 'should report an inactive existing account' do
148148+ did.account_status.should == :takendown
149149+ did.account_active?.should == false
150150+ did.account_exists?.should == true
151151+ end
152152+ end
153153+154154+ context 'when repo is not found' do
155155+ let(:http_response) {
156156+ { status: 400, body: { error: 'RepoNotFound' }.to_json, headers: { 'Content-Type' => 'application/json' }}
157157+ }
158158+159159+ it 'should return nil status and report the account as missing' do
160160+ did.account_status.should be_nil
161161+ did.account_active?.should == false
162162+ did.account_exists?.should == false
163163+ end
164164+ end
165165+166166+ context 'when the document has no pds endpoint' do
167167+ before do
168168+ did.stubs(:document).returns(stub(:pds_endpoint => nil))
169169+ end
170170+171171+ it 'should return nil status and report the account as missing' do
172172+ did.account_status.should be_nil
173173+ did.account_active?.should == false
174174+ did.account_exists?.should == false
175175+ end
176176+ end
177177+178178+ context 'when active field is not set' do
179179+ let(:http_response) {
180180+ { body: { active: nil, status: 'unknown' }.to_json, headers: { 'Content-Type' => 'application/json' }}
181181+ }
182182+183183+ it 'should raise APIError' do
184184+ expect { did.account_status }.to raise_error(DIDKit::APIError)
185185+ expect { did.account_active? }.to raise_error(DIDKit::APIError)
186186+ expect { did.account_exists? }.to raise_error(DIDKit::APIError)
187187+ end
188188+ end
189189+190190+ context 'when active is false but status is not set' do
191191+ let(:http_response) {
192192+ { body: { active: false, status: nil }.to_json, headers: { 'Content-Type' => 'application/json' }}
193193+ }
194194+195195+ it 'should raise APIError' do
196196+ expect { did.account_status }.to raise_error(DIDKit::APIError)
197197+ expect { did.account_active? }.to raise_error(DIDKit::APIError)
198198+ expect { did.account_exists? }.to raise_error(DIDKit::APIError)
199199+ end
200200+ end
201201+202202+ context 'when an error different than RepoNotFound is returned' do
203203+ let(:http_response) {
204204+ { status: 400, body: { error: 'UserIsJerry' }.to_json, headers: { 'Content-Type' => 'application/json' }}
205205+ }
206206+207207+ it 'should raise APIError' do
208208+ expect { did.account_status }.to raise_error(DIDKit::APIError)
209209+ expect { did.account_active? }.to raise_error(DIDKit::APIError)
210210+ expect { did.account_exists? }.to raise_error(DIDKit::APIError)
211211+ end
212212+ end
213213+214214+ context 'when the response is not application/json' do
215215+ let(:http_response) {
216216+ { status: 400, body: 'error', headers: { 'Content-Type' => 'text/html' }}
217217+ }
218218+219219+ it 'should raise APIError' do
220220+ expect { did.account_status }.to raise_error(DIDKit::APIError)
221221+ expect { did.account_active? }.to raise_error(DIDKit::APIError)
222222+ expect { did.account_exists? }.to raise_error(DIDKit::APIError)
223223+ end
224224+ end
225225+226226+ context 'when the response is not 200 or 400' do
227227+ let(:http_response) {
228228+ { status: 500, body: { error: 'RepoNotFound' }.to_json, headers: { 'Content-Type' => 'application/json' }}
229229+ }
230230+231231+ it 'should raise APIError' do
232232+ expect { did.account_status }.to raise_error(DIDKit::APIError)
233233+ expect { did.account_active? }.to raise_error(DIDKit::APIError)
234234+ expect { did.account_exists? }.to raise_error(DIDKit::APIError)
235235+ end
236236+ end
237237+ end
117238end
+1-1
spec/document_spec.rb
···174174 end
175175 end
176176177177- describe '#pds_host' do
177177+ describe '#labeler_host' do
178178 it 'should return the host part of #atproto_labeler endpoint' do
179179 doc = subject.new(did, service_json)
180180 doc.labeler_host.should == 'labels.dholms.xyz'
+146
spec/plc_operation_spec.rb
···208208 expect { subject.new(json) }.to raise_error(DIDKit::PLCOperation::FormatError)
209209 end
210210 end
211211+212212+ context 'when a service entry is missing fields' do
213213+ let(:json) {
214214+ base_json.tap { |h|
215215+ h['operation']['services'] = {
216216+ "atproto_pds" => {
217217+ "endpoint" => "https://pds.dholms.xyz"
218218+ },
219219+ "atproto_labeler" => {
220220+ "type" => "AtprotoLabeler",
221221+ "endpoint" => "https://labeler.example.com"
222222+ }
223223+ }
224224+ }
225225+ }
226226+227227+ it 'should raise a format error' do
228228+ expect { subject.new(json) }.to raise_error(DIDKit::PLCOperation::FormatError)
229229+ end
230230+ end
231231+232232+ context 'when services are valid' do
233233+ let(:json) {
234234+ base_json.tap { |h|
235235+ h['operation']['services'] = {
236236+ "atproto_pds" => {
237237+ "type" => "AtprotoPersonalDataServer",
238238+ "endpoint" => "https://pds.dholms.xyz"
239239+ },
240240+ "atproto_labeler" => {
241241+ "type" => "AtprotoLabeler",
242242+ "endpoint" => "https://labeler.example.com"
243243+ },
244244+ "custom_service" => {
245245+ "type" => "OtherService",
246246+ "endpoint" => "https://custom.example.com"
247247+ }
248248+ }
249249+ }
250250+ }
251251+252252+ it 'should parse services into ServiceRecords' do
253253+ op = subject.new(json)
254254+255255+ op.services.length.should == 3
256256+ op.services.each { |s| s.should be_a(DIDKit::ServiceRecord) }
257257+258258+ pds, labeller, custom = op.services
259259+260260+ pds.type.should == 'AtprotoPersonalDataServer'
261261+ pds.endpoint.should == 'https://pds.dholms.xyz'
262262+263263+ labeller.type.should == 'AtprotoLabeler'
264264+ labeller.endpoint.should == 'https://labeler.example.com'
265265+266266+ custom.type.should == 'OtherService'
267267+ custom.endpoint.should == 'https://custom.example.com'
268268+ end
269269+270270+ it 'should allow fetching services by key + type' do
271271+ op = subject.new(json)
272272+273273+ custom = op.get_service('custom_service', 'OtherService')
274274+ custom.should be_a(DIDKit::ServiceRecord)
275275+ custom.endpoint.should == 'https://custom.example.com'
276276+ end
277277+278278+ describe '#pds_endpoint' do
279279+ it 'should return the endpoint of #atproto_pds' do
280280+ op = subject.new(json)
281281+ op.pds_endpoint.should == 'https://pds.dholms.xyz'
282282+ end
283283+ end
284284+285285+ describe '#pds_host' do
286286+ it 'should return the host part of #atproto_pds endpoint' do
287287+ op = subject.new(json)
288288+ op.pds_host.should == 'pds.dholms.xyz'
289289+ end
290290+ end
291291+292292+ describe '#labeler_endpoint' do
293293+ it 'should return the endpoint of #atproto_labeler' do
294294+ op = subject.new(json)
295295+ op.labeler_endpoint.should == 'https://labeler.example.com'
296296+ end
297297+ end
298298+299299+ describe '#labeler_host' do
300300+ it 'should return the host part of #atproto_labeler endpoint' do
301301+ op = subject.new(json)
302302+ op.labeler_host.should == 'labeler.example.com'
303303+ end
304304+ end
305305+306306+ it 'should expose the "labeller" aliases for endpoint and host' do
307307+ op = subject.new(json)
308308+309309+ op.labeller_endpoint.should == 'https://labeler.example.com'
310310+ op.labeller_host.should == 'labeler.example.com'
311311+ end
312312+ end
313313+314314+ context 'when services are valid but the specific ones are missing' do
315315+ let(:json) {
316316+ base_json.tap { |h|
317317+ h['operation']['services'] = {
318318+ "custom_service" => {
319319+ "type" => "CustomService",
320320+ "endpoint" => "https://custom.example.com"
321321+ }
322322+ }
323323+ }
324324+ }
325325+326326+ it 'should parse service records' do
327327+ op = subject.new(json)
328328+ op.services.length.should == 1
329329+ end
330330+331331+ describe '#get_service' do
332332+ it 'should return nil' do
333333+ op = subject.new(json)
334334+ other = op.get_service('other_service', 'OtherService')
335335+ other.should be_nil
336336+ end
337337+ end
338338+339339+ describe '#pds_endpoint' do
340340+ it 'should return nil' do
341341+ op = subject.new(json)
342342+ op.pds_endpoint.should be_nil
343343+ op.pds_host.should be_nil
344344+ end
345345+ end
346346+347347+ describe '#labeler_endpoint' do
348348+ it 'should return nil' do
349349+ op = subject.new(json)
350350+ op.labeler_endpoint.should be_nil
351351+ op.labeller_endpoint.should be_nil
352352+ op.labeler_host.should be_nil
353353+ op.labeller_host.should be_nil
354354+ end
355355+ end
356356+ end
211357 end
212358end