aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SCHEMA.md17
-rw-r--r--backend/routes/forms/submit.py34
-rw-r--r--backend/routes/forms/unittesting.py7
3 files changed, 49 insertions, 9 deletions
diff --git a/SCHEMA.md b/SCHEMA.md
index 57c238a..93be830 100644
--- a/SCHEMA.md
+++ b/SCHEMA.md
@@ -169,10 +169,25 @@ Textareas require no additional configuration.
| `_id`/`id` | MongoDB ObjectID | Random identifier used for the response |
| `user` | Optional [user details object](#user-details-object) | An object describing the user that submitted if the form is not anonymous |
| `antispam` | Optional [anti spam object](#anti-spam-object) | An object containing information about the anti-spam on the form submission |
-| `response` | Object | Object containing question IDs mapping to the users answer |
+| `response` | Object | Object containing question IDs mapping to the users answer* |
| `form_id` | String | ID of the form that the user is submitting to |
| `timestamp` | String | ISO formatted string of submission time. |
+
+ * If the question is of type `code`, the response has the following structure:
+```json
+"response": {
+ "<QUESTION ID>": {
+ "value": "<USER CODE>",
+ "passed": bool,
+ "failures": ["<TEST NAME 1>", "<TEST NAME 4>", "<HIDDEN TEST 1>", ...]
+ },
+ ...
+}
+```
+* Values in `<>` are placeholders, while the rest are actual keys
+* `passed` is True only if all tests in the suite passed.
+
### User details object
The user details contains the information returned by Discord alongside an `admin` boolean key representing that the user has admin privileges. The information returned from Discord can be found in the [Discord Developer portal](https://discord.com/developers/docs/resources/user#user-object).
diff --git a/backend/routes/forms/submit.py b/backend/routes/forms/submit.py
index c0a50f3..97cf2ac 100644
--- a/backend/routes/forms/submit.py
+++ b/backend/routes/forms/submit.py
@@ -168,16 +168,38 @@ class SubmitForm(Route):
if any("unittests" in question.data for question in form.questions):
unittest_results = await execute_unittest(response_obj, form)
- if not all(test.passed for test in unittest_results):
- # Return 500 if we encountered an internal error (code 99).
- status_code = 500 if any(
- test.return_code == 99 for test in unittest_results
- ) else 403
+ failures = []
+ status_code = 403
+ for test in unittest_results:
+ response_obj.response[test.question_id] = {
+ "value": response_obj.response[test.question_id],
+ "passed": test.passed
+ }
+
+ if test.return_code == 0:
+ test_names = [] if test.passed else test.result.split(";")
+ response_obj.response[test.question_id]["failures"] = test_names
+
+ # Report a failure on internal errors,
+ # or if the test suite doesn't allow failures
+ if not test.passed:
+ allow_failure = (
+ form.questions[test.question_index].data["unittests"]["allow_failure"]
+ )
+
+ if test.return_code == 99:
+ failures.append(test)
+ status_code = 500
+
+ elif not allow_failure:
+ failures.append(test)
+
+ if len(failures):
return JSONResponse({
"error": "failed_tests",
"test_results": [
- test._asdict() for test in unittest_results if not test.passed
+ test._asdict() for test in failures
]
}, status_code=status_code)
diff --git a/backend/routes/forms/unittesting.py b/backend/routes/forms/unittesting.py
index 590cb52..c23ff48 100644
--- a/backend/routes/forms/unittesting.py
+++ b/backend/routes/forms/unittesting.py
@@ -7,13 +7,15 @@ import httpx
from httpx import HTTPStatusError
from backend.constants import SNEKBOX_URL
-from backend.models import FormResponse, Form
+from backend.models import Form, FormResponse
with open("resources/unittest_template.py") as file:
TEST_TEMPLATE = file.read()
-UnittestResult = namedtuple("UnittestResult", "question_id return_code passed result")
+UnittestResult = namedtuple(
+ "UnittestResult", "question_id question_index return_code passed result"
+)
def filter_unittests(form: Form) -> Form:
@@ -119,6 +121,7 @@ async def execute_unittest(form_response: FormResponse, form: Form) -> list[Unit
unittest_results.append(UnittestResult(
question_id=question.id,
+ question_index=index,
return_code=return_code,
passed=passed,
result=result