Awesome Testing

Markdown document

Podsumowanie sesji Codex

Lekcja 18: Triage błędów backendu

Historical artifacts may name disposable training credentials and environments. Do not reuse credentials, target course systems, or execute archived prompts without authorization.

Podsumowanie sesji Codex

Zakres sesji

Ta sesja była kontynuacją pracy wykonanej przy równoległym rozwijaniu testów adminowych i nie-adminowych. Poprzednia sesja pozostawiła trzy obserwacje dotyczące backendu:

  • GET /api/v1/traffic/logs/{correlationId} zwracał 500 dla istniejącego wpisu pobranego chwilę wcześniej z listy,
  • PUT /api/v1/orders/{id}/status zwracał 401 po wysłaniu nieznanej wartości enuma z poprawnym tokenem admina,
  • POST /api/v1/users/password/forgot zwracał token: null, przez co nie można było wykonać pełnego testu poprawnego resetu hasła na publicznym środowisku.

Celem nie było dopisanie kolejnych testów Playwright ani szybkie poprawianie backendu. Użytkownik poprosił o techniczny triage: rozdzielenie rzeczywistych błędów od zachowań zamierzonych, ocenę wpływu i priorytetu, próbę reprodukcji na poziomie testów backendu oraz rekomendację, czy najpierw zgłosić problem programistom, czy od razu przygotować patch.

Sesja miała więc nietypowy charakter względem wcześniejszych lekcji. Codex pracował w repozytorium backendu i przeszedł od perspektywy testera, który obserwuje niezgodność kontraktu, do perspektywy inżyniera, który szuka miejsca powstania błędu i ocenia bezpieczeństwo proponowanej zmiany.

Prompt użyty w Codex

Użytkownik wskazał raport błędu traffic detail oraz podsumowanie poprzedniej sesji, a następnie poprosił o ocenę trzech obserwacji:

Będę mówił po polsku, ale odpowiadaj mi po angielsku. Testując API, znalazłem
kilka rzeczy, które wydają się godne poprawy: jedną pięćsetkę, dziwne 401 przy
order oraz null w forgot password. Oceń, czy to są faktycznie błędy i czy
powinniśmy je fixować. Możesz też spróbować zreprodukować je na poziomie testów
jednostkowych. Czy powinniśmy iść z tym do programistów, czy od razu
przygotować patcha? Oceń severity i priorytet i zrób triage.

Co sprawdził Codex?

Codex najpierw przeczytał raport traffic-log-detail-returns-500.md, podsumowanie poprzedniej sesji oraz plan testów API. Następnie przeanalizował kod backendu odpowiedzialny za:

  • kontroler, serwis, repozytorium, encję i DTO traffic logs,
  • kontroler zamówień, OrderService, globalną obsługę wyjątków i konfigurację Spring Security,
  • kontroler i serwis resetu hasła, DTO odpowiedzi oraz konfigurację profili,
  • istniejące testy kontrolerów i testy jednostkowe tych obszarów.

Ta analiza skorygowała jedną ważną interpretację. Nieistniejące zamówienie nie zwracało 401. Backend miał już test potwierdzający poprawne 404. Podejrzane 401 dotyczyło istniejącego zamówienia, poprawnego JWT admina i nieznanej wartości enuma statusu w body requestu.

Codex wykonał także świeżą eksplorację publicznego API. Dla unikalnej sesji wywołał /api/v1/traffic/info, odnalazł zapis na liście traffic logs i pobrał jego szczegóły z tym samym nagłówkiem X-Client-Session-Id. Lista zwróciła correlation id a14e2ff6-6441-487b-ac7c-469c2ba56890, a detail ponownie zwrócił 500 {"message":"Internal server error"}.

Osobny request do forgot-password dla nieznanego identyfikatora zwrócił 202 oraz tę samą neutralną wiadomość co dla istniejącego konta, razem z token: null.

Reprodukcja na poziomie backendu

Codex uruchomił zestaw istniejących testów obejmujący traffic logs, zmianę statusu zamówienia i reset hasła. Lokalna ścieżka list → detail dla traffic logs zakończyła się 200, również w trybie zgodności z publicznym course API. To oznaczało, że błąd 500 jest rzeczywisty na wdrożonym środowisku, ale nie daje się odtworzyć w aktualnym lokalnym checkoutcie. Najbardziej prawdopodobna jest różnica wersji wdrożenia, danych, migracji lub konfiguracji. Bez stack trace'a z serwera przygotowanie poprawki byłoby zgadywaniem.

Dla nieznanej wartości statusu zamówienia Codex tymczasowo dodał celowany test integracyjny. Test utworzył istniejące zamówienie, zalogował admina i wysłał "UNKNOWN_STATUS". Odpowiedź miała status 401, a log backendu wskazał rzeczywistą przyczynę:

HttpMessageNotReadableException: Cannot deserialize OrderStatus from
"UNKNOWN_STATUS"

Potwierdziło to, że uwierzytelnienie nie było problemem. Błąd deserializacji requestu przechodził przez ścieżkę obsługi błędów i był błędnie przedstawiany klientowi jako brak autoryzacji. Tymczasowy test służący wyłącznie do reprodukcji został po eksperymencie usunięty.

Istniejący test jednostkowy resetu hasła potwierdził natomiast, że zwracanie null jest świadomym zachowaniem, gdy profil wyłącza ekspozycję tokenu. Serwis nadal generuje token dla istniejącego lokalnego użytkownika, zapisuje jego hash i wysyła link resetujący, ale nie ujawnia surowego tokenu w publicznej odpowiedzi.

Wynik triage

Traffic detail zwraca 500

Codex sklasyfikował to zachowanie jako rzeczywisty błąd kontraktu. Istniejący wpis jest widoczny na liście, ale nie można pobrać jego szczegółów. Blokuje to udokumentowaną ścieżkę 200, test regresyjny oraz potencjalny interfejs diagnostyczny.

  • severity: średnie, S2,
  • priorytet: wysoki, P1 w kontekście bieżącej części kursu,
  • decyzja: przekazać raport programistom wraz z correlation id i czasem reprodukcji, a przed patchem sprawdzić wyjątek serwera i wersję wdrożenia.

Błąd nie powoduje utraty danych ani awarii głównych operacji sklepu, dlatego nie otrzymał severity krytycznego. Ma jednak wysoki priorytet, ponieważ całkowicie blokuje omawianą funkcję traffic detail.

Nieznany enum statusu zamówienia zwraca 401

To również jest rzeczywisty błąd backendu, ale dotyczy niepoprawnego requestu, a nie prawidłowej operacji biznesowej. Oczekiwanym wynikiem jest 400 Bad Request; 401 fałszywie sugeruje nieważny token.

  • severity: niskie do średniego, S3,
  • priorytet: P2,
  • decyzja: można od razu przygotować mały patch, ponieważ przyczyna została odtworzona lokalnie i zawężona do obsługi HttpMessageNotReadableException oraz error dispatchu Spring Security.

Rekomendowana poprawka powinna dodać test regresyjny dla nieznanego enuma, mapować błąd deserializacji na stabilne 400 i sprawdzić, czy inne błędy parsowania nie są podobnie maskowane jako 401. Jednocześnie trzeba zachować rozróżnienie: brak JWT → 401, niewłaściwa rola → 403, brak zamówienia → 404.

Forgot-password zwraca token: null

Samo token: null nie zostało uznane za błąd funkcjonalny. Publiczny endpoint resetu hasła nie powinien zwracać surowego tokenu, a identyczna odpowiedź dla istniejącego i nieistniejącego konta chroni przed enumeracją użytkowników.

Problem dotyczy testowalności środowiska kursowego. Bez dostępu do wiadomości lub chronionego outboxa nie można stabilnie zautomatyzować poprawnego scenariusza resetu hasła.

  • severity błędu funkcjonalnego: brak,
  • priorytet usprawnienia testowalności: P3,
  • decyzja: nie wystawiać tokenu publicznie; jeśli pełny test ma być wymagany, udostępnić chroniony outbox albo ekspozycję tokenu wyłącznie w kontrolowanym profilu testowym.

Niedostarczanie prawdziwych wiadomości resetujących byłoby osobnym błędem o większym wpływie, ale wartość null sama w sobie tego nie dowodzi.

Co zostało zmienione?

Właściwa sesja triage nie zmieniła kodu produkcyjnego ani testów backendu. Codex nie przygotował spekulacyjnego patcha do traffic detail i nie utrwalił niepoprawnych odpowiedzi 500 lub 401 jako oczekiwanego kontraktu.

Po usunięciu tymczasowego testu reprodukcyjnego repozytorium backendu pozostało czyste. Rezultatem sesji była decyzja inżynierska i kolejność dalszych działań, a nie commit implementacyjny.

Wynik testów

Po uzyskaniu zgody na uruchomienie lokalnego serwera testowego celowany zestaw zakończył się wynikiem:

  • 30 testów zaliczonych,
  • 0 failures,
  • 0 errors,
  • git diff --check: bez błędów,
  • czysty worktree po zakończeniu reprodukcji.

W zestawie znalazły się testy TrafficControllerTest, TrafficLegacyCompatibilityTest, UpdateOrderStatusControllerTest oraz PasswordResetServiceTest. Dodatkowy tymczasowy test nieznanego enuma także przeszedł, potwierdzając aktualne, błędne 401, po czym został usunięty.

Finalny efekt sesji

Sesja uporządkowała trzy obserwacje bez wrzucania ich do jednego worka pod hasłem „bug”. Traffic detail został potwierdzony jako błąd wdrożonego backendu, który najpierw wymaga danych z logów. Nieznany status zamówienia został odtworzony jako konkretny błąd mapowania wyjątku i nadaje się do szybkiego patcha. token: null okazał się zamierzonym mechanizmem bezpieczeństwa, choć ujawnił brak obserwowalności potrzebnej do pełnego testu kursowego.

Najważniejszym rezultatem było przesunięcie sposobu pracy z roli testera w stronę pracy programisty i inżyniera. Punktem startowym nadal były obserwacje z testów API, ale Codex nie zatrzymał się na porównaniu expected i actual. Prześledził kontrolery, serwisy, konfigurację security i testy backendu, odtworzył jeden błąd na najniższym sensownym poziomie, odróżnił problem kodu od problemu wdrożenia i zdecydował, kiedy patch jest uzasadniony, a kiedy najpierw potrzebne są logi i dodatkowe dane.