Testplan — Favoritter
Dekning (oppdatert 2026-04-03)
| Lag |
Pakke |
Testfiler |
Testfunksjoner |
Dekning |
| Data |
internal/store |
6 |
24 |
70.8 % |
| HTTP (web) |
internal/handler |
2 |
55 |
56.1 % |
| HTTP (API) |
internal/handler/api |
1 |
28 |
75.8 % |
| Mellomvare |
internal/middleware |
3 |
29 |
83.1 % |
| Konfig |
internal/config |
1 |
8 |
81.1 % |
| Bilde |
internal/image |
1 |
10 |
85.7 % |
| Database |
internal/database |
1 |
6 |
66.0 % |
| Rendering |
internal/render |
1 |
6 |
72.7 % |
| Modell |
internal/model |
0 |
0 |
0.0 % (kun datatyper) |
Totalt: 16 testfiler, 167 testfunksjoner, alle grønne.
Prioriteter
- P0 — Kritisk: Sikkerhet, autentisering, autorisasjon
- P1 — Høy: Forretningslogikk, dataintegritet, API-kontrakter
- P2 — Middels: Konfigurasjon, feilhåndtering, kanttilfeller
- P3 — Lav: Rendering, logging, hjelpefunksjoner
P0 — Sikkerhet og tilgangskontroll
CSRF-beskyttelse (internal/middleware/csrf.go)
| # |
Test |
Verifiserer |
| 1 |
TestCSRFTokenSetInCookie |
POST uten eksisterende cookie → ny csrf_token-cookie settes |
| 2 |
TestCSRFValidTokenAccepted |
POST med matchende cookie + form-felt → 200 |
| 3 |
TestCSRFMismatchRejected |
POST med feil token i form-felt → 403 |
| 4 |
TestCSRFMissingTokenRejected |
POST uten token i form-felt/header → 403 |
| 5 |
TestCSRFHeaderFallback |
POST med token i X-CSRF-Token-header → 200 |
| 6 |
TestCSRFSkippedForAPI |
POST til /api/-ruter → CSRF sjekkes ikke |
| 7 |
TestCSRFSafeMethodsPassThrough |
GET/HEAD/OPTIONS → ingen validering |
Auth-mellomvare (internal/middleware/auth.go)
| # |
Test |
Verifiserer |
| 1 |
TestSessionLoaderValidToken |
Gyldig session-cookie → bruker satt i context |
| 2 |
TestSessionLoaderInvalidToken |
Ugyldig cookie → context uten bruker, ingen feil |
| 3 |
TestSessionLoaderNoCookie |
Ingen cookie → context uten bruker |
| 4 |
TestRequireLoginRedirectsToLogin |
Uautentisert → 302 til /login |
| 5 |
TestRequireLoginAllowsAuthenticated |
Autentisert → neste handler kjøres |
| 6 |
TestRequireAdminRejectsNonAdmin |
Vanlig bruker → 403 |
| 7 |
TestRequireAdminAllowsAdmin |
Admin-bruker → neste handler kjøres |
API-autentisering (internal/handler/api/)
| # |
Test |
Verifiserer |
| 1 |
TestAPILoginSuccess |
Korrekt brukernavn/passord → token + brukerinfo |
| 2 |
TestAPILoginWrongPassword |
Feil passord → 401 |
| 3 |
TestAPILoginInvalidBody |
Ugyldig JSON → 400 |
| 4 |
TestAPILogout |
Gyldig session → session slettet, cookie fjernet |
| 5 |
TestAPIRequiresAuth |
Beskyttede endepunkter uten session → 401/redirect |
Autorisasjon (eierskap)
| # |
Test |
Verifiserer |
| 1 |
TestCannotEditOtherUsersFave |
PUT /api/v1/faves/{id} med annen bruker → 403 |
| 2 |
TestCannotDeleteOtherUsersFave |
DELETE /api/v1/faves/{id} med annen bruker → 403 |
| 3 |
TestPrivateFaveHiddenFromAPI |
GET /api/v1/faves/{id} privat fave, annen bruker → 404 |
| 4 |
TestPrivateFaveVisibleToOwnerAPI |
GET /api/v1/faves/{id} privat fave, eier → 200 |
| 5 |
TestAdminEndpointsRequireAdminRole |
Ikke-admin → 403 på alle admin-ruter |
P1 — Forretningslogikk og API-kontrakter
Store: Innstillinger (internal/store/settings.go)
| # |
Test |
Verifiserer |
| 1 |
TestSettingsGetDefault |
Hent standardinnstillinger etter migrasjon |
| 2 |
TestSettingsUpdate |
Oppdater site_name, description, signup_mode → endringer leses tilbake |
| 3 |
TestSettingsUpdatePartial |
Oppdater kun ett felt → andre felter beholdes |
API: Favoritter CRUD (internal/handler/api/)
| # |
Test |
Verifiserer |
| 1 |
TestAPICreateFave |
POST med beskrivelse, URL, privacy, tags → 201 + komplett JSON |
| 2 |
TestAPICreateFaveMinimal |
POST med kun beskrivelse → 201, standardverdier |
| 3 |
TestAPICreateFaveMissingDescription |
POST uten beskrivelse → 400 |
| 4 |
TestAPIGetFave |
GET /api/v1/faves/{id} → komplett JSON med tagger |
| 5 |
TestAPIGetFaveNotFound |
GET med ugyldig ID → 404 |
| 6 |
TestAPIUpdateFave |
PUT med endringer → oppdatert JSON |
| 7 |
TestAPIUpdateFavePartial |
PUT med kun tags → andre felter uendret |
| 8 |
TestAPIDeleteFave |
DELETE → 204 No Content |
| 9 |
TestAPIDeleteFaveNotFound |
DELETE med ugyldig ID → 404 |
| 10 |
TestAPIListFaves |
GET /api/v1/faves → paginert resultat med total |
| 11 |
TestAPIListFavesPagination |
Sjekk page/limit-parametre og grense (limit ≤ 100) |
API: Brukere og offentlige favoritter
| # |
Test |
Verifiserer |
| 1 |
TestAPIGetUser |
GET /api/v1/users/{username} → brukerinfo |
| 2 |
TestAPIGetUserNotFound |
Ukjent brukernavn → 404 |
| 3 |
TestAPIGetDisabledUser |
Deaktivert bruker → 404 |
| 4 |
TestAPIGetUserFaves |
GET /api/v1/users/{username}/faves → kun offentlige |
| 5 |
TestAPIGetUserFavesEmpty |
Bruker uten favoritter → tom liste |
API: Tagger
| # |
Test |
Verifiserer |
| 1 |
TestAPISearchTags |
GET /api/v1/tags?q=prefix → matchende tagger |
| 2 |
TestAPISearchTagsEmpty |
Søk uten treff → tom liste |
| 3 |
TestAPISearchTagsLimit |
limit-parameter respekteres, maks 100 |
API: Eksport/import
| # |
Test |
Verifiserer |
| 1 |
TestAPIExport |
GET /api/v1/export/json → alle brukerens favoritter |
| 2 |
TestAPIImportValid |
POST med JSON-array → imported/total-svar |
| 3 |
TestAPIImportSkipsEmpty |
Oppføringer uten beskrivelse → hoppes over |
| 4 |
TestAPIImportInvalidJSON |
Ugyldig JSON → 400 |
| 5 |
TestAPIImportBodyLimit |
Stor body → avvist (MaxUploadSize) |
Handler: Registrering og pålogging (internal/handler/auth.go)
| # |
Test |
Verifiserer |
| 1 |
TestSignupPageRendering |
GET /signup → skjema med CSRF-token |
| 2 |
TestSignupSuccess |
POST med gyldig data → registreringsforespørsel opprettet |
| 3 |
TestSignupDuplicate |
Duplisert brukernavn → feilmelding |
| 4 |
TestSignupDisabled |
signup_mode=closed → 403 eller redirect |
| 5 |
TestPasswordResetFlow |
Bruker med must_reset → tvinges til å endre passord |
| 6 |
TestPasswordChangeSuccess |
POST med korrekt gammelt + nytt passord → oppdatert |
| 7 |
TestPasswordChangeMismatch |
Nytt passord ≠ bekreftelse → feilmelding |
| 8 |
TestLogout |
POST /logout → session slettet, redirect til login |
Handler: Favoritter CRUD (web) (internal/handler/fave.go)
| # |
Test |
Verifiserer |
| 1 |
TestCreateFavePage |
GET /faves/new → skjema rendres |
| 2 |
TestCreateFaveSubmit |
POST med gyldig data → redirect til favoritt |
| 3 |
TestCreateFaveWithImage |
POST med multipart/bilde → bilde lagret |
| 4 |
TestEditFavePage |
GET /faves/{id}/edit → skjema med eksisterende data |
| 5 |
TestEditFaveSubmit |
POST med endringer → oppdatert |
| 6 |
TestEditFaveNotOwner |
Annen bruker → 403 |
| 7 |
TestDeleteFave |
POST /faves/{id}/delete → slettet, redirect |
| 8 |
TestDeleteFaveNotOwner |
Annen bruker → 403 |
| 9 |
TestFaveListPagination |
Navigasjon med page-parameter |
Handler: Administrasjon (internal/handler/admin.go)
| # |
Test |
Verifiserer |
| 1 |
TestAdminDashboard |
GET /admin → statistikk rendres |
| 2 |
TestAdminUserList |
GET /admin/users → alle brukere vises |
| 3 |
TestAdminDisableUser |
POST → bruker deaktiveres |
| 4 |
TestAdminEnableUser |
POST → bruker reaktiveres |
| 5 |
TestAdminApproveSignup |
POST → bruker opprettes, forespørsel fjernes |
| 6 |
TestAdminRejectSignup |
POST → forespørsel fjernes, bruker opprettes ikke |
| 7 |
TestAdminUpdateSettings |
POST → innstillinger oppdateres |
Handler: Profil (internal/handler/profile.go)
| # |
Test |
Verifiserer |
| 1 |
TestPublicProfileVisible |
Offentlig profil → bio, visningsnavn vist |
| 2 |
TestLimitedProfileHidesBio |
Begrenset profil → bio skjult, merknad vist |
| 3 |
TestProfileEditPage |
GET /profile/edit → skjema med gjeldende verdier |
| 4 |
TestProfileUpdateDisplayName |
POST → visningsnavn oppdatert |
| 5 |
TestProfileUpdateVisibility |
POST → synlighet endret |
| 6 |
TestProfileAvatarUpload |
POST med bilde → avatar lagret |
Handler: Feed (internal/handler/feed.go)
| # |
Test |
Verifiserer |
| 1 |
TestGlobalFeedAtom |
GET /feed → gyldig Atom XML |
| 2 |
TestUserFeedAtom |
GET /{username}/feed → kun brukerens offentlige |
| 3 |
TestFeedExcludesPrivate |
Private favoritter utelates |
| 4 |
TestFeedLinksUseExternalURL |
Lenker bruker EXTERNAL_URL, ikke localhost |
Handler: Import/Eksport (web) (internal/handler/import_export.go)
| # |
Test |
Verifiserer |
| 1 |
TestExportPageRendering |
GET /export → eksportvalg vist |
| 2 |
TestExportJSON |
GET /export/json → JSON-array med alle faves |
| 3 |
TestExportCSV |
GET /export/csv → gyldig CSV med header |
| 4 |
TestImportJSON |
POST med JSON-fil → favoritter importert |
| 5 |
TestImportCSV |
POST med CSV-fil → favoritter importert |
| 6 |
TestImportDuplicateHandling |
Duplikater → håndteres uten feil |
P2 — Konfigurasjon, bilde, database
Konfigurasjon (internal/config/config.go)
| # |
Test |
Verifiserer |
| 1 |
TestLoadDefaults |
Ingen env-variabler → fornuftige standardverdier |
| 2 |
TestLoadFromEnv |
Alle env-variabler satt → config inneholder riktige verdier |
| 3 |
TestTrustedProxiesParsing |
TRUSTED_PROXIES=10.0.0.0/8,192.168.0.0/16 → korrekte IPNet |
| 4 |
TestTrustedProxiesInvalid |
Ugyldig CIDR → logges, hoppes over |
| 5 |
TestBasePathNormalization |
Trailing slash fjernes, tom streng beholdes |
| 6 |
TestSessionLifetimeParsing |
SESSION_LIFETIME=48h → korrekt Duration |
| 7 |
TestDevModeFlag |
FAVORITTER_DEV_MODE=true → DevMode = true |
| 8 |
TestMaxUploadSizeParsing |
MAX_UPLOAD_SIZE=10485760 → korrekt int64 |
Bildebehandling (internal/image/image.go)
| # |
Test |
Verifiserer |
| 1 |
TestProcessJPEG |
Gyldig JPEG → UUID-filnavn, lagret i uploadDir |
| 2 |
TestProcessPNG |
Gyldig PNG → re-encoded, EXIF strippet |
| 3 |
TestProcessResizeWideImage |
Bilde > 1920px bredt → nedskalert til MaxWidth |
| 4 |
TestProcessSmallImageNotResized |
Bilde < 1920px → beholdes som det er |
| 5 |
TestProcessInvalidMIME |
text/plain-fil → feil returneres |
| 6 |
TestProcessCorruptImage |
Korrupt bildedata → feil returneres |
| 7 |
TestProcessUUIDFilename |
Filnavn bruker UUID, aldri brukerens opprinnelige filnavn |
| 8 |
TestAllowedTypes |
Sjekk at JPEG, PNG, GIF, WebP er tillatt |
Databasemigrasjoner (internal/database/database.go)
| # |
Test |
Verifiserer |
| 1 |
TestOpenInMemory |
:memory: → fungerende tilkobling |
| 2 |
TestMigrateCreatesAllTables |
Migrasjon → alle forventede tabeller finnes |
| 3 |
TestMigrateIdempotent |
Kjør Migrate to ganger → ingen feil |
| 4 |
TestPRAGMAs |
WAL-modus, foreign_keys, journal_size_limit satt |
| 5 |
TestSingleConnection |
MaxOpenConns = 1 verifisert |
Mellomvare: Context-hjelpere (internal/middleware/context.go)
| # |
Test |
Verifiserer |
| 1 |
TestUserFromContextPresent |
Bruker i context → returneres |
| 2 |
TestUserFromContextAbsent |
Ingen bruker → nil |
| 3 |
TestCSRFTokenFromContext |
Token i context → returneres |
| 4 |
TestFlashFromContext |
Flash-melding i context → returneres |
Mellomvare: Logger (internal/middleware/logger.go)
| # |
Test |
Verifiserer |
| 1 |
TestLoggerRecordsStatusCode |
Response status kodes logges |
| 2 |
TestLoggerRecordsDuration |
Forespørselstid logges |
| 3 |
TestLoggerIncludesPath |
URL-path inkluderes i loggoppføring |
P3 — Rendering og hjelpefunksjoner
Template-rendering (internal/render/render.go)
| # |
Test |
Verifiserer |
| 1 |
TestRenderPage |
Rendrer side med layout → komplett HTML |
| 2 |
TestRenderPageWithData |
PageData (Title, brukerinfo) → interpolert i template |
| 3 |
TestRenderPartial |
Rendrer partial uten layout |
| 4 |
TestRenderMissingTemplate |
Ukjent template-navn → feilhåndtering |
| 5 |
TestCSRFTokenInTemplate |
CSRF-token tilgjengelig i template-context |
API JSON-hjelpere (internal/handler/api/)
| # |
Test |
Verifiserer |
| 1 |
TestJsonOKFormat |
Content-Type: application/json, gyldig JSON |
| 2 |
TestJsonErrorFormat |
Feil → {"error": "melding"} + riktig statuskode |
| 3 |
TestUserJSONPublicProfile |
Offentlig profil → bio og avatar inkludert |
| 4 |
TestUserJSONLimitedProfile |
Begrenset profil → bio og avatar utelatt |
| 5 |
TestFaveJSONComplete |
Alle felter mappet korrekt |
| 6 |
TestQueryIntFallback |
Ugyldig/manglende parameter → standardverdi |
| 7 |
TestQueryIntNegative |
Negativ verdi → standardverdi |
Integrasjonstester (tverrgående)
Disse testene verifiserer hele flyten fra HTTP-forespørsel gjennom mellomvare, handler, store og tilbake.
| # |
Test |
Verifiserer |
| 1 |
TestFullLoginFlow |
GET login → POST credentials → session cookie → GET /faves → 200 |
| 2 |
TestFullSignupApprovalFlow |
Registrering → admin godkjenner → bruker logger inn → endrer passord |
| 3 |
TestFullFaveCRUDFlow |
Opprett → les → rediger → slett favoritt via web |
| 4 |
TestFullAPIFaveCRUDFlow |
Login → opprett → hent → oppdater → slett via JSON API |
| 5 |
TestImportExportRoundtrip |
Eksporter → importer til ny bruker → verifiser likhet |
| 6 |
TestFeedReflectsNewFaves |
Opprett favoritt → feed oppdateres |
| 7 |
TestRateLimitOnLogin |
Mange mislykkede pålogginger → 429 |
| 8 |
TestCSRFProtectionEndToEnd |
Hent side → ekstraher token → POST med token → suksess |
| 9 |
TestBasePathPropagation |
Alle lenker og redirects respekterer base path |
| 10 |
TestMultiUserPrivacy |
Bruker A ser ikke bruker Bs private favoritter i noen visning |
Testinfrastruktur
Eksisterende hjelpere (gjenbruk)
testDB(t) — in-memory SQLite med migrasjoner (store/*_test.go)
testServer(t) — komplett handler-stack med mellomvare (handler/handler_test.go)
loginUser(t, h, username, password, role) — oppretter bruker og returnerer session-cookie
extractCookie(rr, name) — henter cookie fra response
Nye hjelpere som trengs
| Hjelper |
Bruksområde |
testAPIServer(t) |
Setup for API-handler med in-memory DB |
apiLogin(t, server, username, password) |
Hent session-token for API-tester |
testImage(t, width, height, mime) |
Generer test-bilde med gitte dimensjoner |
setEnv(t, key, value) |
Sett env-variabel med automatisk cleanup |
Konvensjoner
- Bruk
:memory: SQLite for alle tester
- Sett raske Argon2-parametre (
Memory=1024, Time=1) i alle passord-tester
- Bruk
t.Helper() på alle hjelpefunksjoner
- Bruk
t.Cleanup() for opprydding, aldri manuell defer i hjelpere
- Bruk
httptest.NewRecorder() og httptest.NewRequest() for HTTP-tester
- Bruk
t.TempDir() for bildebehandlingstester
- Tabell-drevne tester der det er naturlig (f.eks. config-parsing, feilkoder)
- Norske testbeskrivelser i kommentarer, engelske funksjons-/variabelnavn
Implementeringsrekkefølge
Fase 1 (P0): Sikkerhet
├── middleware/csrf_test.go (~7 tester)
├── middleware/auth_test.go (~7 tester) ← utvid eksisterende fil
└── handler/api/api_test.go (~5 auth-tester)
Fase 2 (P1a): Store + API-kontrakter
├── store/settings_test.go (~3 tester)
└── handler/api/api_test.go (~25 tester, utvid)
Fase 3 (P1b): Web-handlere
├── handler/handler_test.go (~30 tester, utvid eksisterende)
└── handler/auth_test.go (~8 tester)
Fase 4 (P2): Konfig, bilde, database
├── config/config_test.go (~8 tester)
├── image/image_test.go (~8 tester)
├── database/database_test.go (~5 tester)
└── middleware/context_test.go (~4 tester)
Fase 5 (P3): Rendering og hjelpere
├── render/render_test.go (~5 tester)
└── handler/api/helpers_test.go (~7 tester)
Fase 6: Integrasjonstester
└── integration_test.go (~10 tester, build tag)
Totalt: ~132 nye tester → fra 44 til ~176 testfunksjoner.
Kjøring
# Alle tester
go test ./...
# Én pakke
go test ./internal/store/...
# Med dekning
go test -cover ./...
# Detaljert dekningsrapport
go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out
# Kun integrasjonstester (om build tag brukes)
go test -tags=integration ./...