اختبار التحميل كخدمة CI للمطورين

اختبار التحميل كخدمة CI للمطورين

إحدى المشكلات التي يواجهها بائعو البرامج متعددة المنتجات غالبًا هي تكرار كفاءات المهندسين - المطورين والمختبرين ومسؤولي البنية التحتية - في كل فريق تقريبًا. ينطبق هذا أيضًا على المهندسين المكلفين - المتخصصين في مجال اختبار الحمل.

بدلاً من القيام بواجباتهم المباشرة واستخدام خبرتهم الفريدة لبناء عملية اختبار الحمل ، واختيار المنهجية والمقاييس المثلى وكتابة الاختبارات التلقائية وفقًا لملفات تعريف التحميل ، غالبًا ما يتعين على المهندسين نشر البنية التحتية للاختبار من البداية وتهيئة أدوات التحميل وتضمينها أنفسهم في أنظمة CI ، وإنشاء المراقبة ونشر التقارير.

يمكنك إيجاد حلول لبعض المشاكل التنظيمية في الاختبار التي نستخدمها في Positive Technologies في مقال آخر. وفي هذا ، سأتحدث عن إمكانية دمج اختبارات الحمل في خط أنابيب CI مشترك باستخدام مفهوم "اختبار الحمل كخدمة" (اختبار الحمل كخدمة). سوف تتعلم كيف وأي صور عامل ميناء يمكن استخدامها في خط أنابيب CI ؛ كيفية توصيل مصادر التحميل بمشروع CI الخاص بك باستخدام قالب بناء ؛ كيف يبدو خط الأنابيب التجريبي لإجراء اختبارات الحمل ونشر النتائج. قد تكون المقالة مفيدة لمهندسي اختبار البرمجيات ومهندسي التشغيل الآلي في CI الذين يفكرون في بنية نظام التحميل الخاص بهم.

جوهر المفهوم

ينطوي مفهوم اختبار الحمل كخدمة على القدرة على دمج أدوات التحميل Apache JMeter و Yandex.Tank وأطر العمل الخاصة بك في نظام تكامل عشوائي مستمر. سيكون العرض التوضيحي خاصًا بـ GitLab CI ، لكن المبادئ مشتركة في جميع أنظمة CI.

اختبار الحمل كخدمة هو خدمة مركزية لاختبار الحمل. يتم تشغيل اختبارات التحميل في مجموعات وكلاء مخصصة ، ويتم نشر النتائج تلقائيًا في صفحات GitLab و Influx DB و Grafana أو في أنظمة تقارير الاختبار (TestRail و ReportPortal وما إلى ذلك). يتم تنفيذ الأتمتة والتوسيع بأكبر قدر ممكن من البساطة - عن طريق إضافة قالب gitlab-ci.yml المعتاد وتحديد معلماته في مشروع GitLab CI.

تتمثل ميزة هذا النهج في أن البنية التحتية CI بأكملها ، ووكلاء التحميل ، وصور عامل التحميل لمصادر التحميل ، وخطوط أنابيب الاختبار ، ونشر التقارير يتم الاحتفاظ بها بواسطة قسم أتمتة مركزي (مهندسو DevOps) ، بينما يمكن لمهندسي اختبار الحمل تركيز جهودهم على تطوير الاختبار وتحليل نتائجها ، دون التعامل مع قضايا البنية التحتية.

لتبسيط الوصف ، سنفترض أن التطبيق المستهدف أو الخادم قيد الاختبار قد تم نشره بالفعل وتهيئته مسبقًا (يمكن استخدام البرامج النصية الآلية في Python و SaltStack و Ansible وما إلى ذلك لهذا الغرض). ثم يتناسب المفهوم الكامل لاختبار الحمل كخدمة في ثلاث مراحل: إعداد واختبار ونشر التقارير. مزيد من التفاصيل حول الرسم التخطيطي (كل الصور قابلة للنقر):

اختبار التحميل كخدمة CI للمطورين

المفاهيم والتعاريف الأساسية في اختبار الحمل

عند إجراء اختبارات الحمل ، نحاول الالتزام بها معايير ومنهجية ISTQB، استخدم المصطلحات المناسبة والمقاييس الموصى بها. سأقدم قائمة قصيرة بالمفاهيم والتعاريف الرئيسية في اختبار الحمل.

عامل تحميل - آلة افتراضية سيتم تشغيل التطبيق عليها - مصدر التحميل (Apache JMeter أو Yandex.Tank أو وحدة تحميل مكتوبة ذاتيًا).

هدف الاختبار (الهدف) - الخادم أو التطبيق المثبت على الخادم الذي سيخضع للتحميل.

سيناريو الاختبار (حالة الاختبار) - مجموعة من الخطوات ذات المعلمات: إجراءات المستخدم وردود الفعل المتوقعة على هذه الإجراءات ، مع طلبات واستجابات الشبكة الثابتة ، اعتمادًا على المعلمات المحددة.

الملف الشخصي أو خطة التحميل (الملف الشخصي) - في منهجية ISTQB (القسم 4.2.4 ، ص 43) تحدد ملفات تعريف الحمل المقاييس المهمة لاختبار معين وخيارات لتغيير معلمات الحمل أثناء الاختبار. يمكنك أن ترى أمثلة على الملفات الشخصية في الشكل.

اختبار التحميل كخدمة CI للمطورين

امتحان - نص مع مجموعة محددة سلفا من المعلمات.

خطة الاختبار (خطة الاختبار) - مجموعة من الاختبارات وملف تعريف الحمل.

تستران (تسترن) - تكرار واحد لتشغيل اختبار واحد مع سيناريو تحميل كامل التنفيذ والتقرير المستلم.

طلب الشبكة (طلب) - طلب HTTP مرسل من وكيل إلى هدف.

استجابة الشبكة (استجابة) - استجابة HTTP مرسلة من الهدف إلى الوكيل.
رمز استجابة HTTP (حالة استجابات HTTP) - رمز استجابة قياسي من خادم التطبيق.
المعاملة عبارة عن دورة كاملة للطلبات والردود. يتم احتساب المعاملة من بداية إرسال الطلب (الطلب) حتى اكتمال استلام الرد (الاستجابة).

حالة عملية - ما إذا كان من الممكن إكمال دورة الطلب والاستجابة بنجاح. إذا كان هناك أي خطأ في هذه الدورة ، فإن المعاملة بأكملها تعتبر غير ناجحة.

وقت الاستجابة (الكمون) - الوقت من نهاية إرسال الطلب (الطلب) إلى بداية تلقي الرد (الرد).

مقاييس التحميل - خصائص الخدمة المحملة وعامل الحمولة المحددة في عملية اختبار الحمل.

المقاييس الأساسية لقياس معلمات الحمل

بعض من الأكثر استخداما والموصى بها في المنهجية ISTQB (ص 36 ، 52) المقاييس موضحة في الجدول أدناه. يتم سرد مقاييس مماثلة للوكيل والهدف في نفس السطر.

مقاييس عامل التحميل
مقاييس النظام المستهدف أو التطبيق الذي يتم اختباره تحت الحمل

عدد  وحدة المعالجة المركزية الافتراضية والذاكرة رامات,
أسطوانة - خصائص عامل التحميل "الحديد"
وحدة المعالجة المركزية‏:, الذاكرة ، استخدام القرص - ديناميات وحدة المعالجة المركزية والذاكرة وتحميل القرص
في عملية الاختبار. عادة ما تقاس كنسبة مئوية من
الحد الأقصى للقيم المتاحة

صبيب الشبكة (على عامل التحميل) - الإنتاجية
واجهة الشبكة على الخادم ،
حيث تم تثبيت عامل التحميل.
يقاس عادةً بالبايت في الثانية (بت في الثانية)
صبيب الشبكة(على الهدف) - عرض النطاق الترددي لواجهة الشبكة
على الخادم الهدف. يقاس عادةً بالبايت في الثانية (بت في الثانية)

المستخدمون الافتراضيون- عدد المستخدمين الافتراضيين ،
تنفيذ سيناريوهات الحمل و
تقليد إجراءات المستخدم الحقيقية
حالة المستخدمين الافتراضية، ناجح / فاشل / إجمالي - عدد الناجحين و
الحالات غير الناجحة للمستخدمين الظاهري
لسيناريوهات التحميل ، بالإضافة إلى العدد الإجمالي لها.

من المتوقع عمومًا أن يتمكن جميع المستخدمين من إكمالها
كل ما تبذلونه من المهام المحددة في ملف تعريف التحميل.
أي خطأ يعني أن المستخدم الحقيقي لن يكون قادرًا على ذلك
حل مشكلتك عند العمل مع النظام

الطلبات في الثانية (دقيقة)- عدد طلبات الشبكة في الثانية (أو الدقيقة).

من السمات المهمة لعامل التحميل عدد الطلبات التي يمكنه إنشاؤها.
في الواقع ، يعد هذا تقليدًا لوصول مستخدمين افتراضيين إلى التطبيق
الردود في الثانية (دقيقة)
- عدد استجابات الشبكة في الثانية (أو الدقيقة).

خاصية مهمة للخدمة المستهدفة: كم
إنشاء وإرسال الردود على الاستفسارات مع
وكيل التحميل

حالة استجابة HTTP- عدد رموز الاستجابة المختلفة
من خادم التطبيق الذي استلمه وكيل التحميل.
على سبيل المثال ، 200 OK تعني مكالمة ناجحة ،
و 404 - أن المورد لم يتم العثور عليه

كمون (وقت الاستجابة) - الوقت من النهاية
إرسال طلب (طلب) قبل البدء في تلقي رد (استجابة).
يقاس عادةً بالمللي ثانية (مللي ثانية)

وقت استجابة المعاملة- وقت معاملة واحدة كاملة ،
إكمال دورة الطلب والرد.
هذا هو الوقت من بداية إرسال الطلب (الطلب)
حتى اكتمال استلام الرد (الرد).

يمكن قياس وقت المعاملة بالثواني (أو بالدقائق)
بعدة طرق: ضع في اعتبارك الحد الأدنى ،
الحد الأقصى والمتوسط ​​، وعلى سبيل المثال ، النسبة المئوية التسعون.
القراءات الدنيا والقصوى متطرفة
حالة أداء النظام.
النسبة المئوية التسعون هي الأكثر استخدامًا ،
كما يظهر لمعظم المستخدمين ،
تعمل بشكل مريح عند عتبة أداء النظام

المعاملات في الثانية (دقيقة) - العدد الكامل
المعاملات في الثانية (دقيقة) ،
أي ، إلى أي مدى كان التطبيق قادرًا على قبول و
معالجة الطلبات وإصدار الردود.
في الواقع ، هذا هو صبيب النظام

حالة عملية ، ناجح / فاشل / إجمالي - رقم
الناجحة وغير الناجحة والعدد الإجمالي للمعاملات.

للمستخدمين الحقيقيين غير ناجحة
الصفقة ستعني في الواقع
عدم القدرة على العمل مع النظام تحت الحمل

رسم تخطيطي لاختبار الحمل

مفهوم اختبار الحمل بسيط للغاية ويتكون من ثلاث مراحل رئيسية سبق أن ذكرتها: تحضير-اختبار-تقرير، أي إعداد أهداف الاختبار وتعيين المعلمات لمصادر التحميل ، ثم تنفيذ اختبارات الحمل ، وفي النهاية ، إنشاء تقرير اختبار ونشره.

اختبار التحميل كخدمة CI للمطورين

ملاحظات تخطيطية:

  • QA.Tester هو خبير في اختبار الحمل ،
  • الهدف هو التطبيق المستهدف الذي تريد معرفة سلوكه تحت الحمل.

تصنيف الكيانات والمراحل والخطوات في الرسم التخطيطي

المراحل والخطوات
ما الذي يحدث
ماذا يوجد عند المدخل
ما هو الناتج

التحضير: مرحلة التحضير للاختبار

تحميلالمعلمات
الإعداد والتهيئة
المستعمل
معلمات التحميل ،
اختيار المقاييس و
إعداد خطة الاختبار
(تحميل ملف)
خيارات مخصصة لـ
تهيئة عامل التحميل
خطة اختبار
الغرض من الاختبار

VM
نشر السحابة
آلة افتراضية مع
الخصائص المطلوبة
إعدادات VM لعامل التحميل
البرامج النصية للتشغيل الآلي لـ
إنشاء VM
تم تكوين VM بتنسيق
سحابة

الحياة الفطرية
إعداد وإعداد نظام التشغيل
البيئة ل
عامل تحميل العمل
إعدادات البيئة لـ
عامل تحميل
البرامج النصية للتشغيل الآلي لـ
إعدادات البيئة
البيئة المعدة:
نظام التشغيل والخدمات والتطبيقات ،
ضروري للعمل
عامل تحميل

وكلاء التحميل
التثبيت والتكوين والمعلمات
وكيل التحميل.
أو تنزيل صورة عامل ميناء من
مصدر تحميل تم تكوينه مسبقًا
تحميل صورة عامل إرساء المصدر
(YAT أو JM أو إطار عمل مكتوب ذاتيًا)
خيارات الإعدادات
عامل تحميل
انشاء وجاهز
للعمل تحميل عامل

الاختبار: مرحلة تنفيذ اختبارات الحمل. المصادر هي عوامل تحميل تم نشرها في مجموعات وكلاء مخصصة لـ GitLab CI

حمل
بدء عامل التحميل
مع خطة الاختبار المحددة
وتحميل المعلمات
خيارات المستخدم
للتهيئة
عامل تحميل
خطة اختبار
الغرض من الاختبار
سجلات التنفيذ
اختبارات الحمل
سجلات النظام
ديناميات التغييرات في مقاييس الهدف وعامل الحمولة

وكلاء التشغيل
وكيل التنفيذ
الكثير من نصوص الاختبار
وفقا لل
تحميل ملف
تفاعل وكيل التحميل
لغرض الاختبار
خطة اختبار
الغرض من الاختبار

سجلات
مجموعة من السجلات "الخام"
أثناء اختبار الحمل:
سجلات نشاط وكيل التحميل ،
حالة هدف الاختبار
و VM تشغيل الوكيل

سجلات التنفيذ
اختبارات الحمل
سجلات النظام

المقاييس
جمع المقاييس "الخام" أثناء الاختبار

ديناميات التغييرات في مقاييس الهدف
وعامل تحميل

التقرير: مرحلة إعداد تقرير الاختبار

مولد كهرباء
جمعت المعالجة
نظام التحميل و
نظام مراقبة "خام"
المقاييس والسجلات
تشكيل تقرير في
شكل يمكن قراءته من قبل الإنسان
ممكن مع العناصر
محللون
سجلات التنفيذ
اختبارات الحمل
سجلات النظام
ديناميات التغييرات في المقاييس
الهدف وعامل التحميل
معالجة السجلات "الأولية"
بتنسيق مناسب ل
عمليات التحميل إلى وحدة التخزين الخارجية
تقرير الحمل الثابت ،
انسان قارئ

نشر
نشر التقرير
حول الحمل
الاختبار في الخارج
خدمة
معالجتها "خام"
سجلات بتنسيق مناسب
للتفريغ الخارجي
مستودعات
تم الحفظ في الخارج
تقارير التخزين على
تحميل مناسب
للتحليل البشري

ربط مصادر التحميل في قالب CI

دعنا ننتقل إلى الجزء العملي. أريد أن أوضح كيف في بعض المشاريع في الشركة تقنيات إيجابية لقد قمنا بتنفيذ مفهوم اختبار الحمل كخدمة.

أولاً ، بمساعدة مهندسي DevOps ، أنشأنا مجموعة مخصصة من الوكلاء في GitLab CI لإجراء اختبارات التحميل. من أجل عدم الخلط بينهم في القوالب مع الآخرين ، مثل تجمعات التجميع ، أضفنا علامات إلى هؤلاء الوكلاء ، علامات: حمولة. يمكنك استخدام أي علامات أخرى مفهومة. هم يسألون أثناء التسجيل العدائين GitLab CI.

كيف تعرف الطاقة المطلوبة من خلال الأجهزة؟ يمكن حساب خصائص عوامل التحميل - عدد كافٍ من وحدة المعالجة المركزية الافتراضية وذاكرة الوصول العشوائي والقرص - بناءً على حقيقة أن Docker و Python (لـ Yandex.Tank) و GitLab CI agent و Java (لـ Apache JMeter) يجب أن تعمل على الوكيل . بالنسبة إلى Java ضمن JMeter ، يوصى أيضًا باستخدام 512 ميغابايت كحد أدنى من ذاكرة الوصول العشوائي وكحد أعلى ، 80٪ ذاكرة متوفرة.

وبالتالي ، بناءً على تجربتنا ، نوصي باستخدام ما لا يقل عن 4 وحدات معالجة مركزية (vCPU) ، وذاكرة وصول عشوائي (RAM) سعة 4 جيجابايت ، و 60 جيجابايت SSD لوكلاء التحميل. يتم تحديد معدل نقل بطاقة الشبكة بناءً على متطلبات ملف تعريف التحميل.

نحن نستخدم بشكل أساسي مصدرين للتحميل - Apache JMeter و Yandex.Tank docker images.

ياندكس هي أداة مفتوحة المصدر من Yandex لاختبار الحمل. تعتمد بنيتها المعيارية على مولد طلبات HTTP غير المتزامن عالي الأداء من Phantom. يحتوي الخزان على مراقبة مدمجة لموارد الخادم قيد الاختبار عبر بروتوكول SSH ، ويمكنه إيقاف الاختبار تلقائيًا في ظل ظروف محددة ، ويمكنه عرض النتائج في كل من وحدة التحكم وفي شكل رسوم بيانية ، يمكنك توصيل الوحدات النمطية الخاصة بك لتوسيع الوظائف. بالمناسبة ، استخدمنا الخزان عندما لم يكن سائدًا بعد. في المقالة "Yandex.Tank وأتمتة اختبار الأحمال»يمكنك قراءة قصة كيفية إجرائنا لاختبار الحمل معه في عام 2013 جدار حماية تطبيق PT هو أحد منتجات شركتنا.

أباتشي جيميتر هي أداة اختبار تحميل مفتوحة المصدر من Apache. يمكن استخدامه بشكل جيد على حد سواء لاختبار تطبيقات الويب الثابتة والديناميكية. يدعم JMeter عددًا كبيرًا من البروتوكولات وطرق التفاعل مع التطبيقات: HTTP ، HTTPS (Java ، NodeJS ، PHP ، ASP.NET ، إلخ) ، SOAP / REST Webservices ، FTP ، TCP ، LDAP ، SMTP (S) ، POP3 ( S)) و IMAP (S) وقواعد البيانات عبر JDBC ، يمكنها تنفيذ أوامر shell والعمل مع كائنات Java. لدى JMeter IDE لإنشاء خطط الاختبار وتصحيحها وتنفيذها. يوجد أيضًا CLI لتشغيل سطر الأوامر على أي نظام تشغيل متوافق مع Java (Linux و Windows و Mac OS X). يمكن للأداة إنشاء تقرير اختبار HTML ديناميكيًا.

لسهولة الاستخدام داخل شركتنا ، من أجل قدرة المختبرين أنفسهم على تغيير البيئة وإضافتها ، قمنا ببناء صور عامل ميناء لمصادر التحميل على GitLab CI مع النشر إلى الداخل سجل عامل ميناء في Artifactory. هذا يجعل من الأسرع والأسهل توصيلها في خطوط الأنابيب لاختبارات الحمل. كيفية القيام بدفع عامل الإرساء للتسجيل عبر GitLab CI - انظر تعليمات.

أخذنا ملف عامل الإرساء الأساسي هذا لـ Yandex.Tank:

Dockerfile 
1 | FROM direvius/yandex-tank
2 | ENTRYPOINT [""]

ولأباتشي جي ميتر هذا:

Dockerfile 
1 | FROM vmarrazzo/jmeter
2 | ENTRYPOINT [""]

يمكنك قراءة كيفية عمل نظام التكامل المستمر لدينا في المقالة "أتمتة عمليات التطوير: كيف نفذنا أفكار DevOps في شركة Positive Technologies".

القالب وخط الأنابيب

مثال على نموذج لإجراء اختبارات الحمل متاح في المشروع تحميل تجريبي. في الملف التمهيدي يمكنك قراءة التعليمات الخاصة باستخدام النموذج. في القالب نفسه (ملف .gitlab-ci.yml) هناك ملاحظات حول مسئولية كل خطوة.

النموذج بسيط للغاية ويوضح المراحل الثلاث لاختبار الحمل الموضحة في الرسم البياني أعلاه: إعداد التقارير واختبارها ونشرها. المسؤول عن هذا مراحل: التحضير والاختبار والإبلاغ.

  1. مرحلة إعداد يجب استخدامها للتكوين المسبق لأهداف الاختبار أو التحقق من توفرها. لا تحتاج بيئة مصادر التحميل إلى التهيئة ، فهي مبنية مسبقًا كصور عامل إرساء ويتم نشرها في سجل عامل التحميل: ما عليك سوى تحديد الإصدار المطلوب في مرحلة الاختبار. ولكن يمكنك إعادة بنائها وإنشاء صورك المعدلة.
  2. مرحلة اختبار تُستخدم لتحديد مصدر التحميل وتشغيل الاختبارات وتخزين عناصر الاختبار. يمكنك اختيار أي مصدر تحميل: Yandex.Tank أو Apache JMeter أو الخاص بك أو جميعها معًا. لتعطيل المصادر غير الضرورية ، ما عليك سوى التعليق أو حذف الوظيفة. نقاط الدخول لمصادر التحميل:

    ملاحظة: يتم استخدام قالب تكوين التجميع لإعداد التفاعل مع نظام CI ولا يعني وضع منطق الاختبار فيه. بالنسبة للاختبارات ، يتم تحديد نقطة الإدخال ، حيث يوجد البرنامج النصي control bash. يجب تنفيذ طريقة إجراء الاختبارات وإنشاء التقارير ونصوص الاختبار نفسها بواسطة مهندسي ضمان الجودة. في العرض التوضيحي ، لكلا مصدري التحميل ، يتم استخدام طلب صفحة Yandex الرئيسية كأبسط اختبار. البرامج النصية ومعلمات الاختبار موجودة في الدليل ./الاختبارات.

  3. في هذه المرحلة بلغ تحتاج إلى وصف كيفية نشر نتائج الاختبار التي تم الحصول عليها في مرحلة الاختبار إلى المستودعات الخارجية ، على سبيل المثال ، في صفحات GitLab أو أنظمة إعداد التقارير الخاصة. تتطلب صفحات GitLab ألا يكون الدليل ./public فارغًا وأن يحتوي على ملف index.html على الأقل بعد انتهاء الاختبارات. يمكنك أن تقرأ عن الفروق الدقيقة في خدمة صفحات GitLab. رابط.

    أمثلة على كيفية تصدير البيانات:

    إرشادات إعداد النشر:

في المثال التوضيحي ، يبدو خط الأنابيب الذي يحتوي على اختبارات الحمل ومصادرين للتحميل (يمكنك تعطيل المصدر غير الضروري) كما يلي:

اختبار التحميل كخدمة CI للمطورين

يمكن لـ Apache JMeter إنشاء تقرير HTML بنفسه ، لذلك يكون حفظه في GitLab Pages باستخدام الأدوات القياسية أكثر ربحية. هكذا يبدو تقرير Apache JMeter:

اختبار التحميل كخدمة CI للمطورين

في المثال التوضيحي لـ Yandex.Tank ، سترى فقط ملفات تقرير نص مزيف في قسم صفحات GitLab. أثناء الاختبار ، يمكن لـ Tank حفظ النتائج في قاعدة بيانات InfluxDB ، ومن هناك يمكن عرضها ، على سبيل المثال ، في Grafana (يتم التكوين في الملف ./tests/example-yandextank-test.yml). هكذا يبدو تقرير تانك في جرافانا:

اختبار التحميل كخدمة CI للمطورين

ملخص

تحدثت في المقال عن مفهوم "اختبار الحمل كخدمة" (اختبار الحمل كخدمة). الفكرة الرئيسية هي استخدام البنية التحتية لمجموعات عوامل التحميل التي تم تكوينها مسبقًا وصور عامل التحميل لمصادر التحميل وأنظمة التقارير وخط الأنابيب الذي يجمعها في GitLab CI استنادًا إلى نموذج .gitlab-ci.yml بسيط (مثال رابط). كل هذا مدعوم من قبل فريق صغير من مهندسي الأتمتة ويتم تكراره بناءً على طلب فرق المنتج. آمل أن يساعدك هذا في إعداد وتنفيذ مخطط مماثل في شركتك. أشكر لك إهتمامك!

ملاحظة: أود أن أتقدم بالشكر الجزيل لزملائي ، سيرجي كوربانوف ونيكولاي يوسيف ، على المساعدة الفنية في تنفيذ مفهوم اختبار الحمل كخدمة في شركتنا.

مؤلف: تيمور جيلمولين - نائب رئيس عمليات التكنولوجيا والتطوير (DevOps) في شركة Positive Technologies

المصدر: www.habr.com

إضافة تعليق