tangled
alpha
login
or
join now
mackuba.eu
/
didkit
1
fork
atom
A library for handling DID identifiers used in Bluesky AT Protocol
1
fork
atom
overview
issues
pulls
pipelines
added tests for Document
mackuba.eu
2 months ago
1bde673d
1c13adfc
+247
-4
3 changed files
expand all
collapse all
unified
split
lib
didkit
document.rb
spec
document_spec.rb
spec_helper.rb
+6
-4
lib/didkit/document.rb
···
25
25
@handles = parse_also_known_as(json['alsoKnownAs'] || [])
26
26
end
27
27
28
28
+
def get_verified_handle
29
29
+
Resolver.new.get_verified_handle(self)
30
30
+
end
31
31
+
32
32
+
private
33
33
+
28
34
def parse_services(service_data)
29
35
raise FormatError, "Invalid service data" unless service_data.is_a?(Array) && service_data.all? { |x| x.is_a?(Hash) }
30
36
···
39
45
end
40
46
41
47
services
42
42
-
end
43
43
-
44
44
-
def get_verified_handle
45
45
-
Resolver.new.get_verified_handle(self)
46
48
end
47
49
end
48
50
end
+236
spec/document_spec.rb
···
1
1
+
describe DIDKit::Document do
2
2
+
subject { described_class }
3
3
+
4
4
+
let(:did_string) { 'did:plc:yk4dd2qkboz2yv6tpubpc6co' }
5
5
+
let(:did) { DID.new(did_string) }
6
6
+
let(:json_data) { load_did_json('dholms.json') }
7
7
+
8
8
+
describe '#initialize' do
9
9
+
let(:base_json) { json_data }
10
10
+
11
11
+
context 'with valid input' do
12
12
+
let(:json) { base_json }
13
13
+
14
14
+
it 'should return a Document object' do
15
15
+
doc = subject.new(did, json)
16
16
+
17
17
+
doc.should be_a(DIDKit::Document)
18
18
+
doc.did.should == did
19
19
+
doc.json.should == json
20
20
+
end
21
21
+
22
22
+
it 'should parse services from the JSON' do
23
23
+
doc = subject.new(did, json)
24
24
+
25
25
+
doc.services.should be_an(Array)
26
26
+
doc.services.length.should == 1
27
27
+
28
28
+
doc.services[0].should be_a(DIDKit::ServiceRecord)
29
29
+
doc.services[0].key.should == 'atproto_pds'
30
30
+
doc.services[0].type.should == 'AtprotoPersonalDataServer'
31
31
+
doc.services[0].endpoint.should == 'https://pds.dholms.xyz'
32
32
+
end
33
33
+
34
34
+
it 'should parse handles from the JSON' do
35
35
+
doc = subject.new(did, json)
36
36
+
37
37
+
doc.handles.should == ['dholms.xyz']
38
38
+
end
39
39
+
end
40
40
+
41
41
+
context 'when id is missing' do
42
42
+
let(:json) { base_json.dup.tap { |h| h.delete('id') } }
43
43
+
44
44
+
it 'should raise a format error' do
45
45
+
expect {
46
46
+
subject.new(did, json)
47
47
+
}.to raise_error(DIDKit::Document::FormatError)
48
48
+
end
49
49
+
end
50
50
+
51
51
+
context 'when id is not a string' do
52
52
+
let(:json) { base_json.merge('id' => 123) }
53
53
+
54
54
+
it 'should raise a format error' do
55
55
+
expect {
56
56
+
subject.new(did, json)
57
57
+
}.to raise_error(DIDKit::Document::FormatError)
58
58
+
end
59
59
+
end
60
60
+
61
61
+
context 'when id does not match the DID' do
62
62
+
let(:json) { base_json.merge('id' => 'did:plc:notmatching') }
63
63
+
64
64
+
it 'should raise a format error' do
65
65
+
expect {
66
66
+
subject.new(did, json)
67
67
+
}.to raise_error(DIDKit::Document::FormatError)
68
68
+
end
69
69
+
end
70
70
+
71
71
+
context 'when alsoKnownAs is not an array' do
72
72
+
let(:json) { base_json.merge('alsoKnownAs' => 'at://dholms.xyz') }
73
73
+
74
74
+
it 'should raise an AtHandles format error' do
75
75
+
expect {
76
76
+
subject.new(did, json)
77
77
+
}.to raise_error(DIDKit::AtHandles::FormatError)
78
78
+
end
79
79
+
end
80
80
+
81
81
+
context 'when alsoKnownAs elements are not strings' do
82
82
+
let(:json) { base_json.merge('alsoKnownAs' => [666]) }
83
83
+
84
84
+
it 'should raise an AtHandles format error' do
85
85
+
expect {
86
86
+
subject.new(did, json)
87
87
+
}.to raise_error(DIDKit::AtHandles::FormatError)
88
88
+
end
89
89
+
end
90
90
+
91
91
+
context 'when alsoKnownAs contains multiple handles' do
92
92
+
let(:json) {
93
93
+
base_json.merge('alsoKnownAs' => [
94
94
+
'at://dholms.xyz',
95
95
+
'https://example.com',
96
96
+
'at://other.handle'
97
97
+
])
98
98
+
}
99
99
+
100
100
+
it 'should pick those starting with at:// and remove the prefixes' do
101
101
+
doc = subject.new(did, json)
102
102
+
doc.handles.should == ['dholms.xyz', 'other.handle']
103
103
+
end
104
104
+
end
105
105
+
106
106
+
context 'when service is not an array' do
107
107
+
let(:json) { base_json.merge('service' => 'not-an-array') }
108
108
+
109
109
+
it 'should raise a format error' do
110
110
+
expect {
111
111
+
subject.new(did, json)
112
112
+
}.to raise_error(DIDKit::Document::FormatError)
113
113
+
end
114
114
+
end
115
115
+
116
116
+
context 'when service entries are not hashes' do
117
117
+
let(:json) { base_json.merge('service' => ['invalid']) }
118
118
+
119
119
+
it 'should raise a format error' do
120
120
+
expect {
121
121
+
subject.new(did, json)
122
122
+
}.to raise_error(DIDKit::Document::FormatError)
123
123
+
end
124
124
+
end
125
125
+
126
126
+
context 'when service entries are partially valid' do
127
127
+
let(:services) {
128
128
+
[
129
129
+
{ 'id' => '#atproto_pds', 'type' => 'AtprotoPersonalDataServer', 'serviceEndpoint' => 'https://pds.dholms.xyz' },
130
130
+
{ 'id' => 'not_a_hash', 'type' => 'AtprotoPersonalDataServer', 'serviceEndpoint' => 'https://pds.dholms.xyz' },
131
131
+
{ 'id' => '#wrong_type', 'type' => 123, 'serviceEndpoint' => 'https://pds.dholms.xyz' },
132
132
+
{ 'id' => '#wrong_endpoint', 'type' => 'AtprotoPersonalDataServer', 'serviceEndpoint' => 123 },
133
133
+
{ 'id' => '#lycan', 'type' => 'LycanService', 'serviceEndpoint' => 'https://lycan.feeds.blue' }
134
134
+
]
135
135
+
}
136
136
+
137
137
+
let(:json) { base_json.merge('service' => services) }
138
138
+
139
139
+
it 'should only keep the valid records' do
140
140
+
doc = subject.new(did, json)
141
141
+
142
142
+
doc.services.length.should == 2
143
143
+
doc.services.map(&:key).should == ['atproto_pds', 'lycan']
144
144
+
doc.services.map(&:type).should == ['AtprotoPersonalDataServer', 'LycanService']
145
145
+
doc.services.map(&:endpoint).should == ['https://pds.dholms.xyz', 'https://lycan.feeds.blue']
146
146
+
end
147
147
+
end
148
148
+
end
149
149
+
150
150
+
describe 'service helpers' do
151
151
+
let(:service_json) {
152
152
+
json_data.merge('service' => [
153
153
+
{ 'id' => '#atproto_pds', 'type' => 'AtprotoPersonalDataServer', 'serviceEndpoint' => 'https://pds.dholms.xyz' },
154
154
+
{ 'id' => '#atproto_labeler', 'type' => 'AtprotoLabeler', 'serviceEndpoint' => 'https://labels.dholms.xyz' },
155
155
+
{ 'id' => '#lycan', 'type' => 'LycanService', 'serviceEndpoint' => 'https://lycan.feeds.blue' }
156
156
+
])
157
157
+
}
158
158
+
159
159
+
describe '#pds_endpoint' do
160
160
+
it 'should return the endpoint of #atproto_pds' do
161
161
+
doc = subject.new(did, service_json)
162
162
+
doc.pds_endpoint.should == 'https://pds.dholms.xyz'
163
163
+
end
164
164
+
end
165
165
+
166
166
+
describe '#pds_host' do
167
167
+
it 'should return the host part of #atproto_pds endpoint' do
168
168
+
doc = subject.new(did, service_json)
169
169
+
doc.pds_host.should == 'pds.dholms.xyz'
170
170
+
end
171
171
+
end
172
172
+
173
173
+
describe '#labeler_endpoint' do
174
174
+
it 'should return the endpoint of #atproto_labeler' do
175
175
+
doc = subject.new(did, service_json)
176
176
+
doc.labeler_endpoint.should == 'https://labels.dholms.xyz'
177
177
+
end
178
178
+
end
179
179
+
180
180
+
describe '#pds_host' do
181
181
+
it 'should return the host part of #atproto_labeler endpoint' do
182
182
+
doc = subject.new(did, service_json)
183
183
+
doc.labeler_host.should == 'labels.dholms.xyz'
184
184
+
end
185
185
+
end
186
186
+
187
187
+
describe '#get_service' do
188
188
+
it 'should fetch a service by key and type' do
189
189
+
doc = subject.new(did, service_json)
190
190
+
191
191
+
lycan = doc.get_service('lycan', 'LycanService')
192
192
+
lycan.should_not be_nil
193
193
+
lycan.endpoint.should == 'https://lycan.feeds.blue'
194
194
+
end
195
195
+
196
196
+
it 'should return nil if none of the services match' do
197
197
+
doc = subject.new(did, service_json)
198
198
+
199
199
+
result = doc.get_service('lycan', 'AtprotoLabeler')
200
200
+
result.should be_nil
201
201
+
202
202
+
result = doc.get_service('atproto_pds', 'PDS')
203
203
+
result.should be_nil
204
204
+
205
205
+
result = doc.get_service('unknown', 'Test')
206
206
+
result.should be_nil
207
207
+
end
208
208
+
end
209
209
+
210
210
+
it 'should expose the "labeller" aliases for endpoint and host' do
211
211
+
doc = subject.new(did, service_json)
212
212
+
213
213
+
doc.labeller_endpoint.should == 'https://labels.dholms.xyz'
214
214
+
doc.labeller_host.should == 'labels.dholms.xyz'
215
215
+
end
216
216
+
217
217
+
describe 'if there is no matching service' do
218
218
+
let(:service_json) {
219
219
+
json_data.merge('service' => [
220
220
+
{ 'id' => '#lycan', 'type' => 'LycanService', 'serviceEndpoint' => 'https://lycan.feeds.blue' }
221
221
+
])
222
222
+
}
223
223
+
224
224
+
it 'should return nil from the relevant methods' do
225
225
+
doc = subject.new(did, service_json)
226
226
+
227
227
+
doc.pds_endpoint.should be_nil
228
228
+
doc.pds_host.should be_nil
229
229
+
doc.labeller_endpoint.should be_nil
230
230
+
doc.labeller_host.should be_nil
231
231
+
doc.labeler_endpoint.should be_nil
232
232
+
doc.labeler_host.should be_nil
233
233
+
end
234
234
+
end
235
235
+
end
236
236
+
end
+5
spec/spec_helper.rb
···
1
1
# frozen_string_literal: true
2
2
3
3
require 'didkit'
4
4
+
require 'json'
4
5
require 'webmock/rspec'
5
6
6
7
RSpec.configure do |config|
···
21
22
def load_did_file(name)
22
23
File.read(File.join(__dir__, 'dids', name))
23
24
end
25
25
+
26
26
+
def load_did_json(name)
27
27
+
JSON.parse(load_did_file(name))
28
28
+
end