Skip to content

Commit

Permalink
test(codaveri-integration): added tests for BE polling operations
Browse files Browse the repository at this point in the history
- added polling Codaveri evaluation tests
- added polling Codaveri (submitted) feedback test
  • Loading branch information
adi-herwana-nus authored and cysjonathan committed Jul 3, 2024
1 parent b829a64 commit c108b59
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@

context 'when feedback request succeeds immediately' do
before do
Excon.defaults[:mock] = true
Excon.stub({ method: 'POST' }, Codaveri::FeedbackApiStubs::FEEDBACK_SUCCESS_FINAL_RESULT)
end
after do
Expand Down Expand Up @@ -95,5 +96,61 @@
expect(codaveri_feedback.rating).to be_nil
end
end

context 'when feedback request succeeds after polling' do
# dummy URL
let!(:connection) { Excon.new('http://localhost:53896') }

before do
allow(Excon).to receive(:new).and_return(connection)
allow(connection).to receive(:post).and_call_original

Excon.defaults[:mock] = true
Excon.stub({ method: 'POST' }, Codaveri::FeedbackApiStubs::FEEDBACK_ID_CREATED)
Excon.stub({ method: 'GET' }, Codaveri::FeedbackApiStubs::FEEDBACK_SUCCESS_FINAL_RESULT)
Excon.stub({ method: 'GET' }, Codaveri::FeedbackApiStubs::FEEDBACK_RESULTS_PENDING)
Excon.stub({ method: 'GET' }, Codaveri::FeedbackApiStubs::FEEDBACK_RESULTS_PENDING)
Excon.stub({ method: 'GET' }, Codaveri::FeedbackApiStubs::FEEDBACK_RESULTS_PENDING)
allow(connection).to receive(:get).and_wrap_original do |method, *args|
# After each time connection.get is called, we remove 1 stub from the above list (LIFO)
# so api will be polled a total of 4 times
response = method.call(*args)
Excon.unstub({ method: 'GET' })
response
end

stub_const('Course::Assessment::Answer::ProgrammingCodaveriFeedbackJob::POLL_INTERVAL_SECONDS', 0.001)
end
after do
Excon.stubs.clear
end

it 'polls as long as results still pending' do
expect(connection).to receive(:get).exactly(4).times
subject.perform_now(assessment, question, answer.actable)
end

it 'retrieves the feedback successfully' do
subject.perform_now(assessment, question, answer.actable)

annotation = answer.actable.files.first.annotations.first
expect(annotation).not_to be_nil
expect(annotation.line).to eq(5)

post = annotation.posts.first
expect(post.workflow_state).to eq('draft')
expect(post.text).to eq('This is a test feedback')
expect(post.creator_id).to eq(0)
expect(post.topic.pending_staff_reply).to eq(true)

codaveri_feedback = post.codaveri_feedback
expect(codaveri_feedback.codaveri_feedback_id).to eq(
'6311a0548c57aae93d260927:main.py:63141b108c57aae93d260a00'
)
expect(codaveri_feedback.status).to eq('pending_review')
expect(codaveri_feedback.original_feedback).to eq('This is a test feedback')
expect(codaveri_feedback.rating).to be_nil
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,52 @@
end
end

describe '#grade and succeeded after polling' do
subject { super().grade(answer) }

# dummy URL
let!(:connection) { Excon.new('http://localhost:53896') }

before do
allow(answer.submission.assessment).to receive(:autograded?).and_return(true)

allow(Excon).to receive(:new).and_return(connection)
allow(connection).to receive(:post).and_call_original

Excon.defaults[:mock] = true
Excon.stub({ method: 'POST' }, Codaveri::EvaluateApiStubs::EVALUATE_ID_CREATED)
Excon.stub({ method: 'GET' }, Codaveri::EvaluateApiStubs.evaluate_success_final_result)
Excon.stub({ method: 'GET' }, Codaveri::EvaluateApiStubs::EVALUATE_RESULTS_PENDING)
Excon.stub({ method: 'GET' }, Codaveri::EvaluateApiStubs::EVALUATE_RESULTS_PENDING)
Excon.stub({ method: 'GET' }, Codaveri::EvaluateApiStubs::EVALUATE_RESULTS_PENDING)
allow(connection).to receive(:get).and_wrap_original do |method, *args|
# After each time connection.get is called, we remove 1 stub from the above list (LIFO)
# so api will be polled a total of 4 times
response = method.call(*args)
Excon.unstub({ method: 'GET' })
response
end

stub_const('Course::Assessment::ProgrammingCodaveriEvaluationService::POLL_INTERVAL_SECONDS', 0.001)
end
after do
Excon.stubs.clear
end

it 'polls as long as results still pending' do
expect(connection).to receive(:get).exactly(4).times
subject
end

context 'when the answer is correct' do
it 'marks the answer correct' do
subject
expect(answer).to be_correct
expect(answer.grade).to eq(question.maximum_grade)
end
end
end

describe '#grade but failed immediately' do
subject { super().grade(answer) }

Expand All @@ -118,7 +164,7 @@
Excon.stubs.clear
end

context 'when an invalid API is provided' do
context 'when the API call fails' do
it 'raises a CodaveriError' do
expect { subject }.to raise_error(CodaveriError)
expect(answer.grade).to eq(nil)
Expand All @@ -129,7 +175,38 @@
end
end

# TODO: Add tests for API success/failure after some polling attempts
describe '#grade and failed after polling' do
subject { super().grade(answer) }

let!(:connection) { Excon.new('http://localhost:53896') }

before do
allow(answer.submission.assessment).to receive(:autograded?).and_return(true)

allow(Excon).to receive(:new).and_return(connection)
allow(connection).to receive(:post).and_call_original

Excon.defaults[:mock] = true
Excon.stub({ method: 'POST' }, Codaveri::EvaluateApiStubs::EVALUATE_ID_CREATED)
Excon.stub({ method: 'GET' }, Codaveri::EvaluateApiStubs.evaluate_failure_final_result)
Excon.stub({ method: 'GET' }, Codaveri::EvaluateApiStubs::EVALUATE_RESULTS_PENDING)
allow(connection).to receive(:get).and_wrap_original do |method, *args|
response = method.call(*args)
Excon.unstub({ method: 'GET' })
response
end

stub_const('Course::Assessment::ProgrammingCodaveriEvaluationService::POLL_INTERVAL_SECONDS', 0.01)
end
after do
Excon.stubs.clear
end

it 'polls as long as results still pending, then throw error' do
expect(connection).to receive(:get).exactly(2).times
expect { subject }.to raise_error(CodaveriError)
end
end

describe '#grade but wrong' do
subject { super().grade(answer) }
Expand Down
26 changes: 25 additions & 1 deletion spec/support/stubs/codaveri/evaluate_api_stubs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def evaluate_success_final_result
success: true,
message: 'Evaluation successfully generated',
data: {
id: '6659878d3ad73c7a4aac96f0',
exprResults: [
{
run: {
Expand Down Expand Up @@ -106,7 +107,8 @@ def evaluate_success_final_result
}
}
]
}
},
transactionId: '66598c55fac28dd29e968852'
}.to_json
}
end
Expand All @@ -124,6 +126,28 @@ def evaluate_failure_final_result
}
end

EVALUATE_ID_CREATED = {
status: 201,
body: {
success: true,
message: 'Evaluation request received',
data: {
id: '6659878d3ad73c7a4aac96f0'
},
transactionId: '66598c55fac28dd29e968853'
}.to_json
}.freeze

EVALUATE_RESULTS_PENDING = {
status: 202,
body: {
success: true,
message: 'Evaluation results not ready yet',
data: {},
transactionId: '6659878d3ad73c7a4aac96f0'
}.to_json
}.freeze

def evaluate_wrong_answer_final_result
ids = test_cases_id_from_factory.map(&:to_s)
{
Expand Down
22 changes: 22 additions & 0 deletions spec/support/stubs/codaveri/feedback_api_stubs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ module Codaveri::FeedbackApiStubs
}.to_json
}.freeze

FEEDBACK_ID_CREATED = {
status: 201,
body: {
success: true,
message: 'Feedback request received',
data: {
id: '6659878d3ad73c7a4aac96f0'
},
transactionId: '66598c55fac28dd29e968853'
}.to_json
}.freeze

FEEDBACK_RESULTS_PENDING = {
status: 202,
body: {
success: true,
message: 'Feedback results not ready yet',
data: {},
transactionId: '6659878d3ad73c7a4aac96f0'
}.to_json
}.freeze

FEEDBACK_FAILURE_FINAL_RESULT = {
status: 400,
body: {
Expand Down

0 comments on commit c108b59

Please sign in to comment.