diff --git a/README.md b/README.md index cbf1186..47a0429 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ docker compose up * `/` - интерфейс * `/api/v1/docs` - swagger-ui документация * `/admin/` - админка -* `/admin/grafana` - графана +* `/admin/grafana` - Grafana * `/docs` - обучающие материалы по анализу данных После запуска по методу выше создается пользователь в админке (`/admin/`) с данными ниже: @@ -23,6 +23,11 @@ docker compose up * `admin` - логин * `prooooooood` - пароль +Данные для Grafana: + +* `admin` - логин +* `proooooood` - пароль + ## Как устроен проект В проекте используются 3 основных модуля: backend, frontend и checker @@ -31,20 +36,20 @@ docker compose up Сам бекенд состоит из 2-х основных компонентов: приложений (где хранятся модели, тесты и настройки админ-панели) и основных колбеков (где хранятся схемы OpenAPI и сами ручки) - Решения на проверку отсылаются через `celery` для асинхронного взаимодействия, так как его ожидание может занять довольно длительное время. + Решения на проверку отсылаются через `celery` для асинхронного взаимодействия. 2. `frontend` является React приложением, которое запускается через Vite. В нем также используется TypeScript для более строгой типизации. Структура приложения является стандартной для подобного вида проектов: есть отдельная папка для компонентов, страниц, стилей, работы с API. 3. `checker` - микросервис на FastAPI, созданный для безопасного асинхронного запуска посылок пользователей. - Данные в этот сервис отсылаются по специальной ручке `/execute`, которая является приватной (ее нет в документации) + Данные в этот сервис отсылаются по специальной ручке `/execute`. - Проверка заданий осуществляется через запуск кода пользователя через специально создаваемый Docker контейнер, на который выдаются следующие ресурсы: + Проверка заданий осуществляется через запуск кода пользователя через Docker контейнер, на который выдаются следующие ресурсы: -* 1 ядро CPU -* 1 ГБ ОЗУ +* 50% одного ядра +* 100 МБ ОЗУ - Для приближения к условиям работы аналитиков в интерпритаторе Python есть следующие библиотеки: + Решению доступны следующие библиотеки для работы с данными: ```python pandas==2.2.3 @@ -56,7 +61,7 @@ docker compose up statsmodels==0.14.4 ``` - Контейнеру дается 1 минута на выполнение кода, потом - контейнер удаляется + Контейнеру дается 1 минута на выполнение кода, потом - контейнер удаляется. ## Тесты @@ -64,10 +69,12 @@ docker compose up Unit-тесты находятся в соответствующих приложениях, которые располагаются по пути `services/backend/apps` -JSON коллекция, в которой хранятся E2E тесты, находится по пути `img/postman_e2e.json`. Ее можно импортировать в постман, нажав на соответсвующую кнопку в интерфейсе Postman +Postman коллекция, c E2E тестами: [tests/postman_collection.json](./tests/postman_collection.json) -![Postman data](img/postman.gif) +Запуск Postman коллекции: -Ниже можно увидеть Coverage тестами бекенда данного приложения +![postman collection run](./assets/gif/postman_collection_run.gif) -![django test](img/superduperdjangotests.png) +Покрытие тестами бекенда данного приложения: + +![backend tests coverage](./assets/img/backend_coverage.png) diff --git a/img/postman.gif b/assets/gif/postman_collection_run.gif similarity index 100% rename from img/postman.gif rename to assets/gif/postman_collection_run.gif diff --git a/img/superduperdjangotests.png b/assets/img/backend_coverage.png similarity index 100% rename from img/superduperdjangotests.png rename to assets/img/backend_coverage.png diff --git a/img/postman_e2e.json b/img/postman_e2e.json deleted file mode 100644 index d4e10d9..0000000 --- a/img/postman_e2e.json +++ /dev/null @@ -1,768 +0,0 @@ -{ - "info": { - "_postman_id": "fd33ed4f-84b5-4045-b926-22d989876fb0", - "name": "Datarush tests", - "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json", - "_exporter_id": "29887339" - }, - "item": [ - { - "name": "User", - "item": [ - { - "name": "Correct registration", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "// Генерация случайных данных\r", - "const randomNamePrefix = `company_${Math.random().toString(36).substring(2, 8)}`;\r", - "const randomUsername = `${Math.random().toString(36).substring(3, 9)}`\r", - "const randomEmail = `${Math.random().toString(36).substring(2, 8)}@timka.test`;\r", - "const randomPassword = `${Math.random().toString(36).substring(2, 12)}!A1`;\r", - "\r", - "// Формирование тела запроса\r", - "const requestData = {\r", - " username: randomUsername,\r", - " email: randomEmail,\r", - " password: randomPassword\r", - "};\r", - "\r", - "// Сохранение данных в переменные окружения\r", - "pm.environment.set(\"randomNamePrefix\", randomNamePrefix);\r", - "pm.environment.set(\"randomEmail\", randomEmail);\r", - "pm.environment.set(\"randomPassword\", randomPassword);\r", - "pm.environment.set(\"randomUsername\", randomUsername)\r", - "\r", - "// Сохранение JSON-объекта в переменную для дальнейшего использования\r", - "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", - "pm.environment.set(\"requestNameREGISTRATION\", JSON.stringify(randomNamePrefix));\r", - "pm.environment.set(\"requestEmailREGISTRATION\", JSON.stringify(randomEmail));\r", - "pm.environment.set(\"requestusernameREGISTRATION\", JSON.stringify(randomUsername))\r", - "pm.environment.set(\"requestPasswordREGISTRATION\", JSON.stringify(randomPassword));" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 201', function () {\r", - " pm.response.to.have.status(201);\r", - "});\r", - "\r", - "pm.test('Response has token', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData.token).to.be.a('string');\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{{requestData}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": "{{BASE_HOST}}/v1/sign-up" - }, - "response": [] - }, - { - "name": "Correct sign in", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const email = pm.environment.get(\"randomEmail\")\r", - "const password = pm.environment.get(\"randomPassword\")\r", - "\r", - "const requestData = {\r", - " email: email,\r", - " password: password\r", - "}\r", - "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has token', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData.token).to.be.a('string');\r", - " pm.environment.set(\"token\", jsonData.token)\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{{requestData}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": "{{BASE_HOST}}/v1/sign-in" - }, - "response": [] - }, - { - "name": "Duplicated reg data", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const email = pm.environment.get(\"randomEmail\")\r", - "const password = pm.environment.get(\"randomPassword\")\r", - "const username = pm.environment.get(\"randomUsername\")\r", - "\r", - "const requestData = {\r", - " email: email,\r", - " password: password,\r", - " username: username\r", - "}\r", - "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 409', function () {\r", - " pm.response.to.have.status(409);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{{requestData}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": "{{BASE_HOST}}/v1/sign-up" - }, - "response": [] - }, - { - "name": "Reg without username", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const email = pm.environment.get(\"randomEmail\")\r", - "const password = pm.environment.get(\"randomPassword\")\r", - "\r", - "const requestData = {\r", - " email: email,\r", - " password: password\r", - "}\r", - "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 400', function () {\r", - " pm.response.to.have.status(400);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{{requestData}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": "{{BASE_HOST}}/v1/sign-up" - }, - "response": [] - } - ] - }, - { - "name": "Competitions", - "item": [ - { - "name": "Get competition with no partipication", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has only 2 elements', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.has.length(2,\"Response has non-2 length, try to reset to only test data state\");\r", - " pm.environment.set(\"competition_id\", jsonData[0].id)\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{BASE_HOST}}/v1/competitions?is_participating=false", - "host": [ - "{{BASE_HOST}}" - ], - "path": [ - "v1", - "competitions" - ], - "query": [ - { - "key": "is_participating", - "value": "false" - } - ] - } - }, - "response": [] - }, - { - "name": "Get competition with partipication", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has only 2 elements', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.has.length(0,\"Response has non-0 length, try to reset to only test data state\");\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{BASE_HOST}}/v1/competitions?is_participating=true", - "host": [ - "{{BASE_HOST}}" - ], - "path": [ - "v1", - "competitions" - ], - "query": [ - { - "key": "is_participating", - "value": "true" - } - ] - } - }, - "response": [] - }, - { - "name": "Get tasks without partipicating in test", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 403', function () {\r", - " pm.response.to.have.status(403);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "GET", - "header": [], - "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks" - }, - "response": [] - }, - { - "name": "Submit task sol without partipicaating", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 403', function () {\r", - " pm.response.to.have.status(403);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "file", - "type": "file", - "src": "/C:/Users/timka/AppData/Local/Postman/app-11.33.4/libGLESv2.dll" - } - ] - }, - "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/submit" - }, - "response": [] - }, - { - "name": "Partipicate in competition", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "POST", - "header": [], - "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/start" - }, - "response": [] - }, - { - "name": "Get competition tasks", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has tasks', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.environment.set(\"task_id\", jsonData[0].id)\r", - " pm.expect(jsonData).to.has.length(9)\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "GET", - "header": [], - "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks" - }, - "response": [] - }, - { - "name": "Get task history", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has token', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.has.length(0);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "GET", - "header": [], - "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/history" - }, - "response": [] - }, - { - "name": "Submit task sol", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has submission id', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData.submission_id).to.be.a('string');\r", - " pm.environment.set(\"sub_id\", jsonData.submission_id)\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "file", - "type": "file", - "src": "/C:/Users/timka/AppData/Local/Postman/app-11.33.4/libGLESv2.dll" - } - ] - }, - "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/submit" - }, - "response": [] - }, - { - "name": "Get task attachments", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has empty array', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.has.length(0);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": { - "token": "{{token}}" - } - }, - "method": "GET", - "header": [], - "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/attachments" - }, - "response": [] - } - ] - }, - { - "name": "Revieews", - "item": [ - { - "name": "Get reviewer profile", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has correct data', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData.name).to.eq(pm.environment.get(\"reviewer_name\"));\r", - " pm.expect(jsonData.surname).to.eq(pm.environment.get(\"reviewer_surname\"))\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": "{{BASE_HOST}}/v1/review/{{reviewer_key}}" - }, - "response": [] - }, - { - "name": "Get submissions", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test('Response has correct data', function () {\r", - " const jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.has.length(0)\r", - "});\r", - "\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": "{{BASE_HOST}}/v1/review/{{reviewer_key}}/submissions/{{sub_id}}" - }, - "response": [] - } - ] - }, - { - "name": "Healthcheck", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test('Status code is 200', function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{BASE_HOST}}/health?format=json", - "host": [ - "{{BASE_HOST}}" - ], - "path": [ - "health" - ], - "query": [ - { - "key": "format", - "value": "json" - } - ] - } - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "packages": {}, - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "packages": {}, - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "BASE_HOST", - "value": "https://datarush.itqdev.xyz/api", - "type": "string" - }, - { - "key": "requestData", - "value": "", - "type": "string" - }, - { - "key": "token", - "value": "", - "type": "string" - }, - { - "key": "competition_id", - "value": "", - "type": "string" - }, - { - "key": "task_id", - "value": "", - "type": "string" - }, - { - "key": "reviewer_key", - "value": "", - "type": "string" - }, - { - "key": "reviewer_name", - "value": "", - "type": "string" - }, - { - "key": "reviewer_surname", - "value": "", - "type": "string" - }, - { - "key": "sub_id", - "value": "", - "type": "string" - } - ] -} \ No newline at end of file diff --git a/infrastructure/backend/.env.template b/infrastructure/backend/.env.template index a0fe19f..6087565 100644 --- a/infrastructure/backend/.env.template +++ b/infrastructure/backend/.env.template @@ -1,6 +1,6 @@ -DJANGO_SECRET_KEY=secretees +DJANGO_SECRET_KEY=Ix22XEoVEHw8fp7yTNWFsrTgsYBCMEraDqA7yFOH DJANGO_DEBUG=False -DJANGO_ALLOWED_HOSTS=* +DJANGO_ALLOWED_HOSTS=datarush.itqdev.xyz DJANGO_CSRF_TRUSTED_ORIGINS=http://localhost,http://127.0.0.1,https://datarush.itqdev.xyz DJANGO_CORS_ALLOWED_ORIGINS=* DJANGO_INTERNAL_IPS=127.0.0.1 diff --git a/infrastructure/grafana/provisioning/dashboards/providers.yaml b/infrastructure/grafana/provisioning/dashboards/providers.yaml index 2a70839..3f33a63 100644 --- a/infrastructure/grafana/provisioning/dashboards/providers.yaml +++ b/infrastructure/grafana/provisioning/dashboards/providers.yaml @@ -1,7 +1,7 @@ apiVersion: 1 providers: - - name: "celery" + - name: "provisioning" orgId: 1 folder: "" type: file diff --git a/services/backend/README.md b/services/backend/README.md index 2fdef57..41c892e 100644 --- a/services/backend/README.md +++ b/services/backend/README.md @@ -15,13 +15,13 @@ Ensure you have the following installed on your system: #### Clone the project ```bash -git clone git@gitlab.com:megazordpobeda/DataRush.git +git clone https://gitlab.com/megazordpobeda/DataRush.git ``` #### Go to the project directory ```bash -cd project/services/backend +cd DataRush/services/backend ``` #### Customize environment @@ -79,13 +79,13 @@ uv run gunicorn config.wsgi ### Clone the project ```bash -git clone git@gitlab.com:megazordpobeda/DataRush.git +git clone https://gitlab.com/megazordpobeda/DataRush.git ``` ### Go to the project directory ```bash -cd project/services/backend +cd DataRush/services/backend ``` ### Build docker image @@ -119,13 +119,13 @@ Backend will be available on [127.0.0.1:8080](http://127.0.0.1:8080). ### Clone the project ```bash -git clone git@gitlab.com:megazordpobeda/DataRush.git +git clone https://gitlab.com/megazordpobeda/DataRush.git ``` ### Go to the project directory ```bash -cd project/services/backend +cd DataRush/services/backend ``` ### Install dependencies diff --git a/services/checker/README.md b/services/checker/README.md index 3af2885..73b7226 100644 --- a/services/checker/README.md +++ b/services/checker/README.md @@ -15,13 +15,13 @@ Ensure you have the following installed on your system: #### Clone the project ```bash -git clone git@gitlab.com:megazordpobeda/DataRush.git +git clone https://gitlab.com/megazordpobeda/DataRush.git ``` #### Go to the project directory ```bash -cd project/services/checker +cd DataRush/services/checker ``` #### Install dependencies @@ -71,13 +71,13 @@ uv run gunicorn config.wsgi ### Clone the project ```bash -git clone git@gitlab.com:megazordpobeda/DataRush.git +git clone https://gitlab.com/megazordpobeda/DataRush.git ``` ### Go to the project directory ```bash -cd project/services/checker +cd DataRush/services/checker ``` ### Build docker image diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 1b873ae..72d104d 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -16,13 +16,13 @@ Plese note that containers will use ports from 13241 to 13245 and 8080, so there ## Clone the project ```bash -git clone git@gitlab.com:megazordpobeda/DataRush.git +git clone https://gitlab.com/megazordpobeda/DataRush.git ``` ## Go to the project directory ```bash -cd devitq/solution/tests/e2e +cd DataRush/solution/tests/e2e ``` ## Install dependencies diff --git a/tests/postman_collection.json b/tests/postman_collection.json new file mode 100644 index 0000000..8893297 --- /dev/null +++ b/tests/postman_collection.json @@ -0,0 +1,750 @@ +{ + "info": { + "_postman_id": "fd33ed4f-84b5-4045-b926-22d989876fb0", + "name": "Datarush tests", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json", + "_exporter_id": "29887339" + }, + "item": [ + { + "name": "User", + "item": [ + { + "name": "Correct registration", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "// Генерация случайных данных\r", + "const randomNamePrefix = `company_${Math.random().toString(36).substring(2, 8)}`;\r", + "const randomUsername = `${Math.random().toString(36).substring(3, 9)}`\r", + "const randomEmail = `${Math.random().toString(36).substring(2, 8)}@timka.test`;\r", + "const randomPassword = `${Math.random().toString(36).substring(2, 12)}!A1`;\r", + "\r", + "// Формирование тела запроса\r", + "const requestData = {\r", + " username: randomUsername,\r", + " email: randomEmail,\r", + " password: randomPassword\r", + "};\r", + "\r", + "// Сохранение данных в переменные окружения\r", + "pm.environment.set(\"randomNamePrefix\", randomNamePrefix);\r", + "pm.environment.set(\"randomEmail\", randomEmail);\r", + "pm.environment.set(\"randomPassword\", randomPassword);\r", + "pm.environment.set(\"randomUsername\", randomUsername)\r", + "\r", + "// Сохранение JSON-объекта в переменную для дальнейшего использования\r", + "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", + "pm.environment.set(\"requestNameREGISTRATION\", JSON.stringify(randomNamePrefix));\r", + "pm.environment.set(\"requestEmailREGISTRATION\", JSON.stringify(randomEmail));\r", + "pm.environment.set(\"requestusernameREGISTRATION\", JSON.stringify(randomUsername))\r", + "pm.environment.set(\"requestPasswordREGISTRATION\", JSON.stringify(randomPassword));" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 201', function () {\r", + " pm.response.to.have.status(201);\r", + "});\r", + "\r", + "pm.test('Response has token', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData.token).to.be.a('string');\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{requestData}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{BASE_HOST}}/v1/sign-up" + }, + "response": [] + }, + { + "name": "Correct sign in", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const email = pm.environment.get(\"randomEmail\")\r", + "const password = pm.environment.get(\"randomPassword\")\r", + "\r", + "const requestData = {\r", + " email: email,\r", + " password: password\r", + "}\r", + "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has token', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData.token).to.be.a('string');\r", + " pm.environment.set(\"token\", jsonData.token)\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{requestData}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{BASE_HOST}}/v1/sign-in" + }, + "response": [] + }, + { + "name": "Duplicated reg data", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const email = pm.environment.get(\"randomEmail\")\r", + "const password = pm.environment.get(\"randomPassword\")\r", + "const username = pm.environment.get(\"randomUsername\")\r", + "\r", + "const requestData = {\r", + " email: email,\r", + " password: password,\r", + " username: username\r", + "}\r", + "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 409', function () {\r", + " pm.response.to.have.status(409);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{requestData}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{BASE_HOST}}/v1/sign-up" + }, + "response": [] + }, + { + "name": "Reg without username", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const email = pm.environment.get(\"randomEmail\")\r", + "const password = pm.environment.get(\"randomPassword\")\r", + "\r", + "const requestData = {\r", + " email: email,\r", + " password: password\r", + "}\r", + "pm.environment.set(\"requestData\", JSON.stringify(requestData));\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 400', function () {\r", + " pm.response.to.have.status(400);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{{requestData}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{BASE_HOST}}/v1/sign-up" + }, + "response": [] + } + ] + }, + { + "name": "Competitions", + "item": [ + { + "name": "Get competition with no partipication", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has only 2 elements', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.has.length(2,\"Response has non-2 length, try to reset to only test data state\");\r", + " pm.environment.set(\"competition_id\", jsonData[0].id)\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{BASE_HOST}}/v1/competitions?is_participating=false", + "host": ["{{BASE_HOST}}"], + "path": ["v1", "competitions"], + "query": [ + { + "key": "is_participating", + "value": "false" + } + ] + } + }, + "response": [] + }, + { + "name": "Get competition with partipication", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has only 2 elements', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.has.length(0,\"Response has non-0 length, try to reset to only test data state\");\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{BASE_HOST}}/v1/competitions?is_participating=true", + "host": ["{{BASE_HOST}}"], + "path": ["v1", "competitions"], + "query": [ + { + "key": "is_participating", + "value": "true" + } + ] + } + }, + "response": [] + }, + { + "name": "Get tasks without partipicating in test", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "GET", + "header": [], + "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks" + }, + "response": [] + }, + { + "name": "Submit task sol without partipicaating", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "file", + "type": "file", + "src": "/C:/Users/timka/AppData/Local/Postman/app-11.33.4/libGLESv2.dll" + } + ] + }, + "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/submit" + }, + "response": [] + }, + { + "name": "Partipicate in competition", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "POST", + "header": [], + "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/start" + }, + "response": [] + }, + { + "name": "Get competition tasks", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has tasks', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.environment.set(\"task_id\", jsonData[0].id)\r", + " pm.expect(jsonData).to.has.length(9)\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "GET", + "header": [], + "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks" + }, + "response": [] + }, + { + "name": "Get task history", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has token', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.has.length(0);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "GET", + "header": [], + "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/history" + }, + "response": [] + }, + { + "name": "Submit task sol", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has submission id', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData.submission_id).to.be.a('string');\r", + " pm.environment.set(\"sub_id\", jsonData.submission_id)\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "file", + "type": "file", + "src": "/C:/Users/timka/AppData/Local/Postman/app-11.33.4/libGLESv2.dll" + } + ] + }, + "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/submit" + }, + "response": [] + }, + { + "name": "Get task attachments", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has empty array', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.has.length(0);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "{{token}}" + } + }, + "method": "GET", + "header": [], + "url": "{{BASE_HOST}}/v1/competitions/{{competition_id}}/tasks/{{task_id}}/attachments" + }, + "response": [] + } + ] + }, + { + "name": "Revieews", + "item": [ + { + "name": "Get reviewer profile", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has correct data', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData.name).to.eq(pm.environment.get(\"reviewer_name\"));\r", + " pm.expect(jsonData.surname).to.eq(pm.environment.get(\"reviewer_surname\"))\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": "{{BASE_HOST}}/v1/review/{{reviewer_key}}" + }, + "response": [] + }, + { + "name": "Get submissions", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test('Response has correct data', function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.has.length(0)\r", + "});\r", + "\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": "{{BASE_HOST}}/v1/review/{{reviewer_key}}/submissions/{{sub_id}}" + }, + "response": [] + } + ] + }, + { + "name": "Healthcheck", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{BASE_HOST}}/health?format=json", + "host": ["{{BASE_HOST}}"], + "path": ["health"], + "query": [ + { + "key": "format", + "value": "json" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [""] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [""] + } + } + ], + "variable": [ + { + "key": "BASE_HOST", + "value": "https://datarush.itqdev.xyz/api", + "type": "string" + }, + { + "key": "requestData", + "value": "", + "type": "string" + }, + { + "key": "token", + "value": "", + "type": "string" + }, + { + "key": "competition_id", + "value": "", + "type": "string" + }, + { + "key": "task_id", + "value": "", + "type": "string" + }, + { + "key": "reviewer_key", + "value": "", + "type": "string" + }, + { + "key": "reviewer_name", + "value": "", + "type": "string" + }, + { + "key": "reviewer_surname", + "value": "", + "type": "string" + }, + { + "key": "sub_id", + "value": "", + "type": "string" + } + ] +}