A library for handling DID identifiers used in Bluesky AT Protocol
at master 238 lines 7.3 kB view raw
1describe DIDKit::DID do 2 subject { described_class } 3 4 let(:plc_did) { 'did:plc:vc7f4oafdgxsihk4cry2xpze' } 5 let(:web_did) { 'did:web:taylorswift.com' } 6 7 describe '#initialize' do 8 context 'with a valid did:plc' do 9 it 'should return an initialized DID object' do 10 did = subject.new(plc_did) 11 12 did.should be_a(DIDKit::DID) 13 did.type.should == :plc 14 did.did.should be_a(String) 15 did.did.should == plc_did 16 did.resolved_by.should be_nil 17 end 18 end 19 20 context 'with a valid did:web' do 21 it 'should return an initialized DID object' do 22 did = subject.new(web_did) 23 24 did.should be_a(DIDKit::DID) 25 did.type.should == :web 26 did.did.should be_a(String) 27 did.did.should == web_did 28 did.resolved_by.should be_nil 29 end 30 end 31 32 context 'with another DID object' do 33 it 'should create a copy of the DID' do 34 other = subject.new(plc_did) 35 did = subject.new(other) 36 37 did.did.should == plc_did 38 did.type.should == :plc 39 did.equal?(other).should == false 40 end 41 end 42 43 context 'with a string that is not a DID' do 44 it 'should raise an error' do 45 expect { 46 subject.new('not-a-did') 47 }.to raise_error(DIDKit::DIDError) 48 end 49 end 50 51 context 'when an unrecognized did: type' do 52 it 'should raise an error' do 53 expect { 54 subject.new('did:example:123') 55 }.to raise_error(DIDKit::DIDError) 56 end 57 end 58 end 59 60 describe '#web_domain' do 61 context 'for a did:web' do 62 it 'should return the domain part' do 63 did = subject.new('did:web:site.example.com') 64 65 did.web_domain.should == 'site.example.com' 66 end 67 end 68 69 context 'for a did:plc' do 70 it 'should return nil' do 71 did = subject.new('did:plc:yk4dd2qkboz2yv6tpubpc6co') 72 73 did.web_domain.should be_nil 74 end 75 end 76 end 77 78 describe '#==' do 79 let(:did_string) { 'did:plc:vc7f4oafdgxsihk4cry2xpze' } 80 let(:other_string) { 'did:plc:oio4hkxaop4ao4wz2pp3f4cr' } 81 82 let(:did) { subject.new(did_string) } 83 let(:other) { subject.new(other_string) } 84 85 context 'given a DID string' do 86 it 'should compare its string value to the other DID' do 87 did.should == did_string 88 did.should_not == other_string 89 end 90 end 91 92 context 'given another DID object' do 93 it "should compare its string value to the other DID's string value" do 94 copy = subject.new(did_string) 95 96 did.should == copy 97 did.should_not == other 98 end 99 end 100 101 context 'given something that is not a DID' do 102 it 'should return false' do 103 did.should_not == :didplc 104 did.should_not == [did_string] 105 end 106 end 107 end 108 109 describe '#to_s' do 110 it "should return the DID's string value" do 111 did = subject.new(plc_did) 112 113 did.to_s.should be_a(String) 114 did.to_s.should == plc_did 115 end 116 end 117 118 describe 'account status' do 119 let(:document) { stub(:pds_endpoint => 'https://pds.ruby.space') } 120 let(:did) { subject.new(plc_did) } 121 122 before do 123 did.stubs(:document).returns(document) 124 125 stub_request(:get, 'https://pds.ruby.space/xrpc/com.atproto.sync.getRepoStatus') 126 .with(query: { did: plc_did }) 127 .to_return(http_response) if defined?(http_response) 128 end 129 130 context 'when repo is active' do 131 let(:http_response) { 132 { body: { active: true }.to_json, headers: { 'Content-Type' => 'application/json' }} 133 } 134 135 it 'should report active account state' do 136 did.account_status.should == :active 137 did.account_active?.should == true 138 did.account_exists?.should == true 139 end 140 end 141 142 context 'when repo is inactive' do 143 let(:http_response) { 144 { body: { active: false, status: 'takendown' }.to_json, headers: { 'Content-Type' => 'application/json' }} 145 } 146 147 it 'should report an inactive existing account' do 148 did.account_status.should == :takendown 149 did.account_active?.should == false 150 did.account_exists?.should == true 151 end 152 end 153 154 context 'when repo is not found' do 155 let(:http_response) { 156 { status: 400, body: { error: 'RepoNotFound' }.to_json, headers: { 'Content-Type' => 'application/json' }} 157 } 158 159 it 'should return nil status and report the account as missing' do 160 did.account_status.should be_nil 161 did.account_active?.should == false 162 did.account_exists?.should == false 163 end 164 end 165 166 context 'when the document has no pds endpoint' do 167 before do 168 did.stubs(:document).returns(stub(:pds_endpoint => nil)) 169 end 170 171 it 'should return nil status and report the account as missing' do 172 did.account_status.should be_nil 173 did.account_active?.should == false 174 did.account_exists?.should == false 175 end 176 end 177 178 context 'when active field is not set' do 179 let(:http_response) { 180 { body: { active: nil, status: 'unknown' }.to_json, headers: { 'Content-Type' => 'application/json' }} 181 } 182 183 it 'should raise APIError' do 184 expect { did.account_status }.to raise_error(DIDKit::APIError) 185 expect { did.account_active? }.to raise_error(DIDKit::APIError) 186 expect { did.account_exists? }.to raise_error(DIDKit::APIError) 187 end 188 end 189 190 context 'when active is false but status is not set' do 191 let(:http_response) { 192 { body: { active: false, status: nil }.to_json, headers: { 'Content-Type' => 'application/json' }} 193 } 194 195 it 'should raise APIError' do 196 expect { did.account_status }.to raise_error(DIDKit::APIError) 197 expect { did.account_active? }.to raise_error(DIDKit::APIError) 198 expect { did.account_exists? }.to raise_error(DIDKit::APIError) 199 end 200 end 201 202 context 'when an error different than RepoNotFound is returned' do 203 let(:http_response) { 204 { status: 400, body: { error: 'UserIsJerry' }.to_json, headers: { 'Content-Type' => 'application/json' }} 205 } 206 207 it 'should raise APIError' do 208 expect { did.account_status }.to raise_error(DIDKit::APIError) 209 expect { did.account_active? }.to raise_error(DIDKit::APIError) 210 expect { did.account_exists? }.to raise_error(DIDKit::APIError) 211 end 212 end 213 214 context 'when the response is not application/json' do 215 let(:http_response) { 216 { status: 400, body: 'error', headers: { 'Content-Type' => 'text/html' }} 217 } 218 219 it 'should raise APIError' do 220 expect { did.account_status }.to raise_error(DIDKit::APIError) 221 expect { did.account_active? }.to raise_error(DIDKit::APIError) 222 expect { did.account_exists? }.to raise_error(DIDKit::APIError) 223 end 224 end 225 226 context 'when the response is not 200 or 400' do 227 let(:http_response) { 228 { status: 500, body: { error: 'RepoNotFound' }.to_json, headers: { 'Content-Type' => 'application/json' }} 229 } 230 231 it 'should raise APIError' do 232 expect { did.account_status }.to raise_error(DIDKit::APIError) 233 expect { did.account_active? }.to raise_error(DIDKit::APIError) 234 expect { did.account_exists? }.to raise_error(DIDKit::APIError) 235 end 236 end 237 end 238end