31. عملاء الويب لخدمات JSON و XML للإصدار 12
سنكتب ثلاثة تطبيقات عميل وحدة التحكم لخدمات JSON و XML لخادم الويب الذي كتبناه للتو. سنعيد استخدام بنية العميل/الخادم من الإصدار 11:

سنكتب ثلاثة نصوص برمجية للوحدة:
- ستستخدم البرامج النصية [main] و [main3] طبقة [business] الخاصة بالخادم؛
- سيستخدم البرنامج النصي [main2] طبقة [business] الخاصة بالعميل؛
31.1. هيكل دليل نصوص العميل
يتم إنشاء المجلد [http-clients/07] مبدئيًا عن طريق نسخ المجلد [http-clients/06]. ثم يتم تعديله.

- في [1]: البيانات التي يستخدمها العميل أو ينشئها؛
- في [2]، نصوص تكوين العميل ونصوص وحدة التحكم؛
- في [3]، طبقة [dao] الخاصة بالعميل؛
- في [4]، مجلد الاختبار لطبقة [dao] الخاصة بالعميل؛
31.2. طبقة [dao] للعملاء


31.2.1. الواجهة
ستقوم طبقة [dao] بتنفيذ واجهة [InterfaceImpôtsDaoWithHttpSession] التالية:
تتوافق كل طريقة من طرق الواجهة مع عنوان URL لخدمة على خادم حساب الضرائب.
- السطر 7: تمتد الواجهة من فئة [AbstractDao]، التي تدير الوصول إلى نظام الملفات؛
يتم تعريف التعيين بين الطرق وعناوين URL للخدمات في ملف التكوين [config]:
# 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. التنفيذ
يتم تنفيذ واجهة [InterfaceImpôtsDaoWithHttpSession] بواسطة فئة [ImpôtsDaoWithHttpSession] التالية:
- الأسطر 16–34: منشئ الفئة؛
- السطر 19: يتم تهيئة الفئة الأم؛
- الأسطر 21–28: يتم تخزين بيانات تكوين معينة؛
- الأسطر 29–34: يتم إنشاء ثلاث خصائص تُستخدم في أساليب الفئة؛
- الأسطر 36–82: تقوم طريقة [get_response] بفصل العناصر المشتركة بين جميع الطرق في طبقة [dao]: إرسال طلب HTTP واسترداد استجابة HTTP من الخادم؛
- الأسطر 38–42: تعريف المعلمات الخمس لطريقة [get_response]؛
- السطر 42: لاحظ أنه نظرًا لأن الخادم يحافظ على الجلسة، يحتاج العميل إلى قراءة/إرسال ملفات تعريف الارتباط؛
- الأسطر 44–46: نتحقق من وجود جلسة عمل صالحة بالفعل؛
- السطر 51: حالة GET. يتم إرسال ملفات تعريف الارتباط المستلمة مرة أخرى؛
- السطر 54: حالة POST. يمكن أن تحتوي هذه الحالة على نوعين من المعلمات:
- النوع [x-www-form-urlencoded]. هذا هو الحال بالنسبة لعناوين URL [/calculate-tax] و [/authenticate-user]. ثم نستخدم المعلمة [data_value] التي استلمتها الطريقة؛
- النوع [json]. هذا هو الحال بالنسبة لعنوان URL [/calculate-taxes]. ثم نستخدم المعلمة [json_value] التي استلمتها الطريقة؛
هنا أيضًا، يتم إرجاع ملف تعريف ارتباط الجلسة.
- الأسطر 56–62: إذا كنا في وضع [debug]، يتم تسجيل استجابة الخادم. هذا السجل مهم لأنه يسمح لنا بمعرفة ما أعاده الخادم بالضبط؛
- الأسطر 64–68: اعتمادًا على ما إذا كنا في وضع JSON أو XML، يتم تحويل استجابة الخادم النصية إلى قاموس. لنأخذ مثال عنوان URL [/init-session]:
استجابة JSON هي كما يلي:
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"]}
الاستجابة XML هي كما يلي:
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>
يضمن الكود في الأسطر 64–68 أنه، في كلتا الحالتين، تحتوي [result] على قاموس بمفاتيح [action, status, response]؛
- الأسطر 70–72: إذا كانت الاستجابة تحتوي على ملفات تعريف الارتباط، يتم استردادها. ويجب إرسالها مرة أخرى مع الطلب التالي؛
- الأسطر 74–79: إذا لم تكن حالة HTTP للاستجابة هي 200، يتم إثارة استثناء مع رسالة الخطأ الموجودة في result[‘response’]. يمكن أن يكون هذا خطأً واحدًا أو قائمة من الأخطاء؛
- الأسطر 81–82: إرجاع استجابة الخادم إلى الكود المستدعي؛
[init_session]
- السطر 84: تُستخدم طريقة [init_session] لتعيين نوع الجلسة (JSON أو XML) التي يرغب العميل في بدءها مع الخادم؛
- السطر 86: يتم تخزين نوع الجلسة المطلوب داخل الفئة. في الواقع، تتطلب جميع الطرق هذه المعلومات لفك تشفير استجابة الخادم بشكل صحيح؛
- الأسطر 88-90: باستخدام تكوين التطبيق، يتم تحديد عنوان URL للخدمة المراد الاستعلام عنها؛
- السطر 93: يتم الاستعلام عن عنوان URL للخدمة. لا يتم استرداد نتيجة طريقة [get_response]:
- إذا أطلقت استثناءً، فهذا يعني أن العملية قد فشلت. لا يتم التعامل مع الاستثناء هنا وسيتم تمريره مباشرةً إلى الكود المستدعي، والذي سيقوم بعد ذلك بإنهاء عمل العميل مع رسالة خطأ؛
- إذا لم تحدث استثناء، فإن تهيئة الجلسة قد نجحت؛
[authenticate_user]
- تُستخدم طريقة [authenticate_user] للمصادقة مع الخادم. للقيام بذلك، تستقبل بيانات اعتماد تسجيل الدخول [user, password] في السطر 1؛
- الأسطر 2–4: نحدد عنوان URL للخدمة المراد الاستعلام عنها؛
- الأسطر 5-8: معلمات POST، نظرًا لأن عنوان URL [/authenticate-user] يتوقع طلب POST مع المعلمات [user, password]؛
- السطر 11: يتم تنفيذ الطلب. مرة أخرى، لا نسترد استجابة الخادم. إن الاستثناء الذي ترمي به [get_response] هو الذي يشير إلى ما إذا كانت العملية ناجحة أم لا؛
[calculate_tax]
- تحسب الطريقة [calculate_tax] الضريبة لمكلف [taxpayer] تم تمريره كمعلمة. يتم تعديل هذه المعلمة بواسطة الطريقة (السطر 15) وبالتالي تشكل نتيجة الطريقة؛
- الأسطر 2–4: نحدد عنوان URL للخدمة المراد الاستعلام عنها؛
- الأسطر 6-10: المعلمات لطلب POST المراد إرساله. يتوقع عنوان URL للخدمة [/calculate-tax] طلب POST مع المعلمات [married, children, salary]؛
- السطور 12-13: يتم تنفيذ الطلب واسترداد استجابة الخادم. يعرض عنوان URL للخدمة [/calculate-tax] قاموسًا بمفاتيح الضريبة [tax, discount, surcharge, reduction, rate]؛
- السطر 15: يتم استخدام القاموس الذي تم الحصول عليه [response] لتحديث دافع الضرائب [taxpayer]؛
[calculate_tax_in_bulk_mode]
- السطر 2: تتلقى الطريقة قائمة بالدافعين من النوع TaxPayer؛
- الأسطر 7–13: يتم تحويل قائمة عناصر [TaxPayer] هذه إلى قائمة من القواميس [spouse, children, salary]؛
- الأسطر 15-17: يتم تعيين عنوان URL للخدمة؛
- السطور 19-20: يتم تنفيذ طلب POST، مع نص JSON يتكون من قائمة القواميس التي تم إنشاؤها في السطر 7. يتم استرداد استجابة الخادم؛
- السطور 23–24: كشفت الاختبارات عن مشكلة عندما تكون الجلسة من النوع XML:
- إذا كانت القائمة الأولية لدافعي الضرائب تحتوي على N عنصرًا (N>1)، فإن النتيجة هي قائمة من N قواميس من النوع [OrderedDict]؛
- إذا كانت القائمة الأولية تحتوي على عنصر واحد فقط، فإن النتيجة ليست قائمة بل عنصر واحد من النوع [OrderedDict]؛
- السطران 23-24: إذا كان هذا هو الحال (عنصر واحد)، فإننا نحول النتيجة إلى قائمة من عنصر واحد؛
- الأسطر 25-28: تحتوي قائمة القواميس المستلمة هذه على مبلغ الضريبة لكل دافع ضرائب في القائمة الأولية. ثم نقوم بتحديث كل منها بالنتائج المستلمة؛
[get_simulations]
- السطر 1: تطلب الطريقة قائمة المحاكاة التي تم إجراؤها في الجلسة الحالية؛
- السطر 2: تعيد الطريقة استجابة الخادم؛
[delete_simulation]
- السطر 1: تقوم الطريقة بحذف المحاكاة التي تم تمرير معرفها؛
- السطر 7: تعيد استجابة الخادم، وهي قائمة المحاكاة المتبقية بعد الحذف المطلوب؛
[get-admindata]
- السطر 1: تطلب الطريقة الثوابت الضريبية من الخادم لحساب الضريبة؛
- السطر 29: تُرجع نوع [AdminData]؛
- السطر 9: نسترد استجابة الخادم في شكل قاموس. تُظهر الاختبارات وجود مشكلة عندما تكون الجلسة جلسة XML: فبدلاً من أن تكون القيم أرقامًا، تكون القيم في القاموس سلاسل نصية. كنا قد أبلغنا عن هذه المشكلة أثناء دراسة وحدة [xmltodict] ووجدنا أن هذا سلوك طبيعي. لا تحتوي [xmltodict] على معلومات عن النوع في دفق XML الذي يتم تزويدها به. ومع ذلك، في هذه الحالة المحددة، يجب تحويل جميع القيم في القاموس المستلم إلى قيم رقمية. يحتوي هذا القاموس على ثلاث قوائم [limites، coeffr، coeffn] وسلسلة من الخصائص الرقمية؛
- الأسطر 13–25: إنشاء قاموس [result2] بقيم رقمية من قاموس [result] الذي يحتوي على قيم من نوع سلسلة؛
- السطر 29: يتم استخدام القاموس [result2] لتهيئة نوع [AdminData]؛
31.2.3. مصنع طبقة [dao]
سيكون عملاؤنا متعددي الخيوط. نظرًا لأن طبقة [dao] يتم تنفيذها بواسطة فئة ذات حالة قراءة/كتابة (= خصائص قراءة/كتابة)، يجب أن يكون لكل خيط طبقة [dao] خاصة به، وإلا يجب مزامنة الوصول إلى البيانات المشتركة بين الخيوط. هنا نختار الحل الأول. نستخدم فئة [ImpôtsDaoWithHttpSessionFactory] قادرة على إنشاء مثيلات لطبقة [dao]:
31.3. تكوين العميل

يتم تكوين العملاء باستخدام ملفات [config] و [config_layers]. ملف [config] هو كما يلي:
ملف [config_layers] كما يلي:
- لن يتمكن العملاء من الوصول المباشر إلى طبقة [dao]. وللوصول إليها، يجب عليهم المرور عبر مصنع طبقة [dao]؛
31.4. العميل [main]
يتيح لك عميل [main] اختبار عناوين URL [/init-session، /authenticate-user، /calculate-taxes، /end-session]:
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 | |
- الأسطر 4-11: يتوقع العميل معلمة تحدد نوع الجلسة، JSON أو XML، لاستخدامها مع الخادم؛
- الأسطر 13-15: تم تكوين العميل؛
- الأسطر 48–104: هذا الكود مألوف. وقد استُخدم مرات عديدة. وهو يوزع دافعي الضرائب الذين نريد حساب الضريبة عليهم على عدة خيوط؛
- السطر 26: طريقة [thread_function] هي الطريقة التي تنفذها كل خيط لحساب الضريبة للمكلفين المخصصين له؛
- الأسطر 27–30: لكل مؤشر ترابط طبقة [dao] خاصة به؛
- يتم حساب الضريبة في أربع خطوات:
- السطور 37-38: تهيئة جلسة (JSON أو XML) مع الخادم؛
- السطران 39-40: المصادقة مع الخادم؛
- السطور 41-42: حساب الضريبة؛
- الأسطر 43-44: إغلاق الجلسة مع الخادم؛
عند تنفيذ هذا الرمز في الوضع [json]، يتم إنشاء السجلات التالية:
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
يوضح ما سبق مسار تنفيذ الخيط [Thread-2].
إذا قمنا بتشغيل [main] في وضع XML، فستكون السجلات كما يلي:
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
فيما يلي مسار مؤشر ترابط [Thread-2].
31.5. العميل [main2]

يتيح لك العميل [main2] اختبار عناوين URL [/init-session، /authenticate-user، /get-admindata، /end-session]:
- الأسطر 1-11: استرداد المعلمة [json, xml] التي تحدد نوع الجلسة المراد إنشاؤها مع الخادم؛
- الأسطر 13-15: نقوم بتكوين العميل؛
- الأسطر 30-33: نقوم بإنشاء طبقة [dao]؛
- الأسطر 34-35: باستخدامها، نسترد قائمة دافعي الضرائب الذين يجب حساب الضريبة عليهم؛
- ثم نمر بالخطوات الأربع للحوار مع الخادم؛
- السطور 41–42: يتم بدء جلسة مع الخادم؛
- السطور 43-44: نقوم بالمصادقة مع الخادم؛
- السطور 45-46: نطلب ثوابت الضريبة من الخادم لحساب الضريبة؛
- السطران 47-48: يتم إغلاق الجلسة مع الخادم؛
- الأسطر 49–52: باستخدام هذه الثوابت، يمكننا حساب ضريبة دافعي الضرائب باستخدام الطبقة [التجارية] المحلية على العميل؛
- السطران 53 و54: يتم حفظ النتائج؛
بالنسبة لجلسة XML، تكون النتائج كما يلي:
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. العميل [main3]
يتيح لك العميل [main3] اختبار عناوين URL [/init-session، /calculate-taxes، /get-simulations، /delete-simulation، /end-session]:

- الأسطر 1-11: استرداد نوع الجلسة من معلمات البرنامج النصي؛
- الأسطر 13-15: نقوم بتكوين التطبيق؛
- الأسطر 25-50: كود تم شرحه بالفعل في مرحلة ما؛
- السطور 51-52: نطلب قائمة المحاكاة التي تم إجراؤها في الجلسة الحالية؛
- الأسطر 53-57: حذف كل محاكاة أخرى؛
- السطور 58–59: يتم إنهاء الجلسة؛
خلال جلسة jSON، تكون السجلات كما يلي:
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
- السطر 6: لدينا 11 محاكاة؛
- السطر 12: بعد عمليات الحذف المختلفة، لم يتبق سوى 5؛
31.7. فئة الاختبار [Test2HttpClientDaoWithSession]

تختبر فئة [Test2HttpClientDaoWithSession] طبقة [dao] للعملاء على النحو التالي:
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 | |
- ترسل طبقة [dao] طلبًا إلى الخادم، وتستقبل الرد، وتقوم بتنسيقه لإعادته إلى الكود المستدعي. عندما يرسل الخادم ردًا برمز حالة غير 200، تثير طبقة [dao] استثناءً. لذلك، يتضمن عدد من الاختبارات التحقق مما إذا كان قد حدث استثناء أم لا؛
- الأسطر 9–18: نقوم بتهيئة جلسة JSON. لا ينبغي أن تكون هناك أخطاء؛
- الأسطر 20-29: نقوم بتهيئة جلسة XML. لا ينبغي أن يكون هناك أي خطأ؛
- الأسطر 31-40: نقوم بتهيئة جلسة بنوع غير صحيح. يجب أن يحدث خطأ؛
- الأسطر 42-54: نقوم بالمصادقة باستخدام بيانات الاعتماد الصحيحة. لا ينبغي أن يكون هناك أي خطأ؛
- الأسطر 56-68: المصادقة باستخدام بيانات اعتماد غير صحيحة. يجب أن يحدث خطأ؛
- الأسطر 70-92: نحسب الضريبة ثم نطلب قائمة المحاكاة. يجب أن نحصل على واحدة. بالإضافة إلى ذلك، نتحقق من أن هذه المحاكاة تحتوي على الضريبة المطلوبة؛
- الأسطر 94–119: يتم إنشاء محاكاة ثم حذفها. ثم تتم محاولة حذف محاكاة على الرغم من عدم وجود محاكاة متبقية. يجب أن يحدث خطأ؛
- الأسطر 121–137: يتم تشغيل الاختبار كنص برمجي قياسي لوحدة التحكم؛
- الأسطر 122–124: نقوم بتكوين التطبيق؛
- الأسطر 126–129: نقوم بتكوين المسجل. سيسمح لنا ذلك بتتبع السجلات؛
- الأسطر 131–133: نقوم بإنشاء مثيل لطبقة [DAO] التي سيتم اختبارها؛
- الأسطر 135–137: تشغيل الاختبارات؛
إخراج وحدة التحكم كما يلي:
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