This scenario starts with the default administrator and ends with a withdrawn submission followed by a successful resubmission.
Complete the setup guide first.
Administrator
→ creates teacher and student
Teacher
→ creates group and assignment
Student
→ joins group
Worker
→ validates assignment
Student
→ practices, submits, polls result, withdraws, resubmits
Teacher
→ can inspect the student's current work and execution
Request
POST {{baseUrl}}/api/auth/login{
"identifier": "{{adminEmail}}",
"password": "{{adminPassword}}"
}Expected: HTTP 200, data.user.role = "ADMIN".
Save the token:
const body = pm.response.json();
pm.environment.set("adminToken", body.data.token);Use the administrator bearer token.
POST {{baseUrl}}/api/auth/signup
Authorization: Bearer {{adminToken}}{
"role": "TEACHER",
"name": "API Teacher",
"fatherLastName": "Testing",
"motherLastName": "Guide",
"enrollmentNumber": "TEA-001",
"email": "{{teacherEmail}}"
}Expected: HTTP 201, data.role = "TEACHER" and
data.temporaryPassword = true.
Save data.id as teacherId. Retrieve the temporary password from the
configured teacher inbox and store it as teacherPassword.
POST {{baseUrl}}/api/auth/signup
Authorization: Bearer {{adminToken}}{
"role": "STUDENT",
"name": "API Student",
"fatherLastName": "Testing",
"motherLastName": "Guide",
"enrollmentNumber": "2026630002",
"email": "{{studentEmail}}"
}Expected: HTTP 201, data.role = "STUDENT".
Save data.id as studentId. Retrieve the generated password and save it as
studentPassword.
The signup endpoint is limited to three requests per five minutes. Avoid repeatedly sending the same request.
Teacher:
POST {{baseUrl}}/api/auth/login{
"identifier": "{{teacherEmail}}",
"password": "{{teacherPassword}}"
}Save data.token as teacherToken and data.user.id as teacherId.
Student:
POST {{baseUrl}}/api/auth/login{
"identifier": "{{studentEmail}}",
"password": "{{studentPassword}}"
}Save data.token as studentToken and data.user.id as studentId.
Verify either identity with:
GET {{baseUrl}}/api/auth/me
Authorization: Bearer {{teacherToken}}Use the teacher token:
POST {{baseUrl}}/api/groups
Authorization: Bearer {{teacherToken}}{
"name": "API Testing 101",
"description": "Temporary group for manual API verification"
}Expected: HTTP 201. The owner response includes data.joinCode.
const body = pm.response.json();
pm.environment.set("groupId", body.data.id);
pm.environment.set("joinCode", body.data.joinCode);POST {{baseUrl}}/api/groups/join
Authorization: Bearer {{studentToken}}{
"joinCode": "{{joinCode}}"
}Expected: HTTP 200. The student-facing group response must not expose the
join code.
Verify the teacher roster:
GET {{baseUrl}}/api/groups/{{groupId}}/students
Authorization: Bearer {{teacherToken}}The response should contain studentId with an active enrollment.
Save this as reference.py:
a, b = map(int, input().split())
print(a + b)Save these test inputs as separate files:
test-1.in
2 3
test-2.in
-4 7
Use POST {{baseUrl}}/api/assignments with the teacher token and a form-data
body:
| Key | Type | Value |
|---|---|---|
metadata |
Text (application/json) |
JSON below |
referenceSolution |
File | reference.py |
testCaseInputs |
File | test-1.in |
testCaseInputs |
File | test-2.in |
Metadata:
{
"groupId": "{{groupId}}",
"title": "Add two integers",
"description": "Read two integers and print their sum.",
"constraints": ["Input contains exactly two integers."],
"hints": ["Use split() and map()."],
"tags": ["arithmetic", "introduction"],
"timeLimitMs": 2000,
"memoryLimitMb": 128,
"comparatorType": "EXACT_MATCH",
"allowedLanguages": ["PYTHON"],
"referenceLanguage": "PYTHON",
"sampleFlags": [true, false],
"maxPoints": 100,
"examples": [
{
"input": "2 3",
"output": "5",
"explanation": "2 + 3 equals 5."
}
]
}Expected: HTTP 202 and data.validationStatus = "PROCESSING".
Save:
const body = pm.response.json();
pm.environment.set("assignmentId", body.data.id);Poll as the teacher:
GET {{baseUrl}}/api/assignments/{{assignmentId}}
Authorization: Bearer {{teacherToken}}Stop when:
READY: continue.FAILED: inspect the worker logs; do not continue.
When ready, save the active revisions:
const body = pm.response.json();
pm.environment.set(
"activeTestSuiteRevisionId",
body.data.activeTestSuiteRevisionId
);
pm.environment.set(
"activeReferenceRevisionId",
body.data.activeReferenceSolutionRevisionId
);The response should contain one public sample test case. Private cases and expected outputs must not be exposed.
GET {{baseUrl}}/api/assignments?groupId={{groupId}}&page=0&size=10
Authorization: Bearer {{studentToken}}Expected: HTTP 200; the page contains the ready assignment.
POST {{baseUrl}}/api/execution/check
Authorization: Bearer {{studentToken}}{
"code": "a, b = map(int, input().split())\nprint(a + b)",
"language": "PYTHON",
"assignmentId": "{{assignmentId}}",
"testCases": ["10 20", "-5 2"],
"executionType": "PRACTICE"
}Expected: HTTP 202, data.executionType = "PRACTICE" and
data.status = "PENDING".
Save data.id as practiceExecutionId, poll:
GET {{baseUrl}}/api/execution/check/{{practiceExecutionId}}
Authorization: Bearer {{studentToken}}After the status becomes terminal, retrieve:
GET {{baseUrl}}/api/execution/check/{{practiceExecutionId}}/report
Authorization: Bearer {{studentToken}}Both cases should pass. Practice execution does not create a submission.
The group owner can run the same practice request using teacherToken, but
cannot send a definitive submission.
POST {{baseUrl}}/api/execution/check
Authorization: Bearer {{studentToken}}{
"code": "a, b = map(int, input().split())\nprint(a + b)",
"language": "PYTHON",
"assignmentId": "{{assignmentId}}",
"executionType": "DEFINITIVE"
}Expected: HTTP 202, with a non-null data.submissionId.
const body = pm.response.json();
pm.environment.set("executionId", body.data.id);
pm.environment.set("submissionId", body.data.submissionId);The backend derives the student from the JWT. A client-supplied requesterId
is ignored.
Poll:
GET {{baseUrl}}/api/execution/check/{{executionId}}
Authorization: Bearer {{studentToken}}For the correct solution, expect data.status = "AC".
Then retrieve:
GET {{baseUrl}}/api/execution/check/{{executionId}}/report
Authorization: Bearer {{studentToken}}Expected report properties:
- Overall status
AC - Two ordered test results
- Each result contains its test-case UUID
- No private expected-output object key is exposed
The teacher may retrieve the same definitive execution and report with
teacherToken.
Student:
GET {{baseUrl}}/api/assignments/{{assignmentId}}/my-work
Authorization: Bearer {{studentToken}}Teacher:
GET {{baseUrl}}/api/assignments/{{assignmentId}}/students/{{studentId}}/work
Authorization: Bearer {{teacherToken}}Expected state:
status = "SUBMITTED"currentSubmissionId = {{submissionId}}- The submission history contains the current
SUBMITTEDsubmission
Repeat the definitive request before withdrawing.
Expected: HTTP 400; the response should instruct the student to withdraw
the current submission. No new submission or execution should be created.
POST {{baseUrl}}/api/submissions/{{submissionId}}/withdraw
Authorization: Bearer {{studentToken}}Expected: HTTP 200.
Repeat GET /api/assignments/{{assignmentId}}/my-work. The old submission
should remain in history with:
status = "WITHDRAWN"- A non-null
withdrawnAt - No current submitted delivery
Send another definitive execution with this intentionally wrong solution:
{
"code": "a, b = map(int, input().split())\nprint(a - b)",
"language": "PYTHON",
"assignmentId": "{{assignmentId}}",
"executionType": "DEFINITIVE"
}Save the new executionId and submissionId. Poll until terminal.
Expected:
- The request is accepted because the previous submission was withdrawn.
- The new execution becomes
WA. - Student work points at the replacement submission.
- Submission history contains both the withdrawn and current submissions.
Continue with assignment updates and evaluation.