Skip to content

Commit a85db9b

Browse files
authored
ISSUE-7711: Added api route GET api/.../groups/:id/test_results (#7754)
1 parent 3421ef3 commit a85db9b

File tree

5 files changed

+196
-11
lines changed

5 files changed

+196
-11
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- Enable zip downloads of test results (#7733)
2121
- Create rake task to remove orphaned end users (#7741)
2222
- Enable scanned assignments the ability to add inactive students (#7737)
23+
- Enable test results downloads through the API (#7754)
2324

2425
### 🐛 Bug fixes
2526
- Fix name column search in graders table (#7693)

app/controllers/api/groups_controller.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,31 @@ def annotations
203203
end
204204
end
205205

206+
def test_results
207+
return render_no_grouping_error unless grouping
208+
209+
# Use the existing Assignment#summary_test_results method filtered for this specific group
210+
# This ensures format consistency with the UI download (summary_test_result_json)
211+
group_name = grouping.group.group_name
212+
results = assignment.summary_test_results([group_name])
213+
214+
return render_no_grouping_error if results.blank?
215+
216+
# Group by test_group name to match the summary_test_result_json format
217+
results_by_test_group = results.group_by(&:name)
218+
219+
respond_to do |format|
220+
format.xml { render xml: results_by_test_group.to_xml(root: 'test_results', skip_types: 'true') }
221+
format.json { render json: results_by_test_group }
222+
end
223+
end
224+
225+
def render_no_grouping_error
226+
render 'shared/http_status',
227+
locals: { code: '404', message: 'No test results found for this group' },
228+
status: :not_found
229+
end
230+
206231
def add_annotations
207232
result = self.grouping&.current_result
208233
return page_not_found('No submission exists for that group') if result.nil?

app/models/assignment.rb

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ def summary_json(user)
668668
end
669669

670670
# Generates the summary of the most test results associated with an assignment.
671-
def summary_test_results
671+
def summary_test_results(group_names = nil)
672672
latest_test_run_by_grouping = TestRun.group('grouping_id').select('MAX(created_at) as test_runs_created_at',
673673
'grouping_id')
674674
.where.not(submission_id: nil)
@@ -682,17 +682,21 @@ def summary_test_results
682682
.select('id', 'test_runs.grouping_id', 'groups.group_name')
683683
.to_sql
684684

685-
self.test_groups.joins(test_group_results: :test_results)
686-
.joins("INNER JOIN (#{latest_test_runs}) latest_test_runs \
685+
query = self.test_groups.joins(test_group_results: :test_results)
686+
.joins("INNER JOIN (#{latest_test_runs}) latest_test_runs \
687687
ON test_group_results.test_run_id = latest_test_runs.id")
688-
.select('test_groups.name',
689-
'test_groups.id as test_groups_id',
690-
'latest_test_runs.group_name',
691-
'test_results.name as test_result_name',
692-
'test_results.status',
693-
'test_results.marks_earned',
694-
'test_results.marks_total',
695-
:output, :extra_info, :error_type)
688+
689+
# Optionally - filters specific groups if provided
690+
query = query.where('latest_test_runs.group_name': group_names) if group_names.present?
691+
692+
query.select('test_groups.name',
693+
'test_groups.id as test_groups_id',
694+
'latest_test_runs.group_name',
695+
'test_results.name as test_result_name',
696+
'test_results.status',
697+
'test_results.marks_earned',
698+
'test_results.marks_total',
699+
:output, :extra_info, :error_type)
696700
end
697701

698702
# Generate a JSON summary of the most recent test results associated with an assignment.

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
put 'remove_tag'
4343
post 'collect_submission'
4444
post 'add_test_run'
45+
get 'test_results'
4546
end
4647
resources :submission_files, only: [:index, :create] do
4748
collection do

spec/controllers/api/groups_controller_spec.rb

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,5 +1306,159 @@
13061306
end
13071307
end
13081308
end
1309+
1310+
context 'GET test_results' do
1311+
let(:grouping) { create(:grouping_with_inviter, assignment: assignment) }
1312+
let(:test_group) { create(:test_group, assignment: assignment) }
1313+
let(:submission) { create(:version_used_submission, grouping: grouping) }
1314+
1315+
context 'when the group has test results' do
1316+
let!(:test_run) do
1317+
create(:test_run, grouping: grouping, role: instructor, status: :complete, submission: submission)
1318+
end
1319+
let!(:test_group_result) do
1320+
create(:test_group_result, test_run: test_run, test_group: test_group,
1321+
marks_earned: 5.0, marks_total: 10.0, time: 1000)
1322+
end
1323+
1324+
before do
1325+
create(:test_result, test_group_result: test_group_result, name: 'Test 1',
1326+
status: 'pass', marks_earned: 3.0, marks_total: 5.0, position: 1)
1327+
end
1328+
1329+
context 'expecting json response' do
1330+
before do
1331+
request.env['HTTP_ACCEPT'] = 'application/json'
1332+
get :test_results, params: { id: grouping.group.id, assignment_id: assignment.id, course_id: course.id }
1333+
end
1334+
1335+
it 'should be successful' do
1336+
expect(response).to have_http_status(:ok)
1337+
end
1338+
1339+
it 'should return data grouped by test group name' do
1340+
expect(response.parsed_body).to have_key(test_group.name)
1341+
end
1342+
1343+
it 'should return test results for the group' do
1344+
test_results = response.parsed_body[test_group.name]
1345+
expect(test_results).to be_an(Array)
1346+
expect(test_results.first).to include(
1347+
'test_result_name' => 'Test 1',
1348+
'status' => 'pass',
1349+
'marks_earned' => 3.0,
1350+
'marks_total' => 5.0
1351+
)
1352+
end
1353+
end
1354+
1355+
context 'expecting xml response' do
1356+
before do
1357+
request.env['HTTP_ACCEPT'] = 'application/xml'
1358+
get :test_results, params: { id: grouping.group.id, assignment_id: assignment.id, course_id: course.id }
1359+
end
1360+
1361+
it 'should be successful' do
1362+
expect(response).to have_http_status(:ok)
1363+
end
1364+
1365+
it 'should return xml content' do
1366+
xml_data = Hash.from_xml(response.body)
1367+
expect(xml_data).to have_key('test_results')
1368+
end
1369+
end
1370+
1371+
context 'with multiple test groups' do
1372+
let(:test_group_two) { create(:test_group, assignment: assignment, name: 'Group B') }
1373+
let!(:test_group_result_two) do
1374+
create(:test_group_result, test_run: test_run, test_group: test_group_two)
1375+
end
1376+
1377+
before do
1378+
create(:test_result, test_group_result: test_group_result_two, name: 'Test B1',
1379+
status: 'pass', marks_earned: 2.0, marks_total: 5.0, position: 1)
1380+
request.env['HTTP_ACCEPT'] = 'application/json'
1381+
get :test_results, params: { id: grouping.group.id, assignment_id: assignment.id, course_id: course.id }
1382+
end
1383+
1384+
it 'should be successful' do
1385+
expect(response).to have_http_status(:ok)
1386+
end
1387+
1388+
it 'should return results keyed by each test group name' do
1389+
expect(response.parsed_body.keys).to contain_exactly(test_group.name, test_group_two.name)
1390+
end
1391+
1392+
it 'should return correct test results for each group' do
1393+
expect(response.parsed_body[test_group.name].first['test_result_name']).to eq('Test 1')
1394+
expect(response.parsed_body[test_group_two.name].first['test_result_name']).to eq('Test B1')
1395+
end
1396+
end
1397+
end
1398+
1399+
context 'authorization check' do
1400+
it_behaves_like 'for a different course' do
1401+
before do
1402+
request.env['HTTP_ACCEPT'] = 'application/json'
1403+
get :test_results, params: { id: grouping.group.id, assignment_id: assignment.id, course_id: course.id }
1404+
end
1405+
end
1406+
end
1407+
1408+
context 'when the group has no test results' do
1409+
before do
1410+
request.env['HTTP_ACCEPT'] = 'application/json'
1411+
get :test_results, params: { id: grouping.group.id, assignment_id: assignment.id, course_id: course.id }
1412+
end
1413+
1414+
it 'should return 404 status' do
1415+
expect(response).to have_http_status(:not_found)
1416+
end
1417+
end
1418+
1419+
context 'when the group does not exist' do
1420+
before do
1421+
request.env['HTTP_ACCEPT'] = 'application/json'
1422+
get :test_results, params: { id: 999_999, assignment_id: assignment.id, course_id: course.id }
1423+
end
1424+
1425+
it 'should return 404 status' do
1426+
expect(response).to have_http_status(:not_found)
1427+
end
1428+
end
1429+
1430+
context 'when multiple test runs exist' do
1431+
let!(:older_test_run) do
1432+
create(:test_run, grouping: grouping, role: instructor, created_at: 2.days.ago, status: :complete,
1433+
submission: submission)
1434+
end
1435+
let!(:newer_test_run) do
1436+
create(:test_run, grouping: grouping, role: instructor, created_at: 1.hour.ago, status: :complete,
1437+
submission: submission)
1438+
end
1439+
let!(:older_test_group_result) do
1440+
create(:test_group_result, test_run: older_test_run, test_group: test_group)
1441+
end
1442+
let!(:newer_test_group_result) do
1443+
create(:test_group_result, test_run: newer_test_run, test_group: test_group)
1444+
end
1445+
1446+
before do
1447+
create(:test_result, test_group_result: older_test_group_result, name: 'Old Test',
1448+
marks_earned: 1.0, marks_total: 5.0, status: 'pass', position: 1)
1449+
create(:test_result, test_group_result: newer_test_group_result, name: 'New Test',
1450+
marks_earned: 4.0, marks_total: 5.0, status: 'pass', position: 1)
1451+
request.env['HTTP_ACCEPT'] = 'application/json'
1452+
get :test_results, params: { id: grouping.group.id, assignment_id: assignment.id, course_id: course.id }
1453+
end
1454+
1455+
it 'should return only the latest test run results' do
1456+
test_results = response.parsed_body[test_group.name]
1457+
expect(test_results.length).to eq(1)
1458+
expect(test_results.first['test_result_name']).to eq('New Test')
1459+
expect(test_results.first['marks_earned']).to eq(4.0)
1460+
end
1461+
end
1462+
end
13091463
end
13101464
end

0 commit comments

Comments
 (0)