package main import ( "encoding/json" "os" "path/filepath" "testing" ) func TestNewCredentialStore(t *testing.T) { t.Parallel() t.Run("non-existent path returns empty store", func(t *testing.T) { cs, err := newCredentialStore(filepath.Join(t.TempDir(), "nonexistent.json")) if err != nil { t.Fatalf("newCredentialStore(nonexistent) = _, %v, want nil", err) } if cs == nil { t.Fatal("newCredentialStore returned nil store") } }) t.Run("valid JSON loads credentials", func(t *testing.T) { path := filepath.Join(t.TempDir(), "creds.json") creds := map[string]localCred{ "cred1": {PublicKey: []byte("key1"), SignCount: 5}, } data, _ := json.Marshal(creds) os.WriteFile(path, data, 0600) cs, err := newCredentialStore(path) if err != nil { t.Fatalf("newCredentialStore(valid) = _, %v, want nil", err) } pk, sc, err := cs.Lookup("cred1") if err != nil { t.Fatalf("Lookup cred1: %v", err) } if string(pk) != "key1" { t.Errorf("publicKey = %q, want %q", string(pk), "key1") } if sc != 5 { t.Errorf("signCount = %d, want 5", sc) } }) t.Run("invalid JSON returns parse error", func(t *testing.T) { path := filepath.Join(t.TempDir(), "bad.json") os.WriteFile(path, []byte("{invalid"), 0600) _, err := newCredentialStore(path) if err == nil { t.Fatal("newCredentialStore(invalid JSON) = _, nil, want error") } }) t.Run("empty file returns empty store", func(t *testing.T) { path := filepath.Join(t.TempDir(), "empty.json") os.WriteFile(path, nil, 0600) cs, err := newCredentialStore(path) if err != nil { t.Fatalf("newCredentialStore(empty) = _, %v, want nil", err) } _, _, err = cs.Lookup("anything") if err == nil { t.Fatal("Lookup anything on empty store: expected error") } }) } func TestCredentialStoreSaveAndLookup(t *testing.T) { t.Parallel() t.Run("save then lookup returns credential with signCount=0", func(t *testing.T) { path := filepath.Join(t.TempDir(), "creds.json") cs, err := newCredentialStore(path) if err != nil { t.Fatal(err) } err = cs.Save("mykey", []byte("pubkey-data")) if err != nil { t.Fatalf("Save: %v", err) } pk, sc, err := cs.Lookup("mykey") if err != nil { t.Fatalf("Lookup mykey: %v", err) } if string(pk) != "pubkey-data" { t.Errorf("publicKey = %q, want %q", string(pk), "pubkey-data") } if sc != 0 { t.Errorf("signCount = %d, want 0", sc) } }) t.Run("save duplicate ID returns error", func(t *testing.T) { path := filepath.Join(t.TempDir(), "creds.json") cs, _ := newCredentialStore(path) cs.Save("dup", []byte("first")) err := cs.Save("dup", []byte("second")) if err == nil { t.Fatal("Save duplicate: expected error") } }) t.Run("lookup non-existent ID returns error", func(t *testing.T) { path := filepath.Join(t.TempDir(), "creds.json") cs, _ := newCredentialStore(path) _, _, err := cs.Lookup("nobody") if err == nil { t.Fatal("Lookup non-existent: expected error") } }) } func TestCredentialStoreUpdateSignCount(t *testing.T) { t.Parallel() t.Run("save, update, then lookup returns new count", func(t *testing.T) { path := filepath.Join(t.TempDir(), "creds.json") cs, _ := newCredentialStore(path) cs.Save("ctr", []byte("pk")) err := cs.UpdateSignCount("ctr", 42) if err != nil { t.Fatalf("UpdateSignCount: %v", err) } _, sc, err := cs.Lookup("ctr") if err != nil { t.Fatalf("Lookup after update: %v", err) } if sc != 42 { t.Errorf("signCount = %d, want 42", sc) } }) t.Run("update non-existent credential returns error", func(t *testing.T) { path := filepath.Join(t.TempDir(), "creds.json") cs, _ := newCredentialStore(path) err := cs.UpdateSignCount("ghost", 1) if err == nil { t.Fatal("UpdateSignCount non-existent: expected error") } }) } func TestCredentialStorePersistence(t *testing.T) { t.Parallel() t.Run("credential persists across store instances", func(t *testing.T) { path := filepath.Join(t.TempDir(), "persist.json") cs, _ := newCredentialStore(path) cs.Save("persist-key", []byte("persist-data")) cs2, err := newCredentialStore(path) if err != nil { t.Fatalf("newCredentialStore(reopen): %v", err) } pk, _, err := cs2.Lookup("persist-key") if err != nil { t.Fatalf("Lookup persist-key after reopen: %v", err) } if string(pk) != "persist-data" { t.Errorf("publicKey = %q, want %q", string(pk), "persist-data") } }) t.Run("file deleted results in empty store", func(t *testing.T) { path := filepath.Join(t.TempDir(), "deleted.json") cs, _ := newCredentialStore(path) cs.Save("gone-key", []byte("gone-data")) os.Remove(path) cs2, err := newCredentialStore(path) if err != nil { t.Fatalf("newCredentialStore(after delete): %v", err) } _, _, err = cs2.Lookup("gone-key") if err == nil { t.Fatal("Lookup gone-key after file delete: expected error") } }) }