A very experimental PLC implementation which uses BFT consensus for decentralization
24
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 096b0f2ced4a6322dac290af85ec2c5d6768cc28 313 lines 9.7 kB view raw
1package httpapi 2 3import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/http/httptest" 10 "testing" 11 "time" 12 13 "github.com/did-method-plc/go-didplc" 14 "github.com/stretchr/testify/require" 15 "tangled.org/gbl08ma.com/didplcbft/plc" 16 "tangled.org/gbl08ma.com/didplcbft/types" 17) 18 19// MockReadPLC is a mock implementation of the ReadPLC interface for testing. 20type MockReadPLC struct { 21 shouldReturnError bool 22 errorType string 23} 24 25func (m *MockReadPLC) ValidateOperation(ctx context.Context, atHeight plc.TreeVersion, at time.Time, did string, opBytes []byte) error { 26 if m.shouldReturnError { 27 switch m.errorType { 28 case "notfound": 29 return plc.ErrDIDNotFound 30 case "gone": 31 return plc.ErrDIDGone 32 } 33 return fmt.Errorf("internal error") 34 } 35 return nil 36} 37 38func (m *MockReadPLC) Resolve(ctx context.Context, atHeight plc.TreeVersion, did string) (didplc.Doc, error) { 39 if m.shouldReturnError { 40 switch m.errorType { 41 case "notfound": 42 return didplc.Doc{}, plc.ErrDIDNotFound 43 case "gone": 44 return didplc.Doc{}, plc.ErrDIDGone 45 } 46 return didplc.Doc{}, fmt.Errorf("internal error") 47 } 48 return didplc.Doc{ 49 ID: "did:plc:test", 50 }, nil 51} 52 53func (m *MockReadPLC) OperationLog(ctx context.Context, atHeight plc.TreeVersion, did string) ([]didplc.OpEnum, error) { 54 if m.shouldReturnError { 55 if m.errorType == "notfound" { 56 return []didplc.OpEnum{}, plc.ErrDIDNotFound 57 } 58 return []didplc.OpEnum{}, fmt.Errorf("internal error") 59 } 60 return []didplc.OpEnum{}, nil 61} 62 63func (m *MockReadPLC) AuditLog(ctx context.Context, atHeight plc.TreeVersion, did string) ([]didplc.LogEntry, error) { 64 if m.shouldReturnError { 65 if m.errorType == "notfound" { 66 return []didplc.LogEntry{}, plc.ErrDIDNotFound 67 } 68 return []didplc.LogEntry{}, fmt.Errorf("internal error") 69 } 70 return []didplc.LogEntry{}, nil 71} 72 73func (m *MockReadPLC) LastOperation(ctx context.Context, atHeight plc.TreeVersion, did string) (didplc.OpEnum, error) { 74 if m.shouldReturnError { 75 if m.errorType == "notfound" { 76 return didplc.OpEnum{}, plc.ErrDIDNotFound 77 } 78 return didplc.OpEnum{}, fmt.Errorf("internal error") 79 } 80 return didplc.OpEnum{}, nil 81} 82 83func (m *MockReadPLC) Data(ctx context.Context, atHeight plc.TreeVersion, did string) (didplc.RegularOp, error) { 84 if m.shouldReturnError { 85 switch m.errorType { 86 case "notfound": 87 return didplc.RegularOp{}, plc.ErrDIDNotFound 88 case "gone": 89 return didplc.RegularOp{}, plc.ErrDIDGone 90 } 91 return didplc.RegularOp{}, fmt.Errorf("internal error") 92 } 93 return didplc.RegularOp{}, nil 94} 95 96func (m *MockReadPLC) Export(ctx context.Context, atHeight plc.TreeVersion, after uint64, count int) ([]types.SequencedLogEntry, error) { 97 if m.shouldReturnError { 98 return []types.SequencedLogEntry{}, fmt.Errorf("internal error") 99 } 100 return []types.SequencedLogEntry{}, nil 101} 102 103func TestServer(t *testing.T) { 104 mockPLC := &MockReadPLC{} 105 106 t.Run("Test Resolve DID", func(t *testing.T) { 107 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 108 require.NoError(t, err) 109 110 req, err := http.NewRequest("GET", "/did:plc:test", nil) 111 require.NoError(t, err) 112 113 rr := httptest.NewRecorder() 114 server.router.ServeHTTP(rr, req) 115 116 require.Equal(t, http.StatusOK, rr.Code) 117 require.Contains(t, rr.Body.String(), "did:plc:test") 118 }) 119 120 t.Run("Test Resolve DID Not Found", func(t *testing.T) { 121 mockPLC := &MockReadPLC{shouldReturnError: true, errorType: "notfound"} 122 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 123 require.NoError(t, err) 124 125 req, err := http.NewRequest("GET", "/did:plc:test", nil) 126 require.NoError(t, err) 127 128 rr := httptest.NewRecorder() 129 server.router.ServeHTTP(rr, req) 130 131 require.Equal(t, http.StatusNotFound, rr.Code) 132 require.Contains(t, rr.Body.String(), "DID not registered: did:plc:test") 133 }) 134 135 t.Run("Test Resolve DID Gone", func(t *testing.T) { 136 mockPLC := &MockReadPLC{shouldReturnError: true, errorType: "gone"} 137 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 138 require.NoError(t, err) 139 140 req, err := http.NewRequest("GET", "/did:plc:test", nil) 141 require.NoError(t, err) 142 143 rr := httptest.NewRecorder() 144 server.router.ServeHTTP(rr, req) 145 146 require.Equal(t, http.StatusGone, rr.Code) 147 require.Contains(t, rr.Body.String(), "DID not available: did:plc:test") 148 }) 149 150 t.Run("Test Resolve DID Internal Error", func(t *testing.T) { 151 mockPLC := &MockReadPLC{shouldReturnError: true, errorType: "internal"} 152 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 153 require.NoError(t, err) 154 155 req, err := http.NewRequest("GET", "/did:plc:test", nil) 156 require.NoError(t, err) 157 158 rr := httptest.NewRecorder() 159 server.router.ServeHTTP(rr, req) 160 161 require.Equal(t, http.StatusInternalServerError, rr.Code) 162 require.Contains(t, rr.Body.String(), "Internal server error") 163 }) 164 165 t.Run("Test Create PLC Operation", func(t *testing.T) { 166 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 167 require.NoError(t, err) 168 169 op := map[string]interface{}{ 170 "type": "plc_operation", 171 "rotationKeys": []string{"did:key:test"}, 172 "verificationMethods": map[string]string{"atproto": "did:key:test"}, 173 "alsoKnownAs": []string{"at://test"}, 174 "services": map[string]interface{}{"atproto_pds": map[string]string{"type": "AtprotoPersonalDataServer", "endpoint": "https://test.com"}}, 175 "prev": nil, 176 "sig": "test", 177 } 178 opBytes, _ := json.Marshal(op) 179 180 req, err := http.NewRequest("POST", "/did:plc:test", bytes.NewBuffer(opBytes)) 181 require.NoError(t, err) 182 183 rr := httptest.NewRecorder() 184 server.router.ServeHTTP(rr, req) 185 186 require.Equal(t, http.StatusOK, rr.Code) 187 }) 188 189 t.Run("Test Get PLC Log", func(t *testing.T) { 190 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 191 require.NoError(t, err) 192 193 req, err := http.NewRequest("GET", "/did:plc:test/log", nil) 194 require.NoError(t, err) 195 196 rr := httptest.NewRecorder() 197 server.router.ServeHTTP(rr, req) 198 199 require.Equal(t, http.StatusOK, rr.Code) 200 }) 201 202 t.Run("Test Get PLC Log Not Found", func(t *testing.T) { 203 mockPLC := &MockReadPLC{shouldReturnError: true, errorType: "notfound"} 204 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 205 require.NoError(t, err) 206 207 req, err := http.NewRequest("GET", "/did:plc:test/log", nil) 208 require.NoError(t, err) 209 210 rr := httptest.NewRecorder() 211 server.router.ServeHTTP(rr, req) 212 213 require.Equal(t, http.StatusNotFound, rr.Code) 214 require.Contains(t, rr.Body.String(), "DID not registered: did:plc:test") 215 }) 216 217 t.Run("Test Get PLC Audit Log", func(t *testing.T) { 218 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 219 require.NoError(t, err) 220 221 req, err := http.NewRequest("GET", "/did:plc:test/log/audit", nil) 222 require.NoError(t, err) 223 224 rr := httptest.NewRecorder() 225 server.router.ServeHTTP(rr, req) 226 227 require.Equal(t, http.StatusOK, rr.Code) 228 }) 229 230 t.Run("Test Get Last Operation", func(t *testing.T) { 231 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 232 require.NoError(t, err) 233 234 req, err := http.NewRequest("GET", "/did:plc:test/log/last", nil) 235 require.NoError(t, err) 236 237 rr := httptest.NewRecorder() 238 server.router.ServeHTTP(rr, req) 239 240 require.Equal(t, http.StatusOK, rr.Code) 241 }) 242 243 t.Run("Test Get Last Operation Internal Error", func(t *testing.T) { 244 mockPLC := &MockReadPLC{shouldReturnError: true, errorType: "internal"} 245 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 246 require.NoError(t, err) 247 248 req, err := http.NewRequest("GET", "/did:plc:test/log/last", nil) 249 require.NoError(t, err) 250 251 rr := httptest.NewRecorder() 252 server.router.ServeHTTP(rr, req) 253 254 require.Equal(t, http.StatusInternalServerError, rr.Code) 255 require.Contains(t, rr.Body.String(), "Internal server error") 256 }) 257 258 t.Run("Test Get PLC Data", func(t *testing.T) { 259 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 260 require.NoError(t, err) 261 262 req, err := http.NewRequest("GET", "/did:plc:test/data", nil) 263 require.NoError(t, err) 264 265 rr := httptest.NewRecorder() 266 server.router.ServeHTTP(rr, req) 267 268 require.Equal(t, http.StatusOK, rr.Code) 269 }) 270 271 t.Run("Test Get PLC Data Not Found", func(t *testing.T) { 272 mockPLC := &MockReadPLC{shouldReturnError: true, errorType: "notfound"} 273 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 274 require.NoError(t, err) 275 276 req, err := http.NewRequest("GET", "/did:plc:test/data", nil) 277 require.NoError(t, err) 278 279 rr := httptest.NewRecorder() 280 server.router.ServeHTTP(rr, req) 281 282 require.Equal(t, http.StatusNotFound, rr.Code) 283 require.Contains(t, rr.Body.String(), "DID not registered: did:plc:test") 284 }) 285 286 t.Run("Test Export", func(t *testing.T) { 287 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 288 require.NoError(t, err) 289 290 req, err := http.NewRequest("GET", "/export?count=10", nil) 291 require.NoError(t, err) 292 293 rr := httptest.NewRecorder() 294 server.router.ServeHTTP(rr, req) 295 296 require.Equal(t, http.StatusOK, rr.Code) 297 }) 298 299 t.Run("Test Export Internal Error", func(t *testing.T) { 300 mockPLC := &MockReadPLC{shouldReturnError: true, errorType: "internal"} 301 server, err := NewServer(mockPLC, nil, "tcp://127.0.0.1:8080", 15*time.Second) 302 require.NoError(t, err) 303 304 req, err := http.NewRequest("GET", "/export?count=10", nil) 305 require.NoError(t, err) 306 307 rr := httptest.NewRecorder() 308 server.router.ServeHTTP(rr, req) 309 310 require.Equal(t, http.StatusInternalServerError, rr.Code) 311 require.Contains(t, rr.Body.String(), "Internal server error") 312 }) 313}