Skip to content
This repository was archived by the owner on Sep 25, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ GEM
docile (1.1.5)
domain_name (0.5.25)
unf (>= 0.0.5, < 1.0.0)
factory_girl (4.5.0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lowjoel If this is a gem, Gemfile.lock should not be checked into the repo ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but this gem is a gem that is to be used as a client program... so nothing should depend on evaluator-slave.

Gemfile.lock should not be in the repo if it's a library and other things include it, because then the dependencies might not resolve.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, that is my guess also.

activesupport (>= 3.0.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
faraday_middleware (0.10.0)
Expand Down Expand Up @@ -92,6 +94,7 @@ DEPENDENCIES
codeclimate-test-reporter
coursemology-evaluator!
coveralls
factory_girl
rake
rspec
simplecov
Expand Down
1 change: 1 addition & 0 deletions coursemology-evaluator.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec'
spec.add_development_dependency 'factory_girl'
spec.add_development_dependency 'simplecov'
spec.add_development_dependency 'coveralls'
spec.add_development_dependency 'codeclimate-test-reporter'
Expand Down
8 changes: 6 additions & 2 deletions lib/coursemology/evaluator/cli.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'optparse'

class Coursemology::Evaluator::CLI
Options = Struct.new(:host, :api_token, :api_user_email)
Options = Struct.new(:host, :api_token, :api_user_email, :one_shot)

def self.start(argv)
new.start(argv)
Expand All @@ -15,7 +15,7 @@ def run(argv)
options = optparse!(argv)
Coursemology::Evaluator::Client.initialize(options.host, options.api_user_email,
options.api_token)
Coursemology::Evaluator::Client.new.run
Coursemology::Evaluator::Client.new(options.one_shot).run
end

private
Expand All @@ -39,6 +39,10 @@ def optparse!(argv) # rubocop:disable Metrics/MethodLength
parser.on('-uUSER', '--api-user-email=USER') do |user|
options.api_user_email = user
end

parser.on('-o', '--one-shot') do
options.one_shot = true
end
end

option_parser.parse!(argv)
Expand Down
43 changes: 42 additions & 1 deletion lib/coursemology/evaluator/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,50 @@ def self.initialize(host, api_user_email, api_token)
Coursemology::Evaluator::Models::Base.initialize
end

def initialize
# @param [Boolean] one_shot If the client should only fire one request.
def initialize(one_shot = false)
@terminate = one_shot
end

def run
Signal.trap('SIGTERM', method(:on_sig_term))

loop do
allocate_evaluations
break if @terminate

sleep(1.minute)
end
end

private

# Requests evaluations from the server.
def allocate_evaluations
evaluations = Coursemology::Evaluator::Models::ProgrammingEvaluation.allocate
on_allocate(evaluations)
end

# The callback for handling an array of allocated evaluations.
#
# @param [Array<Coursemology::Evaluator::Models::ProgrammingEvaluation>] evaluations The
# evaluations retrieved from the server.
def on_allocate(evaluations)
evaluations.each do |evaluation|
on_evaluation(evaluation)
end
end

# The callback for handling an evaluation.
#
# @param [Coursemology::Evaluator::Models::ProgrammingEvaluation] evaluation The evaluation
# retrieved from the server.
def on_evaluation(evaluation)
evaluation.save
end

# The callback for handling SIGTERM sent to the process.
def on_sig_term
@terminate = true
end
end
15 changes: 11 additions & 4 deletions spec/coursemology/evaluator/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
RSpec.describe Coursemology::Evaluator::CLI do
let(:host) { 'http://localhost:3000' }
let!(:original_api_token) { Coursemology::Evaluator::Models::Base.api_token }
let(:api_token) { 'abcd' }
let(:api_user_email) { 'test@example.org' }
let(:argv) do
["--host=#{host}", "--api-token=#{api_token}", "--api-user-email=#{api_user_email}"]
["--host=#{host}", "--api-token=#{api_token}", "--api-user-email=#{api_user_email}",
'--one-shot']
end

describe Coursemology::Evaluator::CLI::Options do
Expand All @@ -22,22 +24,27 @@
describe '#start' do
subject { Coursemology::Evaluator::CLI.new }
it 'calls #run' do
expect(subject).to receive(:run).and_call_original
expect(subject).to receive(:run)
subject.start(argv)
end
end

describe '#run' do
let(:api_token) { original_api_token }
subject { Coursemology::Evaluator::CLI.new.run(argv) }

it 'creates a client' do
expect(Coursemology::Evaluator::Client).to receive(:new).and_call_original
subject
VCR.use_cassette('client/no_pending_evaluations') do
subject
end
end

it 'runs the client' do
expect(Coursemology::Evaluator::Client).to receive_message_chain(:new, :run)
subject
VCR.use_cassette('client/no_pending_evaluations') do
subject
end
end
end
end
Expand Down
38 changes: 38 additions & 0 deletions spec/coursemology/evaluator/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,42 @@
end
end
end

describe '#run' do
it 'loops until @terminate is set' do
expect(subject).to receive(:allocate_evaluations).at_least(:once)
allow(subject).to receive(:sleep) do
sleep(0.1.seconds)
end

Thread.new { subject.instance_variable_set(:@terminate, true) }
subject.run
end
end

describe '#allocate_evaluations' do
context 'when an evaluation is provided' do
let(:dummy_evaluation) { build(:programming_evaluation) }
before do
expect(Coursemology::Evaluator::Models::ProgrammingEvaluation).to \
receive(:allocate).and_return([dummy_evaluation])
end

it 'calls #on_allocate with the evaluation' do
expect(subject).to receive(:on_allocate).with([dummy_evaluation]).and_call_original
subject.send(:allocate_evaluations)
end
end
end

describe '#on_sig_term' do
it 'terminates the loop' do
expect(subject).to receive(:allocate_evaluations).at_least(:once)
allow(subject).to receive(:sleep) do
sleep(0.1.seconds)
end
Thread.new { subject.send(:on_sig_term) }
subject.run
end
end
end
8 changes: 8 additions & 0 deletions spec/factories/programming_evaluations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FactoryGirl.define do
factory :programming_evaluation, class: Coursemology::Evaluator::Models::ProgrammingEvaluation do
id 1
language 'Polyglot::Language::Python::Python2Point7'
memory_limit 32
time_limit 5
end
end
58 changes: 58 additions & 0 deletions spec/fixtures/vcr/cassettes/client/no_pending_evaluations.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions spec/support/factory_girl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'factory_girl'

RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods

config.before(:suite) do
FactoryGirl.find_definitions
end
end