iOS-Cookies prüfen: getrennte Sitzungen und sauberes Abmelden

iOS-Cookies prüfen: getrennte Sitzungen und sauberes Abmelden

iOS-Cookies prüfen: getrennte Sitzungen und sauberes Abmelden

Wenn bei Regressionstests zum Kontowechsel auf demselben Cloud-Mac nach der Anmeldung mit Konto B noch Daten von Konto A ankommen, sollte der Simulator nicht vorschnell zurückgesetzt werden. Prüfen Sie Cookie-Speicher, Request-Header und noch laufende Tasks getrennt voneinander: Die alte Sitzung kann aus einem gemeinsam genutzten Speicher stammen, aus einem manuell gesetzten Header in der Netzwerkschicht oder sogar aus einer Antwort, die erst nach dem Abmelden eintrifft.

Zunächst prüfen wir das Verhalten ohne Netzwerkzugriffe mit dem integrierten Netzwerk-Framework von macOS. Anschließend kommen dieselben Prüfkriterien im iOS-Simulator zum Einsatz. Legen Sie den Prüfcode im Repository ab, damit er nach jedem Checkout auf dem Cloud-Mac reproduzierbar ausgeführt werden kann, ohne vom Zustand der letzten grafischen Sitzung abzuhängen.

Eigentümerschaft der Sitzungsdaten festlegen

Erstellen Sie für jedes angemeldete Konto ein eigenes Sitzungsobjekt, das Konfiguration, Cookie-Speicher und die zugehörigen Tasks verwaltet. Verwenden Sie keine veränderbare Konfiguration als globalen Singleton. Erwarten Sie auch nicht, dass Änderungen an der ursprünglichen Konfiguration eine bereits erstellte URLSession beeinflussen: Beim Erstellen der Sitzung wird die Konfiguration kopiert.

Halten Sie mindestens drei Bedingungen fest: Cookies von Konto A dürfen nicht in Requests von Konto B gelangen; beim Abmelden dürfen nur Daten des aktuellen Kontos gelöscht werden; alte Antworten dürfen nach dem Abmelden den angemeldeten Zustand nicht wiederherstellen. Benötigen anonyme Requests überhaupt keine Cookies, deaktivieren Sie die automatische Cookie-Verarbeitung und prüfen Sie zusätzlich, dass die Netzwerkschicht keinen Cookie-Header manuell setzt.

ephemeral bedeutet, dass Sitzungsdaten nicht dauerhaft auf der Festplatte gespeichert werden. Es bedeutet weder, dass im Arbeitsspeicher keine Cookies vorhanden sind, noch, dass zwei Anwendungskonten automatisch voneinander isoliert sind.

Unabhängige Speicher per Skript prüfen

Speichern Sie den folgenden Inhalt als cookie-check.swift. Das Skript verwendet ausschließlich fiktive Sitzungswerte und die lokale Domain localhost. Es sendet keine Netzwerkanfragen und greift nicht auf den standardmäßigen gemeinsamen Speicher zu.

import Foundation

func require(_ condition: Bool, _ message: String) {
    if !condition {
        fatalError(message)
    }
}

func makeCookie(_ value: String) -> HTTPCookie {
    HTTPCookie(properties: [
        .domain: "localhost",
        .path: "/",
        .name: "session",
        .value: value
    ])!
}

let first = URLSessionConfiguration.ephemeral
let second = URLSessionConfiguration.ephemeral

guard let a = first.httpCookieStorage,
      let b = second.httpCookieStorage else {
    fatalError("Cookie storage unavailable")
}

require(a !== b, "Stores must be independent")

let target = URL(string: "http://localhost/account")!
a.setCookie(makeCookie("fixture-a"))
b.setCookie(makeCookie("fixture-b"))

func values(_ store: HTTPCookieStorage) -> [String] {
    (store.cookies(for: target) ?? [])
        .filter { $0.name == "session" }
        .map(\.value)
        .sorted()
}

require(values(a) == ["fixture-a"], "Account A mismatch")
require(values(b) == ["fixture-b"], "Account B mismatch")

for cookie in a.cookies ?? [] {
    a.deleteCookie(cookie)
}

require(values(a).isEmpty, "Account A was not cleared")
require(values(b) == ["fixture-b"], "Account B was affected")

Führen Sie auf einem Rechner, auf dem die Kommandozeilenwerkzeuge bereits initialisiert wurden, Folgendes aus:

set -eu
xcrun swift cookie-check.swift

Bei erfolgreicher Prüfung gibt es keine Ausgabe. Schlägt eine Assertion fehl, endet der Prozess mit einem Exit-Status ungleich null. Hier wird der gesamte Speicher a geleert. Das ist nur zulässig, weil er ausschließlich Konto A gehört. Verwendet die Anwendung weiterhin einen gemeinsamen Speicher, müssen die Cookies zunächst nach ihrer fachlichen Kontozuordnung gefiltert werden; die vollständige Löschung darf dann nicht unverändert übernommen werden.

Das Skript weist die Unabhängigkeit der Speicher und den Umfang der Löschung nach. Es beweist nicht, dass echte Requests bereits korrekt angebunden sind. Eine erfolgreiche Prüfung auf dieser Ebene ersetzt daher nicht die Abnahme der Netzwerkschicht.

Echte Requests und Antworten einbinden

Verwenden Sie im Test-Target der Anwendung den tatsächlichen Netzwerkclient und erstellen Sie separate Sitzungen für Konto A und Konto B. Lassen Sie einen kontrollierbaren Testdienst per Set-Cookie Cookies mit gleichem Namen, aber unterschiedlichen Werten zurückgeben. Rufen Sie anschließend einen Echo-Endpunkt auf und prüfen Sie, ob der Server für jedes Konto die jeweils zugehörigen Cookies erhält.

Die Requests müssen durch die Netzwerkschicht der Anwendung laufen; Interceptoren dürfen für den Test nicht umgangen werden. Prüfen Sie besonders, ob Standard-Header, Retry-Logik oder die Verarbeitung von Weiterleitungen erneut auf den gemeinsamen Speicher zugreifen. Setzen Sie bei der Prüfung des automatischen Cookie-Verhaltens auch keine Header von Hand, da dies Fehler in der zugrunde liegenden Anbindung verdecken kann.

Ergänzen Sie Testfälle für Path, Secure und Ablaufzeiten: Ein Cookie mit eng begrenztem Pfad darf nicht bei Requests an andere Pfade erscheinen; abgelaufene Cookies dürfen nicht weiter gesendet werden; sichere Cookies müssen in einer kontrollierten HTTPS-Umgebung geprüft werden. Eine lokale HTTP-Test-Fixture kann die Semantik sicherer Verbindungen nicht nachweisen.

Gleichnamige Cookies können gleichzeitig existieren, wenn sie sich in Domain und Pfad unterscheiden. Assertions sollten deshalb Mengen aus Name, Domain, Pfad und Wert vergleichen, statt anzunehmen, dass im Speicher immer nur ein einziges session-Cookie liegt. Treffen Sie auch keine überzogenen Annahmen über die Sortierung im Header-String. Parsen Sie ihn und vergleichen Sie die semantischen Inhalte.

Beim Abmelden verspätete Antworten berücksichtigen

Versetzen Sie das Konto zuerst in den Zustand „Abmeldung läuft“ und verhindern Sie das Erstellen neuer Tasks. Brechen Sie anschließend alte Tasks ab oder lassen Sie sie vollständig auslaufen. Löschen Sie danach die Cookies dieses Kontos, invalidieren Sie die alte Sitzung und erstellen Sie für die nächste Anmeldung ein neues Objekt.

Bloßes Löschen führt zu einer Race Condition: Ein alter Request kann später noch eine Antwort mit Set-Cookie erhalten und damit erneut in den alten Speicher schreiben. Auch das Abbrechen ist keine synchrone Barriere, denn Callbacks können bereits in der Warteschlange liegen. Vergeben Sie deshalb bei jeder Anmeldung eine Sitzungsgeneration. Prüfen Sie diese vor der Verarbeitung einer Antwort; Antworten aus einer alten Generation dürfen den aktuellen Benutzerzustand nicht aktualisieren.

Verzögern Sie im Test die Antwort für Konto A, lösen Sie die Abmeldung aus und melden Sie Konto B an. Geben Sie erst danach die Antwort für Konto A frei. Prüfen Sie abschließend sowohl den UI-Zustand von Konto B als auch die fachliche Benutzeridentität und die Cookies des nächsten Requests. Wer nur prüft, ob der Speicher im Moment der Abmeldung leer ist, erkennt diese Fehlerklasse nicht.

Die Abnahme in zwei Teststufen aufteilen

Führen Sie bei jedem Merge zuerst das Speicherskript ohne Netzwerkzugriffe aus. Danach folgen auf einem festgelegten Simulator die Tests für Request-Echos und verspätete Antworten. Jeder Test erstellt seine eigene Konfiguration und seine eigenen Fixtures. Stoppen Sie am Ende die Dienste und brechen Sie die Tasks ab. Teilen Sie keine veränderbaren Sitzungen zwischen Tests, damit sich parallel ausgeführte Tests nicht gegenseitig beeinflussen.

Halten Sie bei Fehlern Request-ID, Sitzungsgeneration sowie Cookie-Namen und -Attribute fest, aber keine echten Cookie-Werte. Wenn Werte verglichen werden müssen, verwenden Sie feste Kennungen aus den Test-Fixtures. Kopieren Sie keinen Anmeldestatus aus der Produktion auf den Cloud-Mac.

Lassen Sie zum Schluss absichtlich beide Konten denselben Speicher verwenden und vergewissern Sie sich, dass der Test fehlschlägt. Entfernen Sie danach gezielt die Prüfung der Sitzungsgeneration und stellen Sie sicher, dass der Test die verspätete Antwort als Fehler erkennt. Erst wenn beide Regressionen zuverlässig erkannt werden, prüft das Test-Gate tatsächlich die Kontogrenzen – und nicht nur einige Assertions, die zufällig erfolgreich sind.

Häufig gestellte Fragen

Verhindert eine ephemere Konfiguration jeden Cookie-Übertrag?

Nein. Auch ephemere Sitzungen speichern Cookies im Arbeitsspeicher. Erstellen Sie unabhängige Konfigurationen und prüfen Sie, ob die Netzwerkschicht gemeinsame Speicher oder eigene Cookie-Header einsetzt.

Reicht reset beim Abmelden?

Nein. Sperren Sie neue Requests, beenden Sie alte Aufgaben und löschen Sie anschließend die Cookies des Kontos. reset betrifft zusätzlich Cache und Zugangsdaten und ersetzt keinen geordneten Logout.

Der nächste Build auf einem exklusiven Mac.

Wählen Sie einen Cloud-Mac ohne Virtualisierung und behalten Sie Ihren gewohnten Xcode- und CI-Workflow bei. Konfigurieren Sie die Maschine passend zu Ihrer Arbeitslast; den aktuellen Verfügbarkeitsstatus sehen Sie live in der Konsole.

Cloud-Mac jetzt mieten

Den nächsten Build auf einer exklusiven physischen Maschine ausführen.

Behalten Sie Ihre gewohnten Befehle und CI-Abläufe bei und wählen Sie einen Cloud-Mac passend zu Ihrer Arbeitslast.