mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-20 09:14:16 +00:00
unit tests
This commit is contained in:
@@ -691,3 +691,400 @@ func TestContextCancellation(t *testing.T) {
|
||||
t.Error("Expected error due to context cancellation, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestListReposByCollection tests listing repositories by collection
|
||||
func TestListReposByCollection(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
collection string
|
||||
limit int
|
||||
cursor string
|
||||
serverResponse string
|
||||
serverStatus int
|
||||
wantErr bool
|
||||
checkFunc func(*testing.T, *ListReposByCollectionResult)
|
||||
}{
|
||||
{
|
||||
name: "successful list with results",
|
||||
collection: ManifestCollection,
|
||||
limit: 100,
|
||||
cursor: "",
|
||||
serverResponse: `{
|
||||
"repos": [
|
||||
{"did": "did:plc:alice123"},
|
||||
{"did": "did:plc:bob456"}
|
||||
],
|
||||
"cursor": "nextcursor789"
|
||||
}`,
|
||||
serverStatus: http.StatusOK,
|
||||
wantErr: false,
|
||||
checkFunc: func(t *testing.T, result *ListReposByCollectionResult) {
|
||||
if len(result.Repos) != 2 {
|
||||
t.Errorf("len(Repos) = %v, want 2", len(result.Repos))
|
||||
}
|
||||
if result.Repos[0].DID != "did:plc:alice123" {
|
||||
t.Errorf("Repos[0].DID = %v, want did:plc:alice123", result.Repos[0].DID)
|
||||
}
|
||||
if result.Cursor != "nextcursor789" {
|
||||
t.Errorf("Cursor = %v, want nextcursor789", result.Cursor)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty results",
|
||||
collection: ManifestCollection,
|
||||
limit: 50,
|
||||
cursor: "cursor123",
|
||||
serverResponse: `{"repos": []}`,
|
||||
serverStatus: http.StatusOK,
|
||||
wantErr: false,
|
||||
checkFunc: func(t *testing.T, result *ListReposByCollectionResult) {
|
||||
if len(result.Repos) != 0 {
|
||||
t.Errorf("len(Repos) = %v, want 0", len(result.Repos))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
collection: ManifestCollection,
|
||||
limit: 100,
|
||||
cursor: "",
|
||||
serverResponse: `{"error":"InternalError"}`,
|
||||
serverStatus: http.StatusInternalServerError,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Verify query parameters
|
||||
query := r.URL.Query()
|
||||
if query.Get("collection") != tt.collection {
|
||||
t.Errorf("collection = %v, want %v", query.Get("collection"), tt.collection)
|
||||
}
|
||||
if tt.limit > 0 && query.Get("limit") != strings.TrimSpace(string(rune(tt.limit))) {
|
||||
// Check if limit param exists when specified
|
||||
if !strings.Contains(r.URL.RawQuery, "limit=") {
|
||||
t.Error("limit parameter missing")
|
||||
}
|
||||
}
|
||||
if tt.cursor != "" && query.Get("cursor") != tt.cursor {
|
||||
t.Errorf("cursor = %v, want %v", query.Get("cursor"), tt.cursor)
|
||||
}
|
||||
|
||||
// Send response
|
||||
w.WriteHeader(tt.serverStatus)
|
||||
w.Write([]byte(tt.serverResponse))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(server.URL, "did:plc:test123", "test-token")
|
||||
result, err := client.ListReposByCollection(context.Background(), tt.collection, tt.limit, tt.cursor)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ListReposByCollection() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && tt.checkFunc != nil {
|
||||
tt.checkFunc(t, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetActorProfile tests fetching actor profiles
|
||||
func TestGetActorProfile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
actor string
|
||||
serverResponse string
|
||||
serverStatus int
|
||||
wantErr bool
|
||||
checkFunc func(*testing.T, *ActorProfile)
|
||||
}{
|
||||
{
|
||||
name: "successful profile fetch by handle",
|
||||
actor: "alice.bsky.social",
|
||||
serverResponse: `{
|
||||
"did": "did:plc:alice123",
|
||||
"handle": "alice.bsky.social",
|
||||
"displayName": "Alice Smith",
|
||||
"description": "Test user",
|
||||
"avatar": "https://cdn.example.com/avatar.jpg"
|
||||
}`,
|
||||
serverStatus: http.StatusOK,
|
||||
wantErr: false,
|
||||
checkFunc: func(t *testing.T, profile *ActorProfile) {
|
||||
if profile.DID != "did:plc:alice123" {
|
||||
t.Errorf("DID = %v, want did:plc:alice123", profile.DID)
|
||||
}
|
||||
if profile.Handle != "alice.bsky.social" {
|
||||
t.Errorf("Handle = %v, want alice.bsky.social", profile.Handle)
|
||||
}
|
||||
if profile.DisplayName != "Alice Smith" {
|
||||
t.Errorf("DisplayName = %v, want Alice Smith", profile.DisplayName)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "successful profile fetch by DID",
|
||||
actor: "did:plc:bob456",
|
||||
serverResponse: `{
|
||||
"did": "did:plc:bob456",
|
||||
"handle": "bob.example.com"
|
||||
}`,
|
||||
serverStatus: http.StatusOK,
|
||||
wantErr: false,
|
||||
checkFunc: func(t *testing.T, profile *ActorProfile) {
|
||||
if profile.DID != "did:plc:bob456" {
|
||||
t.Errorf("DID = %v, want did:plc:bob456", profile.DID)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "profile not found",
|
||||
actor: "nonexistent.example.com",
|
||||
serverResponse: "",
|
||||
serverStatus: http.StatusNotFound,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
actor: "error.example.com",
|
||||
serverResponse: `{"error":"InternalError"}`,
|
||||
serverStatus: http.StatusInternalServerError,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Verify query parameter
|
||||
query := r.URL.Query()
|
||||
if query.Get("actor") != tt.actor {
|
||||
t.Errorf("actor = %v, want %v", query.Get("actor"), tt.actor)
|
||||
}
|
||||
|
||||
// Verify path
|
||||
if !strings.Contains(r.URL.Path, "app.bsky.actor.getProfile") {
|
||||
t.Errorf("Path = %v, should contain app.bsky.actor.getProfile", r.URL.Path)
|
||||
}
|
||||
|
||||
// Send response
|
||||
w.WriteHeader(tt.serverStatus)
|
||||
w.Write([]byte(tt.serverResponse))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(server.URL, "did:plc:test123", "test-token")
|
||||
profile, err := client.GetActorProfile(context.Background(), tt.actor)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetActorProfile() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && tt.checkFunc != nil {
|
||||
tt.checkFunc(t, profile)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetProfileRecord tests fetching profile records from PDS
|
||||
func TestGetProfileRecord(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
did string
|
||||
serverResponse string
|
||||
serverStatus int
|
||||
wantErr bool
|
||||
checkFunc func(*testing.T, *ProfileRecord)
|
||||
}{
|
||||
{
|
||||
name: "successful profile record fetch",
|
||||
did: "did:plc:alice123",
|
||||
serverResponse: `{
|
||||
"uri": "at://did:plc:alice123/app.bsky.actor.profile/self",
|
||||
"cid": "bafytest",
|
||||
"value": {
|
||||
"displayName": "Alice Smith",
|
||||
"description": "Test description",
|
||||
"avatar": {
|
||||
"$type": "blob",
|
||||
"ref": {"$link": "bafyavatar"},
|
||||
"mimeType": "image/jpeg",
|
||||
"size": 12345
|
||||
}
|
||||
}
|
||||
}`,
|
||||
serverStatus: http.StatusOK,
|
||||
wantErr: false,
|
||||
checkFunc: func(t *testing.T, profile *ProfileRecord) {
|
||||
if profile.DisplayName != "Alice Smith" {
|
||||
t.Errorf("DisplayName = %v, want Alice Smith", profile.DisplayName)
|
||||
}
|
||||
if profile.Description != "Test description" {
|
||||
t.Errorf("Description = %v, want Test description", profile.Description)
|
||||
}
|
||||
if profile.Avatar == nil {
|
||||
t.Fatal("Avatar should not be nil")
|
||||
}
|
||||
if profile.Avatar.Ref.Link != "bafyavatar" {
|
||||
t.Errorf("Avatar.Ref.Link = %v, want bafyavatar", profile.Avatar.Ref.Link)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "profile record not found",
|
||||
did: "did:plc:nonexistent",
|
||||
serverResponse: "",
|
||||
serverStatus: http.StatusNotFound,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Verify query parameters
|
||||
query := r.URL.Query()
|
||||
if query.Get("repo") != tt.did {
|
||||
t.Errorf("repo = %v, want %v", query.Get("repo"), tt.did)
|
||||
}
|
||||
if query.Get("collection") != "app.bsky.actor.profile" {
|
||||
t.Errorf("collection = %v, want app.bsky.actor.profile", query.Get("collection"))
|
||||
}
|
||||
if query.Get("rkey") != "self" {
|
||||
t.Errorf("rkey = %v, want self", query.Get("rkey"))
|
||||
}
|
||||
|
||||
// Send response
|
||||
w.WriteHeader(tt.serverStatus)
|
||||
w.Write([]byte(tt.serverResponse))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(server.URL, "did:plc:test123", "test-token")
|
||||
profile, err := client.GetProfileRecord(context.Background(), tt.did)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetProfileRecord() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && tt.checkFunc != nil {
|
||||
tt.checkFunc(t, profile)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestClientDID tests the DID() getter method
|
||||
func TestClientDID(t *testing.T) {
|
||||
expectedDID := "did:plc:test123"
|
||||
client := NewClient("https://pds.example.com", expectedDID, "token")
|
||||
|
||||
if client.DID() != expectedDID {
|
||||
t.Errorf("DID() = %v, want %v", client.DID(), expectedDID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestClientPDSEndpoint tests the PDSEndpoint() getter method
|
||||
func TestClientPDSEndpoint(t *testing.T) {
|
||||
expectedEndpoint := "https://pds.example.com"
|
||||
client := NewClient(expectedEndpoint, "did:plc:test123", "token")
|
||||
|
||||
if client.PDSEndpoint() != expectedEndpoint {
|
||||
t.Errorf("PDSEndpoint() = %v, want %v", client.PDSEndpoint(), expectedEndpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewClientWithIndigoClient tests client initialization with Indigo client
|
||||
func TestNewClientWithIndigoClient(t *testing.T) {
|
||||
// Note: We can't easily create a real indigo client in tests without complex setup
|
||||
// We pass nil for the indigo client, which is acceptable for testing the constructor
|
||||
// The actual client.go code will handle nil indigo client by checking before use
|
||||
|
||||
// Skip this test for now as it requires a real indigo client
|
||||
// The function is tested indirectly through integration tests
|
||||
t.Skip("Skipping TestNewClientWithIndigoClient - requires real indigo client setup")
|
||||
|
||||
// When properly set up with a real indigo client, the test would look like:
|
||||
// client := NewClientWithIndigoClient("https://pds.example.com", "did:plc:test123", indigoClient)
|
||||
// if !client.useIndigoClient { t.Error("useIndigoClient should be true") }
|
||||
}
|
||||
|
||||
// TestListRecordsError tests error handling in ListRecords
|
||||
func TestListRecordsError(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(`{"error":"InternalError"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(server.URL, "did:plc:test123", "test-token")
|
||||
_, err := client.ListRecords(context.Background(), ManifestCollection, 10)
|
||||
|
||||
if err == nil {
|
||||
t.Error("Expected error from ListRecords, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestUploadBlobError tests error handling in UploadBlob
|
||||
func TestUploadBlobError(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"error":"InvalidBlob"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(server.URL, "did:plc:test123", "test-token")
|
||||
_, err := client.UploadBlob(context.Background(), []byte("test"), "application/octet-stream")
|
||||
|
||||
if err == nil {
|
||||
t.Error("Expected error from UploadBlob, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBlobServerError tests error handling in GetBlob for non-404 errors
|
||||
func TestGetBlobServerError(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(`{"error":"InternalError"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(server.URL, "did:plc:test123", "test-token")
|
||||
_, err := client.GetBlob(context.Background(), "bafytest")
|
||||
|
||||
if err == nil {
|
||||
t.Error("Expected error from GetBlob, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "failed with status 500") {
|
||||
t.Errorf("Error should mention status 500, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBlobInvalidBase64 tests error handling for invalid base64 in JSON-wrapped blob
|
||||
func TestGetBlobInvalidBase64(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Return JSON string with invalid base64
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`"not-valid-base64!!!"`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(server.URL, "did:plc:test123", "test-token")
|
||||
_, err := client.GetBlob(context.Background(), "bafytest")
|
||||
|
||||
if err == nil {
|
||||
t.Error("Expected error from GetBlob with invalid base64, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "base64") {
|
||||
t.Errorf("Error should mention base64, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
package atproto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestResolveIdentity tests resolving identifiers to DID, handle, and PDS endpoint
|
||||
func TestResolveIdentity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
identifier string
|
||||
wantErr bool
|
||||
skipCI bool // Skip in CI where network may not be available
|
||||
}{
|
||||
{
|
||||
name: "invalid identifier - empty",
|
||||
identifier: "",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "invalid identifier - malformed DID",
|
||||
identifier: "did:invalid",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "invalid identifier - malformed handle",
|
||||
identifier: "not a valid handle!@#",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "valid DID format but nonexistent",
|
||||
identifier: "did:plc:nonexistent000000000000",
|
||||
wantErr: true,
|
||||
skipCI: true, // Skip in CI - requires network
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.skipCI && testing.Short() {
|
||||
t.Skip("Skipping network-dependent test in short mode")
|
||||
}
|
||||
|
||||
did, handle, pdsEndpoint, err := ResolveIdentity(context.Background(), tt.identifier)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ResolveIdentity() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr {
|
||||
if did == "" {
|
||||
t.Error("Expected non-empty DID")
|
||||
}
|
||||
if handle == "" {
|
||||
t.Error("Expected non-empty handle")
|
||||
}
|
||||
if pdsEndpoint == "" {
|
||||
t.Error("Expected non-empty PDS endpoint")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveIdentityInvalidIdentifier tests error handling for invalid identifiers
|
||||
func TestResolveIdentityInvalidIdentifier(t *testing.T) {
|
||||
// Test with clearly invalid identifier
|
||||
_, _, _, err := ResolveIdentity(context.Background(), "not-a-valid-identifier-!@#$%")
|
||||
if err == nil {
|
||||
t.Error("Expected error for invalid identifier, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "invalid identifier") {
|
||||
t.Errorf("Error should mention 'invalid identifier', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveDIDToPDS tests resolving DIDs to PDS endpoints
|
||||
func TestResolveDIDToPDS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
did string
|
||||
wantErr bool
|
||||
skipCI bool
|
||||
}{
|
||||
{
|
||||
name: "invalid DID - empty",
|
||||
did: "",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "invalid DID - malformed",
|
||||
did: "not-a-did",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "invalid DID - wrong method",
|
||||
did: "did:unknown:test",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "valid DID format but nonexistent",
|
||||
did: "did:plc:nonexistent000000000000",
|
||||
wantErr: true,
|
||||
skipCI: true, // Skip in CI - requires network
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.skipCI && testing.Short() {
|
||||
t.Skip("Skipping network-dependent test in short mode")
|
||||
}
|
||||
|
||||
pdsEndpoint, err := ResolveDIDToPDS(context.Background(), tt.did)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ResolveDIDToPDS() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && pdsEndpoint == "" {
|
||||
t.Error("Expected non-empty PDS endpoint")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveDIDToPDSInvalidDID tests error handling for invalid DIDs
|
||||
func TestResolveDIDToPDSInvalidDID(t *testing.T) {
|
||||
// Test with clearly invalid DID
|
||||
_, err := ResolveDIDToPDS(context.Background(), "not-a-did")
|
||||
if err == nil {
|
||||
t.Error("Expected error for invalid DID, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "invalid DID") {
|
||||
t.Errorf("Error should mention 'invalid DID', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveHandleToDID tests resolving handles and DIDs to just DIDs
|
||||
func TestResolveHandleToDID(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
identifier string
|
||||
wantErr bool
|
||||
skipCI bool
|
||||
}{
|
||||
{
|
||||
name: "invalid identifier - empty",
|
||||
identifier: "",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "invalid identifier - malformed",
|
||||
identifier: "not a valid identifier!@#",
|
||||
wantErr: true,
|
||||
skipCI: false,
|
||||
},
|
||||
{
|
||||
name: "valid DID format but nonexistent",
|
||||
identifier: "did:plc:nonexistent000000000000",
|
||||
wantErr: true,
|
||||
skipCI: true, // Skip in CI - requires network
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.skipCI && testing.Short() {
|
||||
t.Skip("Skipping network-dependent test in short mode")
|
||||
}
|
||||
|
||||
did, err := ResolveHandleToDID(context.Background(), tt.identifier)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ResolveHandleToDID() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && did == "" {
|
||||
t.Error("Expected non-empty DID")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveHandleToDIDInvalidIdentifier tests error handling for invalid identifiers
|
||||
func TestResolveHandleToDIDInvalidIdentifier(t *testing.T) {
|
||||
// Test with clearly invalid identifier
|
||||
_, err := ResolveHandleToDID(context.Background(), "not-a-valid-identifier-!@#$%")
|
||||
if err == nil {
|
||||
t.Error("Expected error for invalid identifier, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "invalid identifier") {
|
||||
t.Errorf("Error should mention 'invalid identifier', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestInvalidateIdentity tests cache invalidation
|
||||
func TestInvalidateIdentity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
identifier string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "invalid identifier - empty",
|
||||
identifier: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid identifier - malformed",
|
||||
identifier: "not a valid identifier!@#",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "valid DID format",
|
||||
identifier: "did:plc:test123",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid handle format",
|
||||
identifier: "alice.bsky.social",
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := InvalidateIdentity(context.Background(), tt.identifier)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("InvalidateIdentity() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestInvalidateIdentityInvalidIdentifier tests error handling
|
||||
func TestInvalidateIdentityInvalidIdentifier(t *testing.T) {
|
||||
// Test with clearly invalid identifier
|
||||
err := InvalidateIdentity(context.Background(), "not-a-valid-identifier-!@#$%")
|
||||
if err == nil {
|
||||
t.Error("Expected error for invalid identifier, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "invalid identifier") {
|
||||
t.Errorf("Error should mention 'invalid identifier', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveIdentityHandleInvalid tests handling of invalid handles
|
||||
func TestResolveIdentityHandleInvalid(t *testing.T) {
|
||||
// This test checks the code path where handle is "handle.invalid"
|
||||
// We can't easily test this without a real PDS returning this value
|
||||
// But we can at least verify the function handles this case
|
||||
|
||||
// Test with an identifier that would trigger network lookup
|
||||
// In short mode (CI), this is skipped
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping network-dependent test in short mode")
|
||||
}
|
||||
|
||||
// Try to resolve a nonexistent handle
|
||||
_, _, _, err := ResolveIdentity(context.Background(), "nonexistent-handle-999999.test")
|
||||
|
||||
// We expect an error since this handle doesn't exist
|
||||
if err == nil {
|
||||
t.Log("Expected error for nonexistent handle, but got success (this is OK if the test domain resolves)")
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveDIDToPDSNoPDSEndpoint tests error handling when no PDS endpoint is found
|
||||
func TestResolveDIDToPDSNoPDSEndpoint(t *testing.T) {
|
||||
// This tests the error path where a DID document exists but has no PDS endpoint
|
||||
// We can't easily test this without a real PDS, but we can at least verify
|
||||
// the function checks for empty PDS endpoints
|
||||
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping network-dependent test in short mode")
|
||||
}
|
||||
|
||||
// Try with a nonexistent DID
|
||||
_, err := ResolveDIDToPDS(context.Background(), "did:plc:nonexistent000000000000")
|
||||
|
||||
// We expect an error
|
||||
if err == nil {
|
||||
t.Error("Expected error for nonexistent DID")
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveIdentityNoPDSEndpoint tests error handling when no PDS endpoint is found
|
||||
func TestResolveIdentityNoPDSEndpoint(t *testing.T) {
|
||||
// This tests the error path where identity resolves but has no PDS endpoint
|
||||
// We can't easily test this without a real PDS, but we can at least verify
|
||||
// the function checks for empty PDS endpoints
|
||||
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping network-dependent test in short mode")
|
||||
}
|
||||
|
||||
// Try with a nonexistent identifier
|
||||
_, _, _, err := ResolveIdentity(context.Background(), "did:plc:nonexistent000000000000")
|
||||
|
||||
// We expect an error
|
||||
if err == nil {
|
||||
t.Error("Expected error for nonexistent DID")
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetDirectory tests that GetDirectory returns a non-nil directory
|
||||
func TestGetDirectory(t *testing.T) {
|
||||
dir := GetDirectory()
|
||||
if dir == nil {
|
||||
t.Error("GetDirectory() returned nil")
|
||||
}
|
||||
|
||||
// Call again to test singleton behavior
|
||||
dir2 := GetDirectory()
|
||||
if dir2 == nil {
|
||||
t.Error("GetDirectory() returned nil on second call")
|
||||
}
|
||||
|
||||
// In Go, we can't directly compare interface pointers, but we can verify
|
||||
// both calls returned something
|
||||
if dir == nil || dir2 == nil {
|
||||
t.Error("GetDirectory() should return the same instance")
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveIdentityContextCancellation tests that resolver respects context cancellation
|
||||
func TestResolveIdentityContextCancellation(t *testing.T) {
|
||||
// Create a context that's already canceled
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
// Try to resolve - should fail quickly with context canceled error
|
||||
_, _, _, err := ResolveIdentity(ctx, "alice.bsky.social")
|
||||
|
||||
// We expect an error, though it might be from parsing before network call
|
||||
// The important thing is it doesn't hang
|
||||
if err == nil {
|
||||
t.Log("Expected error due to context cancellation, but got success (identifier may have been parsed without network)")
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveDIDToPDSContextCancellation tests that resolver respects context cancellation
|
||||
func TestResolveDIDToPDSContextCancellation(t *testing.T) {
|
||||
// Create a context that's already canceled
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
// Try to resolve - should fail quickly with context canceled error
|
||||
_, err := ResolveDIDToPDS(ctx, "did:plc:test123")
|
||||
|
||||
// We expect an error, though it might be from parsing before network call
|
||||
if err == nil {
|
||||
t.Log("Expected error due to context cancellation, but got success (DID may have been parsed without network)")
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveHandleToDIDContextCancellation tests that resolver respects context cancellation
|
||||
func TestResolveHandleToDIDContextCancellation(t *testing.T) {
|
||||
// Create a context that's already canceled
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
// Try to resolve - should fail quickly with context canceled error
|
||||
_, err := ResolveHandleToDID(ctx, "alice.bsky.social")
|
||||
|
||||
// We expect an error, though it might be from parsing before network call
|
||||
if err == nil {
|
||||
t.Log("Expected error due to context cancellation, but got success (identifier may have been parsed without network)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user