31. Web-Clients für die JSON- und XML-Dienste der Version 12
Wir werden drei Konsolen-Client-Anwendungen für die JSON- und XML-Dienste des soeben erstellten Webservers schreiben. Wir werden die Client/Server-Architektur aus Version 11 wiederverwenden:

Wir werden drei Konsolenskripte schreiben:
- Die Skripte [main] und [main3] nutzen die [business]-Schicht des Servers;
- das Skript [main2] nutzt die [business]-Schicht des Clients;
31.1. Die Verzeichnisstruktur der Client-Skripte
Der Ordner [http-clients/07] wird zunächst durch Kopieren des Ordners [http-clients/06] erstellt. Anschließend wird er geändert.

- in [1]: vom Client verwendete oder erstellte Daten;
- in [2] die Konfigurations- und Konsolenskripte des Clients;
- in [3] die [dao]-Schicht des Clients;
- in [4] der Testordner für die [dao]-Schicht des Clients;
31.2. Die [dao]-Ebene des Clients


31.2.1. Schnittstelle
Die [dao]-Schicht wird die folgende [InterfaceImpôtsDaoWithHttpSession]-Schnittstelle implementieren:
Jede Methode der Schnittstelle entspricht einer Service-URL auf dem Steuerberechnungsserver.
- Zeile 7: Die Schnittstelle erweitert die Klasse [AbstractDao], die den Zugriff auf das Dateisystem verwaltet;
Die Zuordnung zwischen Methoden und Service-URLs wird in der Konfigurationsdatei [config] definiert:
# le serveur de calcul de l'impôt
"server": {
"urlServer": "http://127.0.0.1:5000",
"user": {
"login": "admin",
"password": "admin"
},
"url_services": {
"calculate-tax": "/calculer-impot",
"get-admindata": "/get-admindata",
"calculate-tax-in-bulk-mode": "/calculer-impots",
"init-session": "/init-session",
"end-session": "/fin-session",
"authenticate-user": "/authentifier-utilisateur",
"get-simulations": "/lister-simulations",
"delete-simulation": "/supprimer-simulation"
}
31.2.2. Implementierung
Die Schnittstelle [InterfaceImpôtsDaoWithHttpSession] wird durch die folgende Klasse [ImpôtsDaoWithHttpSession] implementiert:
- Zeilen 16–34: der Klassenkonstruktor;
- Zeile 19: Die übergeordnete Klasse wird initialisiert;
- Zeilen 21–28: Bestimmte Konfigurationsdaten werden gespeichert;
- Zeilen 29–34: Es werden drei Eigenschaften erstellt, die in den Methoden der Klasse verwendet werden;
- Zeilen 36–82: Die Methode [get_response] fasst die allen Methoden der [dao]-Schicht gemeinsamen Elemente zusammen: das Senden einer HTTP-Anfrage und das Abrufen der HTTP-Antwort vom Server;
- Zeilen 38–42: Definition der 5 Parameter der Methode [get_response];
- Zeile 42: Beachten Sie, dass der Client Cookies lesen/senden muss, da der Server eine Sitzung aufrechterhält;
- Zeilen 44–46: Wir überprüfen, ob tatsächlich eine gültige aktive Sitzung vorliegt;
- Zeile 51: GET-Fall. Die empfangenen Cookies werden zurückgesendet;
- Zeile 54: POST-Fall. Dieser kann zwei Arten von Parametern haben:
- den Typ [x-www-form-urlencoded]. Dies ist bei den URLs [/calculate-tax] und [/authenticate-user] der Fall. Wir verwenden dann den von der Methode empfangenen Parameter [data_value];
- den Typ [json]. Dies ist bei der URL [/calculate-taxes] der Fall. Wir verwenden dann den von der Methode empfangenen Parameter [json_value];
Auch hier wird das Session-Cookie zurückgegeben.
- Zeilen 56–62: Im [debug]-Modus wird die Antwort des Servers protokolliert. Dieses Protokoll ist wichtig, da es uns ermöglicht, genau zu wissen, was der Server zurückgegeben hat;
- Zeilen 64–68: Je nachdem, ob wir uns im JSON- oder XML-Modus befinden, wird die Textantwort des Servers in ein Dictionary konvertiert. Nehmen wir das Beispiel der URL [/init-session]:
Die JSON-Antwort lautet wie folgt:
2020-08-03 11:45:21.218116, MainThread : {"action": "init-session", "état": 700, "réponse": ["session démarrée avec le type de réponse json"]}
Die XML-Antwort lautet wie folgt:
2020-08-03 11:45:54.671871, MainThread : <?xml version="1.0" encoding="utf-8"?>
<root><action>init-session</action><état>700</état><réponse>session démarrée avec le type de réponse xml</réponse></root>
Der Code in den Zeilen 64–68 stellt sicher, dass [result] in beiden Fällen ein Wörterbuch mit den Schlüsseln [action, status, response] enthält;
- Zeilen 70–72: Wenn die Antwort Cookies enthält, werden diese abgerufen. Diese müssen mit der nächsten Anfrage zurückgesendet werden;
- Zeilen 74–79: Wenn der HTTP-Status der Antwort nicht 200 ist, wird eine Ausnahme mit der in result[‘response’] enthaltenen Fehlermeldung ausgelöst. Dies kann ein einzelner Fehler oder eine Liste von Fehlern sein;
- Zeilen 81–82: Die Antwort des Servers wird an den aufrufenden Code zurückgegeben;
[init_session]
- Zeile 84: Die Methode [init_session] wird verwendet, um den Sitzungstyp (JSON oder XML) festzulegen, den der Client mit dem Server starten möchte;
- Zeile 86: Der gewünschte Sitzungstyp wird in der Klasse gespeichert. Tatsächlich benötigen alle Methoden diese Information, um die Antwort des Servers korrekt zu dekodieren;
- Zeilen 88–90: Anhand der Anwendungskonfiguration wird die abzufragende Service-URL ermittelt;
- Zeile 93: Die Service-URL wird abgefragt. Das Ergebnis der Methode [get_response] wird nicht abgerufen:
- Wenn eine Ausnahme ausgelöst wird, ist der Vorgang fehlgeschlagen. Die Ausnahme wird hier nicht behandelt und direkt an den aufrufenden Code weitergeleitet, der den Client dann mit einer Fehlermeldung beendet;
- Wenn keine Ausnahme ausgelöst wird, war die Initialisierung der Sitzung erfolgreich;
[authenticate_user]
- Die Methode [authenticate_user] dient zur Authentifizierung beim Server. Dazu empfängt sie in Zeile 1 die Anmeldedaten [user, password];
- Zeilen 2–4: Wir legen die URL des abzufragenden Dienstes fest;
- Zeilen 5–8: die POST-Parameter, da die URL [/authenticate-user] eine POST-Anfrage mit den Parametern [user, password] erwartet;
- Zeile 11: Die Anfrage wird ausgeführt. Auch hier rufen wir die Antwort des Servers nicht ab. Es ist die von [get_response] ausgelöste Ausnahme, die angibt, ob der Vorgang erfolgreich war oder nicht;
[calculate_tax]
- Die Methode [calculate_tax] berechnet die Steuer für einen als Parameter übergebenen Steuerzahler [taxpayer]. Dieser Parameter wird durch die Methode geändert (Zeile 15) und stellt somit das Ergebnis der Methode dar;
- Zeilen 2–4: Wir definieren die URL des abzufragenden Dienstes;
- Zeilen 6–10: die Parameter für die zu sendende POST-Anfrage. Die Service-URL [/calculate-tax] erwartet eine POST-Anfrage mit den Parametern [married, children, salary];
- Zeilen 12–13: Die Anfrage wird ausgeführt und die Antwort des Servers abgerufen. Die Service-URL [/calculate-tax] gibt ein Wörterbuch mit den Steuerschlüsseln [tax, discount, surcharge, reduction, rate] zurück;
- Zeile 15: Das erhaltene Wörterbuch [response] wird verwendet, um den Steuerzahler [taxpayer] zu aktualisieren;
[calculate_tax_in_bulk_mode]
- Zeile 2: Die Methode erhält eine Liste von Steuerzahlern vom Typ TaxPayer;
- Zeilen 7–13: Diese Liste von [TaxPayer]-Elementen wird in eine Liste von Wörterbüchern [Ehepartner, Kinder, Gehalt] umgewandelt;
- Zeilen 15–17: Die Service-URL wird festgelegt;
- Zeilen 19–20: Es wird eine POST-Anfrage ausgeführt, deren JSON-Body aus der in Zeile 7 erstellten Liste von Dictionaries besteht. Die Antwort des Servers wird abgerufen;
- Zeilen 23–24: Tests haben ein Problem aufgedeckt, wenn die Sitzung vom Typ XML ist:
- Wenn die ursprüngliche Liste der Steuerzahler N Elemente enthält (N > 1), ist das Ergebnis eine Liste von N Wörterbüchern vom Typ [OrderedDict];
- Wenn die ursprüngliche Liste nur ein Element enthält, ist das Ergebnis keine Liste, sondern ein einzelnes Element vom Typ [OrderedDict];
- Zeilen 23–24: Ist dies der Fall (1 Element), wandeln wir das Ergebnis in eine Liste mit 1 Element um;
- Zeilen 25–28: Diese Liste der empfangenen Wörterbücher enthält den Steuerbetrag für jeden Steuerzahler in der ursprünglichen Liste. Wir aktualisieren dann jedes einzelne mit den empfangenen Ergebnissen;
[get_simulations]
- Zeile 1: Die Methode fordert die Liste der in der aktuellen Sitzung durchgeführten Simulationen an;
- Zeile 2: Die Methode gibt die Antwort des Servers zurück;
[delete_simulation]
- Zeile 1: Die Methode löscht die Simulation, deren ID übergeben wird;
- Zeile 7: Sie gibt die Antwort des Servers zurück, die Liste der nach der angeforderten Löschung verbleibenden Simulationen;
[get-admindata]
- Zeile 1: Die Methode fordert die Steuerkonstanten vom Server an, um die Steuer zu berechnen;
- Zeile 29: Sie gibt einen Typ [AdminData] zurück;
- Zeile 9: Wir rufen die Antwort des Servers in Form eines Dictionaries ab. Tests zeigen, dass es ein Problem gibt, wenn es sich um eine XML-Sitzung handelt: Anstelle von numerischen Werten sind die Werte im Dictionary Zeichenfolgen. Wir hatten dieses Problem bereits bei der Untersuchung des Moduls [xmltodict] gemeldet und festgestellt, dass dies ein normales Verhalten ist. [xmltodict] verfügt über keine Typinformationen im ihm übergebenen XML-Stream. In diesem speziellen Fall müssen jedoch alle Werte im empfangenen Wörterbuch in numerische Werte umgewandelt werden. Dieses Wörterbuch enthält drei Listen [limites, coeffr, coeffn] und eine Reihe numerischer Eigenschaften;
- Zeilen 13–25: Erstellung eines [result2]-Wörterbuchs mit numerischen Werten aus dem [result]-Wörterbuch mit Zeichenfolgenwerten;
- Zeile 29: Das Wörterbuch [result2] wird verwendet, um einen Typ [AdminData] zu initialisieren;
31.2.3. Die [dao]-Layer-Factory
Unsere Clients werden multithreaded sein. Da die [dao]-Schicht durch eine Klasse mit Lese-/Schreibstatus (= Lese-/Schreib-Eigenschaften) implementiert ist, muss jeder Thread über eine eigene [dao]-Schicht verfügen, andernfalls muss der Zugriff auf gemeinsam genutzte Daten zwischen den Threads synchronisiert werden. Hier wählen wir die erste Lösung. Wir verwenden eine [ImpôtsDaoWithHttpSessionFactory]-Klasse, die Instanzen der [dao]-Schicht erstellen kann:
31.3. Client-Konfiguration

Clients werden mithilfe der Dateien [config] und [config_layers] konfiguriert. Die Datei [config] sieht wie folgt aus:
Die Datei [config_layers] sieht wie folgt aus:
- Clients haben keinen direkten Zugriff auf die [dao]-Schicht. Um Zugriff zu erhalten, müssen sie die Factory der [dao]-Schicht durchlaufen;
31.4. Der [main]-Client
Der [main]-Client ermöglicht es Ihnen, die URLs [/init-session, /authenticate-user, /calculate-taxes, /end-session] zu testen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
- Zeilen 4–11: Der Client erwartet einen Parameter, der den Sitzungstyp (JSON oder XML) angibt, der mit dem Server verwendet werden soll;
- Zeilen 13–15: Der Client wird konfiguriert;
- Zeilen 48–104: Dieser Code kommt uns bekannt vor. Er wurde schon oft verwendet. Er verteilt die Steuerzahler, für die wir die Steuer berechnen wollen, auf mehrere Threads;
- Zeile 26: Die Methode [thread_function] ist die Methode, die von jedem Thread ausgeführt wird, um die Steuer für die ihm zugewiesenen Steuerzahler zu berechnen;
- Zeilen 27–30: Jeder Thread verfügt über eine eigene [dao]-Schicht;
- Die Steuerberechnung erfolgt in vier Schritten:
- Zeilen 37–38: Initialisierung einer Sitzung (JSON oder XML) mit dem Server;
- Zeilen 39–40: Authentifizierung beim Server;
- Zeilen 41–42: Steuerberechnung;
- Zeilen 43–44: Beenden der Sitzung mit dem Server;
Wenn dieser Code im [json]-Modus ausgeführt wird, werden die folgenden Protokolle generiert:
2020-08-03 14:28:34.320751, MainThread : début du calcul de l'impôt des contribuables
2020-08-03 14:28:34.328749, Thread-1 : début du calcul de l'impôt des 4 contribuables
2020-08-03 14:28:34.328749, Thread-2 : début du calcul de l'impôt des 4 contribuables
2020-08-03 14:28:34.333592, Thread-3 : début du calcul de l'impôt des 3 contribuables
2020-08-03 14:28:34.368651, Thread-2 : {"action": "init-session", "état": 700, "réponse": ["session démarrée avec le type de réponse json"]}
2020-08-03 14:28:34.375699, Thread-1 : {"action": "init-session", "état": 700, "réponse": ["session démarrée avec le type de réponse json"]}
2020-08-03 14:28:34.377432, Thread-3 : {"action": "init-session", "état": 700, "réponse": ["session démarrée avec le type de réponse json"]}
2020-08-03 14:28:34.385653, Thread-2 : {"action": "authentifier-utilisateur", "état": 200, "réponse": "Authentification réussie"}
2020-08-03 14:28:34.392656, Thread-1 : {"action": "authentifier-utilisateur", "état": 200, "réponse": "Authentification réussie"}
2020-08-03 14:28:34.396377, Thread-3 : {"action": "authentifier-utilisateur", "état": 200, "réponse": "Authentification réussie"}
2020-08-03 14:28:34.406528, Thread-2 : {"action": "calculer-impots", "état": 1500, "réponse": [{"marié": "non", "enfants": 3, "salaire": 100000, "impôt": 16782, "surcôte": 7176, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 1}, {"marié": "oui", "enfants": 3, "salaire": 100000, "impôt": 9200, "surcôte": 2180, "taux": 0.3, "décôte": 0, "réduction": 0, "id": 2}, {"marié": "oui", "enfants": 5, "salaire": 100000, "impôt": 4230, "surcôte": 0, "taux": 0.14, "décôte": 0, "réduction": 0, "id": 3}, {"marié": "non", "enfants": 0, "salaire": 100000, "impôt": 22986, "surcôte": 0, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 4}]}
2020-08-03 14:28:34.413837, Thread-1 : {"action": "calculer-impots", "état": 1500, "réponse": [{"marié": "oui", "enfants": 2, "salaire": 55555, "impôt": 2814, "surcôte": 0, "taux": 0.14, "décôte": 0, "réduction": 0, "id": 1}, {"marié": "oui", "enfants": 2, "salaire": 50000, "impôt": 1384, "surcôte": 0, "taux": 0.14, "décôte": 384, "réduction": 347, "id": 2}, {"marié": "oui", "enfants": 3, "salaire": 50000, "impôt": 0, "surcôte": 0, "taux": 0.14, "décôte": 720, "réduction": 0, "id": 3}, {"marié": "non", "enfants": 2, "salaire": 100000, "impôt": 19884, "surcôte": 4480, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 4}]}
2020-08-03 14:28:34.416695, Thread-3 : {"action": "calculer-impots", "état": 1500, "réponse": [{"marié": "oui", "enfants": 2, "salaire": 30000, "impôt": 0, "surcôte": 0, "taux": 0.0, "décôte": 0, "réduction": 0, "id": 1}, {"marié": "non", "enfants": 0, "salaire": 200000, "impôt": 64210, "surcôte": 7498, "taux": 0.45, "décôte": 0, "réduction": 0, "id": 2}, {"marié": "oui", "enfants": 3, "salaire": 200000, "impôt": 42842, "surcôte": 17283, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 3}]}
2020-08-03 14:28:34.425747, Thread-2 : {"action": "fin-session", "état": 400, "réponse": "session réinitialisée"}
2020-08-03 14:28:34.425747, Thread-2 : fin du calcul de l'impôt des 4 contribuables
2020-08-03 14:28:34.428956, Thread-1 : {"action": "fin-session", "état": 400, "réponse": "session réinitialisée"}
2020-08-03 14:28:34.428956, Thread-1 : fin du calcul de l'impôt des 4 contribuables
2020-08-03 14:28:34.428956, Thread-3 : {"action": "fin-session", "état": 400, "réponse": "session réinitialisée"}
2020-08-03 14:28:34.428956, Thread-3 : fin du calcul de l'impôt des 3 contribuables
2020-08-03 14:28:34.428956, MainThread : fin du calcul de l'impôt des contribuables
Das Obige zeigt den Ausführungspfad von Thread [Thread-2].
Wenn wir [main] im XML-Modus ausführen, sehen die Protokolle wie folgt aus:
2020-08-03 14:32:48.495316, MainThread : début du calcul de l'impôt des contribuables
2020-08-03 14:32:48.496452, Thread-1 : début du calcul de l'impôt des 2 contribuables
2020-08-03 14:32:48.498992, Thread-2 : début du calcul de l'impôt des 2 contribuables
2020-08-03 14:32:48.498992, Thread-3 : début du calcul de l'impôt des 4 contribuables
2020-08-03 14:32:48.498992, Thread-4 : début du calcul de l'impôt des 3 contribuables
2020-08-03 14:32:48.538637, Thread-1 : <?xml version="1.0" encoding="utf-8"?>
<root><action>init-session</action><état>700</état><réponse>session démarrée avec le type de réponse xml</réponse></root>
2020-08-03 14:32:48.540783, Thread-4 : <?xml version="1.0" encoding="utf-8"?>
<root><action>init-session</action><état>700</état><réponse>session démarrée avec le type de réponse xml</réponse></root>
2020-08-03 14:32:48.547811, Thread-3 : <?xml version="1.0" encoding="utf-8"?>
<root><action>init-session</action><état>700</état><réponse>session démarrée avec le type de réponse xml</réponse></root>
2020-08-03 14:32:48.547811, Thread-2 : <?xml version="1.0" encoding="utf-8"?>
<root><action>init-session</action><état>700</état><réponse>session démarrée avec le type de réponse xml</réponse></root>
2020-08-03 14:32:48.555184, Thread-1 : <?xml version="1.0" encoding="utf-8"?>
<root><action>authentifier-utilisateur</action><état>200</état><réponse>Authentification réussie</réponse></root>
2020-08-03 14:32:48.564793, Thread-2 : <?xml version="1.0" encoding="utf-8"?>
<root><action>authentifier-utilisateur</action><état>200</état><réponse>Authentification réussie</réponse></root>
2020-08-03 14:32:48.564793, Thread-3 : <?xml version="1.0" encoding="utf-8"?>
<root><action>authentifier-utilisateur</action><état>200</état><réponse>Authentification réussie</réponse></root>
2020-08-03 14:32:48.568333, Thread-4 : <?xml version="1.0" encoding="utf-8"?>
<root><action>authentifier-utilisateur</action><état>200</état><réponse>Authentification réussie</réponse></root>
2020-08-03 14:32:48.568333, Thread-1 : <?xml version="1.0" encoding="utf-8"?>
<root><action>calculer-impots</action><état>1500</état><réponse><marié>oui</marié><enfants>2</enfants><salaire>55555</salaire><impôt>2814</impôt><surcôte>0</surcôte><taux>0.14</taux><décôte>0</décôte><réduction>0</réduction><id>1</id></réponse><réponse><marié>oui</marié><enfants>2</enfants><salaire>50000</salaire><impôt>1384</impôt><surcôte>0</surcôte><taux>0.14</taux><décôte>384</décôte><réduction>347</réduction><id>2</id></réponse></root>
2020-08-03 14:32:48.579205, Thread-2 : <?xml version="1.0" encoding="utf-8"?>
<root><action>calculer-impots</action><état>1500</état><réponse><marié>oui</marié><enfants>3</enfants><salaire>50000</salaire><impôt>0</impôt><surcôte>0</surcôte><taux>0.14</taux><décôte>720</décôte><réduction>0</réduction><id>1</id></réponse><réponse><marié>non</marié><enfants>2</enfants><salaire>100000</salaire><impôt>19884</impôt><surcôte>4480</surcôte><taux>0.41</taux><décôte>0</décôte><réduction>0</réduction><id>2</id></réponse></root>
2020-08-03 14:32:48.579205, Thread-3 : <?xml version="1.0" encoding="utf-8"?>
<root><action>calculer-impots</action><état>1500</état><réponse><marié>non</marié><enfants>3</enfants><salaire>100000</salaire><impôt>16782</impôt><surcôte>7176</surcôte><taux>0.41</taux><décôte>0</décôte><réduction>0</réduction><id>1</id></réponse><réponse><marié>oui</marié><enfants>3</enfants><salaire>100000</salaire><impôt>9200</impôt><surcôte>2180</surcôte><taux>0.3</taux><décôte>0</décôte><réduction>0</réduction><id>2</id></réponse><réponse><marié>oui</marié><enfants>5</enfants><salaire>100000</salaire><impôt>4230</impôt><surcôte>0</surcôte><taux>0.14</taux><décôte>0</décôte><réduction>0</réduction><id>3</id></réponse><réponse><marié>non</marié><enfants>0</enfants><salaire>100000</salaire><impôt>22986</impôt><surcôte>0</surcôte><taux>0.41</taux><décôte>0</décôte><réduction>0</réduction><id>4</id></réponse></root>
2020-08-03 14:32:48.588051, Thread-4 : <?xml version="1.0" encoding="utf-8"?>
<root><action>calculer-impots</action><état>1500</état><réponse><marié>oui</marié><enfants>2</enfants><salaire>30000</salaire><impôt>0</impôt><surcôte>0</surcôte><taux>0.0</taux><décôte>0</décôte><réduction>0</réduction><id>1</id></réponse><réponse><marié>non</marié><enfants>0</enfants><salaire>200000</salaire><impôt>64210</impôt><surcôte>7498</surcôte><taux>0.45</taux><décôte>0</décôte><réduction>0</réduction><id>2</id></réponse><réponse><marié>oui</marié><enfants>3</enfants><salaire>200000</salaire><impôt>42842</impôt><surcôte>17283</surcôte><taux>0.41</taux><décôte>0</décôte><réduction>0</réduction><id>3</id></réponse></root>
2020-08-03 14:32:48.594058, Thread-1 : <?xml version="1.0" encoding="utf-8"?>
<root><action>fin-session</action><état>400</état><réponse>session réinitialisée</réponse></root>
2020-08-03 14:32:48.595198, Thread-1 : fin du calcul de l'impôt des 2 contribuables
2020-08-03 14:32:48.595198, Thread-2 : <?xml version="1.0" encoding="utf-8"?>
<root><action>fin-session</action><état>400</état><réponse>session réinitialisée</réponse></root>
2020-08-03 14:32:48.595198, Thread-2 : fin du calcul de l'impôt des 2 contribuables
2020-08-03 14:32:48.595198, Thread-3 : <?xml version="1.0" encoding="utf-8"?>
<root><action>fin-session</action><état>400</état><réponse>session réinitialisée</réponse></root>
2020-08-03 14:32:48.595198, Thread-3 : fin du calcul de l'impôt des 4 contribuables
2020-08-03 14:32:48.603351, Thread-4 : <?xml version="1.0" encoding="utf-8"?>
<root><action>fin-session</action><état>400</état><réponse>session réinitialisée</réponse></root>
2020-08-03 14:32:48.603351, Thread-4 : fin du calcul de l'impôt des 3 contribuables
2020-08-03 14:32:48.603351, MainThread : fin du calcul de l'impôt des contribuables
Oben ist der Thread-Trace für [Thread-2] zu sehen.
31.5. Der Client [main2]

Mit dem Client [main2] können Sie die URLs [/init-session, /authenticate-user, /get-admindata, /end-session] testen:
- Zeilen 1–11: Abrufen des Parameters [json, xml], der den Typ der mit dem Server herzustellenden Sitzung festlegt;
- Zeilen 13–15: Wir konfigurieren den Client;
- Zeilen 30–33: Wir erstellen eine [dao]-Schicht;
- Zeilen 34–35: Mithilfe dieser Schicht rufen wir die Liste der Steuerzahler ab, für die die Steuer berechnet werden muss;
- Anschließend durchlaufen wir die vier Schritte des Dialogs mit dem Server;
- Zeilen 41–42: Es wird eine Sitzung mit dem Server gestartet;
- Zeilen 43–44: Wir authentifizieren uns beim Server;
- Zeilen 45–46: Wir fordern die Steuerkonstanten vom Server an, um die Steuer zu berechnen;
- Zeilen 47–48: Die Sitzung mit dem Server wird beendet;
- Zeilen 49–52: Anhand dieser Konstanten können wir die Steuer des Steuerpflichtigen mithilfe der lokalen [Business]-Schicht auf dem Client berechnen;
- Zeilen 53–54: Die Ergebnisse werden gespeichert;
Bei einer XML-Sitzung lauten die Ergebnisse wie folgt:
2020-08-03 14:44:43.194294, MainThread : début du calcul de l'impôt des contribuables
2020-08-03 14:44:43.231633, MainThread : <?xml version="1.0" encoding="utf-8"?>
<root><action>init-session</action><état>700</état><réponse>session démarrée avec le type de réponse xml</réponse></root>
2020-08-03 14:44:43.240872, MainThread : <?xml version="1.0" encoding="utf-8"?>
<root><action>authentifier-utilisateur</action><état>200</état><réponse>Authentification réussie</réponse></root>
2020-08-03 14:44:43.250061, MainThread : <?xml version="1.0" encoding="utf-8"?>
<root><action>get-admindata</action><état>1000</état><réponse><limites>9964.0</limites><limites>27519.0</limites><limites>73779.0</limites><limites>156244.0</limites><limites>93749.0</limites><coeffr>0.0</coeffr><coeffr>0.14</coeffr><coeffr>0.3</coeffr><coeffr>0.41</coeffr><coeffr>0.45</coeffr><coeffn>0.0</coeffn><coeffn>1394.96</coeffn><coeffn>5798.0</coeffn><coeffn>13913.7</coeffn><coeffn>20163.4</coeffn><abattement_dixpourcent_min>437.0</abattement_dixpourcent_min><plafond_impot_couple_pour_decote>2627.0</plafond_impot_couple_pour_decote><plafond_decote_couple>1970.0</plafond_decote_couple><valeur_reduc_demi_part>3797.0</valeur_reduc_demi_part><plafond_revenus_celibataire_pour_reduction>21037.0</plafond_revenus_celibataire_pour_reduction><id>1</id><abattement_dixpourcent_max>12502.0</abattement_dixpourcent_max><plafond_impot_celibataire_pour_decote>1595.0</plafond_impot_celibataire_pour_decote><plafond_decote_celibataire>1196.0</plafond_decote_celibataire><plafond_revenus_couple_pour_reduction>42074.0</plafond_revenus_couple_pour_reduction><plafond_qf_demi_part>1551.0</plafond_qf_demi_part></réponse></root>
2020-08-03 14:44:43.269850, MainThread : <?xml version="1.0" encoding="utf-8"?>
<root><action>fin-session</action><état>400</état><réponse>session réinitialisée</réponse></root>
2020-08-03 14:44:43.269850, MainThread : fin du calcul de l'impôt des contribuables
31.6. Der Client [main3]
Mit dem Client [main3] können Sie die URLs [/init-session, /calculate-taxes, /get-simulations, /delete-simulation, /end-session] testen:

- Zeilen 1–11: Abrufen des Sitzungstyps aus den Skriptparametern;
- Zeilen 13–15: Wir konfigurieren die Anwendung;
- Zeilen 25–50: Code, der bereits an anderer Stelle erläutert wurde;
- Zeilen 51–52: Wir fordern die Liste der in der aktuellen Sitzung durchgeführten Simulationen an;
- Zeilen 53–57: jede zweite Simulation löschen;
- Zeilen 58–59: Die Sitzung wird beendet;
Während einer jSON-Sitzung sehen die Protokolle wie folgt aus:
2020-08-03 15:01:52.702297, MainThread : début du calcul de l'impôt des contribuables
2020-08-03 15:01:52.702297, MainThread : début du calcul de l'impôt des 11 contribuables
2020-08-03 15:01:52.734806, MainThread : {"action": "init-session", "état": 700, "réponse": ["session démarrée avec le type de réponse json"]}
2020-08-03 15:01:52.747961, MainThread : {"action": "authentifier-utilisateur", "état": 200, "réponse": "Authentification réussie"}
2020-08-03 15:01:52.765721, MainThread : {"action": "calculer-impots", "état": 1500, "réponse": [{"marié": "oui", "enfants": 2, "salaire": 55555, "impôt": 2814, "surcôte": 0, "taux": 0.14, "décôte": 0, "réduction": 0, "id": 1}, {"marié": "oui", "enfants": 2, "salaire": 50000, "impôt": 1384, "surcôte": 0, "taux": 0.14, "décôte": 384, "réduction": 347, "id": 2}, {"marié": "oui", "enfants": 3, "salaire": 50000, "impôt": 0, "surcôte": 0, "taux": 0.14, "décôte": 720, "réduction": 0, "id": 3}, {"marié": "non", "enfants": 2, "salaire": 100000, "impôt": 19884, "surcôte": 4480, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 4}, {"marié": "non", "enfants": 3, "salaire": 100000, "impôt": 16782, "surcôte": 7176, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 5}, {"marié": "oui", "enfants": 3, "salaire": 100000, "impôt": 9200, "surcôte": 2180, "taux": 0.3, "décôte": 0, "réduction": 0, "id": 6}, {"marié": "oui", "enfants": 5, "salaire": 100000, "impôt": 4230, "surcôte": 0, "taux": 0.14, "décôte": 0, "réduction": 0, "id": 7}, {"marié": "non", "enfants": 0, "salaire": 100000, "impôt": 22986, "surcôte": 0, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 8}, {"marié": "oui", "enfants": 2, "salaire": 30000, "impôt": 0, "surcôte": 0, "taux": 0.0, "décôte": 0, "réduction": 0, "id": 9}, {"marié": "non", "enfants": 0, "salaire": 200000, "impôt": 64210, "surcôte": 7498, "taux": 0.45, "décôte": 0, "réduction": 0, "id": 10}, {"marié": "oui", "enfants": 3, "salaire": 200000, "impôt": 42842, "surcôte": 17283, "taux": 0.41, "décôte": 0, "réduction": 0, "id": 11}]}
2020-08-03 15:01:52.785505, MainThread : {"action": "lister-simulations", "état": 500, "réponse": [{"décôte": 0, "enfants": 2, "id": 1, "impôt": 2814, "marié": "oui", "réduction": 0, "salaire": 55555, "surcôte": 0, "taux": 0.14}, {"décôte": 384, "enfants": 2, "id": 2, "impôt": 1384, "marié": "oui", "réduction": 347, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 720, "enfants": 3, "id": 3, "impôt": 0, "marié": "oui", "réduction": 0, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 2, "id": 4, "impôt": 19884, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 4480, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 5, "impôt": 16782, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 7176, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 6, "impôt": 9200, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 2180, "taux": 0.3}, {"décôte": 0, "enfants": 5, "id": 7, "impôt": 4230, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 0, "id": 8, "impôt": 22986, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.41}, {"décôte": 0, "enfants": 2, "id": 9, "impôt": 0, "marié": "oui", "réduction": 0, "salaire": 30000, "surcôte": 0, "taux": 0.0}, {"décôte": 0, "enfants": 0, "id": 10, "impôt": 64210, "marié": "non", "réduction": 0, "salaire": 200000, "surcôte": 7498, "taux": 0.45}, {"décôte": 0, "enfants": 3, "id": 11, "impôt": 42842, "marié": "oui", "réduction": 0, "salaire": 200000, "surcôte": 17283, "taux": 0.41}]}
2020-08-03 15:01:52.801475, MainThread : {"action": "supprimer-simulation", "état": 600, "réponse": [{"décôte": 384, "enfants": 2, "id": 2, "impôt": 1384, "marié": "oui", "réduction": 347, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 720, "enfants": 3, "id": 3, "impôt": 0, "marié": "oui", "réduction": 0, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 2, "id": 4, "impôt": 19884, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 4480, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 5, "impôt": 16782, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 7176, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 6, "impôt": 9200, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 2180, "taux": 0.3}, {"décôte": 0, "enfants": 5, "id": 7, "impôt": 4230, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 0, "id": 8, "impôt": 22986, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.41}, {"décôte": 0, "enfants": 2, "id": 9, "impôt": 0, "marié": "oui", "réduction": 0, "salaire": 30000, "surcôte": 0, "taux": 0.0}, {"décôte": 0, "enfants": 0, "id": 10, "impôt": 64210, "marié": "non", "réduction": 0, "salaire": 200000, "surcôte": 7498, "taux": 0.45}, {"décôte": 0, "enfants": 3, "id": 11, "impôt": 42842, "marié": "oui", "réduction": 0, "salaire": 200000, "surcôte": 17283, "taux": 0.41}]}
2020-08-03 15:01:52.810129, MainThread : {"action": "supprimer-simulation", "état": 600, "réponse": [{"décôte": 384, "enfants": 2, "id": 2, "impôt": 1384, "marié": "oui", "réduction": 347, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 2, "id": 4, "impôt": 19884, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 4480, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 5, "impôt": 16782, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 7176, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 6, "impôt": 9200, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 2180, "taux": 0.3}, {"décôte": 0, "enfants": 5, "id": 7, "impôt": 4230, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 0, "id": 8, "impôt": 22986, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.41}, {"décôte": 0, "enfants": 2, "id": 9, "impôt": 0, "marié": "oui", "réduction": 0, "salaire": 30000, "surcôte": 0, "taux": 0.0}, {"décôte": 0, "enfants": 0, "id": 10, "impôt": 64210, "marié": "non", "réduction": 0, "salaire": 200000, "surcôte": 7498, "taux": 0.45}, {"décôte": 0, "enfants": 3, "id": 11, "impôt": 42842, "marié": "oui", "réduction": 0, "salaire": 200000, "surcôte": 17283, "taux": 0.41}]}
2020-08-03 15:01:52.818803, MainThread : {"action": "supprimer-simulation", "état": 600, "réponse": [{"décôte": 384, "enfants": 2, "id": 2, "impôt": 1384, "marié": "oui", "réduction": 347, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 2, "id": 4, "impôt": 19884, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 4480, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 6, "impôt": 9200, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 2180, "taux": 0.3}, {"décôte": 0, "enfants": 5, "id": 7, "impôt": 4230, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 0, "id": 8, "impôt": 22986, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.41}, {"décôte": 0, "enfants": 2, "id": 9, "impôt": 0, "marié": "oui", "réduction": 0, "salaire": 30000, "surcôte": 0, "taux": 0.0}, {"décôte": 0, "enfants": 0, "id": 10, "impôt": 64210, "marié": "non", "réduction": 0, "salaire": 200000, "surcôte": 7498, "taux": 0.45}, {"décôte": 0, "enfants": 3, "id": 11, "impôt": 42842, "marié": "oui", "réduction": 0, "salaire": 200000, "surcôte": 17283, "taux": 0.41}]}
2020-08-03 15:01:52.834604, MainThread : {"action": "supprimer-simulation", "état": 600, "réponse": [{"décôte": 384, "enfants": 2, "id": 2, "impôt": 1384, "marié": "oui", "réduction": 347, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 2, "id": 4, "impôt": 19884, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 4480, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 6, "impôt": 9200, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 2180, "taux": 0.3}, {"décôte": 0, "enfants": 0, "id": 8, "impôt": 22986, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.41}, {"décôte": 0, "enfants": 2, "id": 9, "impôt": 0, "marié": "oui", "réduction": 0, "salaire": 30000, "surcôte": 0, "taux": 0.0}, {"décôte": 0, "enfants": 0, "id": 10, "impôt": 64210, "marié": "non", "réduction": 0, "salaire": 200000, "surcôte": 7498, "taux": 0.45}, {"décôte": 0, "enfants": 3, "id": 11, "impôt": 42842, "marié": "oui", "réduction": 0, "salaire": 200000, "surcôte": 17283, "taux": 0.41}]}
2020-08-03 15:01:52.843803, MainThread : {"action": "supprimer-simulation", "état": 600, "réponse": [{"décôte": 384, "enfants": 2, "id": 2, "impôt": 1384, "marié": "oui", "réduction": 347, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 2, "id": 4, "impôt": 19884, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 4480, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 6, "impôt": 9200, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 2180, "taux": 0.3}, {"décôte": 0, "enfants": 0, "id": 8, "impôt": 22986, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.41}, {"décôte": 0, "enfants": 0, "id": 10, "impôt": 64210, "marié": "non", "réduction": 0, "salaire": 200000, "surcôte": 7498, "taux": 0.45}, {"décôte": 0, "enfants": 3, "id": 11, "impôt": 42842, "marié": "oui", "réduction": 0, "salaire": 200000, "surcôte": 17283, "taux": 0.41}]}
2020-08-03 15:01:52.851855, MainThread : {"action": "supprimer-simulation", "état": 600, "réponse": [{"décôte": 384, "enfants": 2, "id": 2, "impôt": 1384, "marié": "oui", "réduction": 347, "salaire": 50000, "surcôte": 0, "taux": 0.14}, {"décôte": 0, "enfants": 2, "id": 4, "impôt": 19884, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 4480, "taux": 0.41}, {"décôte": 0, "enfants": 3, "id": 6, "impôt": 9200, "marié": "oui", "réduction": 0, "salaire": 100000, "surcôte": 2180, "taux": 0.3}, {"décôte": 0, "enfants": 0, "id": 8, "impôt": 22986, "marié": "non", "réduction": 0, "salaire": 100000, "surcôte": 0, "taux": 0.41}, {"décôte": 0, "enfants": 0, "id": 10, "impôt": 64210, "marié": "non", "réduction": 0, "salaire": 200000, "surcôte": 7498, "taux": 0.45}]}
2020-08-03 15:01:52.863165, MainThread : {"action": "fin-session", "état": 400, "réponse": "session réinitialisée"}
2020-08-03 15:01:52.863165, MainThread : fin du calcul de l'impôt des contribuables
- Zeile 6: Wir haben 11 Simulationen;
- Zeile 12: Nach den verschiedenen Löschungen sind nur noch 5 übrig;
31.7. Die Testklasse [Test2HttpClientDaoWithSession]

Die Klasse [Test2HttpClientDaoWithSession] testet die [dao]-Schicht der Clients wie folgt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
- Die [dao]-Schicht sendet eine Anfrage an den Server, empfängt dessen Antwort und formatiert diese, um sie an den aufrufenden Code zurückzugeben. Wenn der Server eine Antwort mit einem anderen Statuscode als 200 sendet, löst die [dao]-Schicht eine Ausnahme aus. Daher beinhalten einige Tests die Überprüfung, ob eine Ausnahme aufgetreten ist oder nicht;
- Zeilen 9–18: Wir initialisieren eine JSON-Sitzung. Es sollten keine Fehler auftreten;
- Zeilen 20–29: Wir initialisieren eine XML-Sitzung. Es sollte kein Fehler auftreten;
- Zeilen 31–40: Wir initialisieren eine Sitzung mit einem falschen Typ. Es muss ein Fehler auftreten;
- Zeilen 42–54: Wir authentifizieren uns mit den korrekten Anmeldedaten. Es sollte kein Fehler auftreten;
- Zeilen 56–68: Authentifizierung mit falschen Anmeldedaten. Es muss ein Fehler auftreten;
- Zeilen 70–92: Wir berechnen die Steuer und fordern dann die Liste der Simulationen an. Wir sollten eine erhalten. Zusätzlich überprüfen wir, ob diese Simulation die angeforderte Steuer enthält;
- Zeilen 94–119: Eine Simulation wird erstellt und anschließend gelöscht. Dann wird versucht, eine Simulation zu löschen, obwohl keine Simulationen mehr vorhanden sind. Es muss ein Fehler auftreten;
- Zeilen 121–137: Der Test wird als Standard-Konsolenskript ausgeführt;
- Zeilen 122–124: Wir konfigurieren die Anwendung;
- Zeilen 126–129: Wir konfigurieren den Logger. Dies ermöglicht es uns, die Protokolle zu verfolgen;
- Zeilen 131–133: Wir instanziieren die [DAO]-Schicht, die getestet werden soll;
- Zeilen 135–137: Führen Sie die Tests aus;
Die Konsolenausgabe lautet wie folgt:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-clients/07/tests/Test2HttpClientDaoWithSession.py
tests en cours...
test_authenticate_user_failed
..MyException[35, ["Echec de l'authentification"]]
test_authenticate_user_success
test_delete_simulation
MyException[35, ["la simulation n° [100] n'existe pas"]]
test_get_simulations
test_init_session_json
test_init_session_xml
test_init_session_xxx
MyException[73, il n'y a pas de session valide en cours]
----------------------------------------------------------------------
Ran 7 tests in 0.171s
OK
Process finished with exit code 0