diff --git a/Gemfile.lock b/Gemfile.lock index 987133c..2de5a7f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,6 +4,7 @@ PATH coursemology-evaluator (0.0.0) active_rest_client (~> 1.2) activesupport (~> 4.2.0) + faraday_middleware GEM remote: https://rubygems.org/ @@ -36,6 +37,8 @@ GEM unf (>= 0.0.5, < 1.0.0) faraday (0.9.2) multipart-post (>= 1.2, < 3) + faraday_middleware (0.10.0) + faraday (>= 0.7.4, < 0.10) http-cookie (1.0.2) domain_name (~> 0.5) i18n (0.7.0) @@ -79,6 +82,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.1) + vcr (3.0.0) PLATFORMS mswin64 @@ -91,6 +95,7 @@ DEPENDENCIES rake rspec simplecov + vcr BUNDLED WITH 1.10.6 diff --git a/coursemology-evaluator.gemspec b/coursemology-evaluator.gemspec index 115f546..ea38ee6 100644 --- a/coursemology-evaluator.gemspec +++ b/coursemology-evaluator.gemspec @@ -24,7 +24,9 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'simplecov' spec.add_development_dependency 'coveralls' spec.add_development_dependency 'codeclimate-test-reporter' + spec.add_development_dependency 'vcr' spec.add_dependency 'activesupport', '~> 4.2.0' spec.add_dependency 'active_rest_client', '~> 1.2' + spec.add_dependency 'faraday_middleware' end diff --git a/lib/coursemology/evaluator.rb b/lib/coursemology/evaluator.rb index 6cb6283..41e96b3 100644 --- a/lib/coursemology/evaluator.rb +++ b/lib/coursemology/evaluator.rb @@ -1,5 +1,6 @@ require 'active_support/all' require 'active_rest_client' +require 'faraday_middleware' require 'coursemology/evaluator/version' module Coursemology::Evaluator diff --git a/lib/coursemology/evaluator/client.rb b/lib/coursemology/evaluator/client.rb index df59822..c0c3bb7 100644 --- a/lib/coursemology/evaluator/client.rb +++ b/lib/coursemology/evaluator/client.rb @@ -3,6 +3,8 @@ def self.initialize(host, api_user_email, api_token) Coursemology::Evaluator::Models::Base.base_url = host Coursemology::Evaluator::Models::Base.api_user_email = api_user_email Coursemology::Evaluator::Models::Base.api_token = api_token + + Coursemology::Evaluator::Models::Base.initialize end def initialize diff --git a/lib/coursemology/evaluator/models/base.rb b/lib/coursemology/evaluator/models/base.rb index 457c48c..e867f18 100644 --- a/lib/coursemology/evaluator/models/base.rb +++ b/lib/coursemology/evaluator/models/base.rb @@ -2,6 +2,18 @@ class Coursemology::Evaluator::Models::Base < ActiveRestClient::Base class << self attr_accessor :api_user_email attr_accessor :api_token + + def initialize + ActiveRestClient::Base.perform_caching = false + default_config = ActiveRestClient::Base.faraday_config + ActiveRestClient::Base.faraday_config do |faraday| + # +follow_redirects+ must be added before declaring the adapter. See faraday_middleware#32, + # last comment. + faraday.response :follow_redirects + + default_config.call(faraday) + end + end end before_request :add_authentication diff --git a/lib/coursemology/evaluator/models/programming_evaluation.rb b/lib/coursemology/evaluator/models/programming_evaluation.rb new file mode 100644 index 0000000..de30118 --- /dev/null +++ b/lib/coursemology/evaluator/models/programming_evaluation.rb @@ -0,0 +1,28 @@ +class Coursemology::Evaluator::Models::ProgrammingEvaluation < Coursemology::Evaluator::Models::Base + extend ActiveSupport::Autoload + autoload :Package + + get :find, 'courses/assessment/programming_evaluations/:id' + post :allocate, 'courses/assessment/programming_evaluations/allocate' + + # Obtains the package. + # + # @return [Coursemology::Evaluator::Models::ProgrammingEvaluation::Package] + def package + body = plain_request('courses/assessment/programming_evaluations/:id/package', id: id) + Package.new(StringIO.new(body)) + end + + private + + # Performs a plain request. + # + # @param [String] url The URL to request. + # @param [Hash] params The parameter to be part of the request. + # @return [String] The response body. + def plain_request(url, params = {}) + request = ActiveRestClient::Request.new({ url: url, method: :get, options: { plain: true } }, + self.class) + request.call(params) + end +end diff --git a/lib/coursemology/evaluator/models/programming_evaluation/package.rb b/lib/coursemology/evaluator/models/programming_evaluation/package.rb new file mode 100644 index 0000000..1807b14 --- /dev/null +++ b/lib/coursemology/evaluator/models/programming_evaluation/package.rb @@ -0,0 +1,7 @@ +class Coursemology::Evaluator::Models::ProgrammingEvaluation::Package + # Constructs a new Package. + # + # @param [IO] io The IO object containing the package data. + def initialize(io) + end +end diff --git a/spec/coursemology/evaluator/models/base_spec.rb b/spec/coursemology/evaluator/models/base_spec.rb index abb75f3..2f7efb0 100644 --- a/spec/coursemology/evaluator/models/base_spec.rb +++ b/spec/coursemology/evaluator/models/base_spec.rb @@ -3,11 +3,11 @@ subject { Coursemology::Evaluator::Models::Base } describe '.api_user_email' do - it { is_expected.to have_attributes(api_user_email: nil) } + it { is_expected.to have_attributes(api_user_email: anything) } end describe '.api_token' do - it { is_expected.to have_attributes(api_token: nil) } + it { is_expected.to have_attributes(api_token: anything) } end end diff --git a/spec/coursemology/evaluator/models/programming_evaluation/package_spec.rb b/spec/coursemology/evaluator/models/programming_evaluation/package_spec.rb new file mode 100644 index 0000000..a27ed64 --- /dev/null +++ b/spec/coursemology/evaluator/models/programming_evaluation/package_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +RSpec.describe Coursemology::Evaluator::Models::ProgrammingEvaluation::Package do + around(:each) do |example| + File.open(Pathname.new(__dir__).join('../../../..', + 'fixtures/programming_question_template.zip')) do |file| + define_singleton_method(:file) { file } + example.call + end + end + + let(:package) { Coursemology::Evaluator::Models::ProgrammingEvaluation::Package.new(file) } + describe '#initialize' do + it 'accepts an IO object' do + package + end + end +end diff --git a/spec/coursemology/evaluator/models/programming_evaluation_spec.rb b/spec/coursemology/evaluator/models/programming_evaluation_spec.rb new file mode 100644 index 0000000..4da38ef --- /dev/null +++ b/spec/coursemology/evaluator/models/programming_evaluation_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +RSpec.describe Coursemology::Evaluator::Models::ProgrammingEvaluation do + describe '.allocate' do + let(:evaluation) { Coursemology::Evaluator::Models::ProgrammingEvaluation.allocate.first } + it 'obtains an unallocated evaluation' do + VCR.use_cassette 'programming_evaluation/allocate' do + expect(evaluation.id).not_to be_nil + end + end + end + + describe '.find' do + let(:find_id) { 2 } + let(:evaluation) { Coursemology::Evaluator::Models::ProgrammingEvaluation.find(find_id) } + + it 'obtains the requested evaluation' do + VCR.use_cassette 'programming_evaluation/find' do + expect(evaluation.id).to eq(find_id) + end + end + end + + describe '#package' do + let(:evaluation) { Coursemology::Evaluator::Models::ProgrammingEvaluation.find(3) } + + it 'obtains the requested package' do + VCR.use_cassette 'programming_evaluation/package' do + expect(evaluation.package).to \ + be_a(Coursemology::Evaluator::Models::ProgrammingEvaluation::Package) + end + end + end +end diff --git a/spec/fixtures/programming_question_template.zip b/spec/fixtures/programming_question_template.zip new file mode 100644 index 0000000..78cc2c7 Binary files /dev/null and b/spec/fixtures/programming_question_template.zip differ diff --git a/spec/fixtures/vcr/cassettes/programming_evaluation/allocate.yml b/spec/fixtures/vcr/cassettes/programming_evaluation/allocate.yml new file mode 100644 index 0000000..25d080d --- /dev/null +++ b/spec/fixtures/vcr/cassettes/programming_evaluation/allocate.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/courses/assessment/programming_evaluations/allocate + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - ActiveRestClient/1.2.0 + Connection: + - Keep-Alive + Accept: + - application/hal+json, application/json;q=0.5 + X-User-Email: + - test@example.org + X-User-Token: + - YOUR_TOKEN_HERE + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: + headers: + x-frame-options: + - SAMEORIGIN + x-xss-protection: + - 1; mode=block + x-content-type-options: + - nosniff + content-type: + - application/json; charset=utf-8 + cache-control: + - no-store, must-revalidate, private, max-age=0 + x-request-id: + - 1aab36e3-8686-4401-a6fc-68c826d0aa87 + x-runtime: + - '1.329488' + x-miniprofiler-ids: + - '["b33x4y8wpk341vcv4y30","wv0nqz5k610ynte73hks"]' + server: + - WEBrick/1.3.1 (Ruby/2.2.4/2015-10-06) + date: + - Sun, 20 Dec 2015 12:05:20 GMT + content-length: + - '98' + connection: + - Keep-Alive + set-cookie: + - __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/ + body: + encoding: UTF-8 + string: '[{"id":2,"language":"Polyglot::Language::Python::Python2Point7","memory_limit":32,"time_limit":5}]' + http_version: + recorded_at: Sun, 20 Dec 2015 12:05:21 GMT +recorded_with: VCR 3.0.0 diff --git a/spec/fixtures/vcr/cassettes/programming_evaluation/find.yml b/spec/fixtures/vcr/cassettes/programming_evaluation/find.yml new file mode 100644 index 0000000..801bd3b --- /dev/null +++ b/spec/fixtures/vcr/cassettes/programming_evaluation/find.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/courses/assessment/programming_evaluations/2 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - ActiveRestClient/1.2.0 + Connection: + - Keep-Alive + Accept: + - application/hal+json, application/json;q=0.5 + X-User-Email: + - test@example.org + X-User-Token: + - YOUR_TOKEN_HERE + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: + headers: + x-frame-options: + - SAMEORIGIN + x-xss-protection: + - 1; mode=block + x-content-type-options: + - nosniff + content-type: + - application/json; charset=utf-8 + cache-control: + - no-store, must-revalidate, private, max-age=0 + x-request-id: + - 6f11fef6-677e-4374-bd14-ddf5b36cc1b2 + x-runtime: + - '0.413718' + x-miniprofiler-ids: + - '["wv0nqz5k610ynte73hks"]' + server: + - WEBrick/1.3.1 (Ruby/2.2.4/2015-10-06) + date: + - Sun, 20 Dec 2015 12:05:16 GMT + content-length: + - '96' + connection: + - Keep-Alive + set-cookie: + - __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/ + body: + encoding: UTF-8 + string: '{"id":2,"language":"Polyglot::Language::Python::Python2Point7","memory_limit":32,"time_limit":5}' + http_version: + recorded_at: Sun, 20 Dec 2015 12:05:17 GMT +recorded_with: VCR 3.0.0 diff --git a/spec/fixtures/vcr/cassettes/programming_evaluation/package.yml b/spec/fixtures/vcr/cassettes/programming_evaluation/package.yml new file mode 100644 index 0000000..634559a --- /dev/null +++ b/spec/fixtures/vcr/cassettes/programming_evaluation/package.yml @@ -0,0 +1,173 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/courses/assessment/programming_evaluations/3 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - ActiveRestClient/1.2.0 + Connection: + - Keep-Alive + Accept: + - application/hal+json, application/json;q=0.5 + X-User-Email: + - test@example.org + X-User-Token: + - YOUR_TOKEN_HERE + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: + headers: + x-frame-options: + - SAMEORIGIN + x-xss-protection: + - 1; mode=block + x-content-type-options: + - nosniff + content-type: + - application/json; charset=utf-8 + cache-control: + - no-store, must-revalidate, private, max-age=0 + x-request-id: + - 9cfcd480-2827-4ac1-8c00-b19674dbe372 + x-runtime: + - '0.462651' + x-miniprofiler-ids: + - '["nluzcn8efynh6p1p6bsk"]' + server: + - WEBrick/1.3.1 (Ruby/2.2.4/2015-10-06) + date: + - Sun, 20 Dec 2015 23:59:10 GMT + content-length: + - '96' + connection: + - Keep-Alive + set-cookie: + - __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/ + body: + encoding: UTF-8 + string: '{"id":3,"language":"Polyglot::Language::Python::Python2Point7","memory_limit":32,"time_limit":5}' + http_version: + recorded_at: Sun, 20 Dec 2015 23:59:11 GMT +- request: + method: get + uri: http://localhost:3000/courses/assessment/programming_evaluations/3/package + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - ActiveRestClient/1.2.0 + Connection: + - Keep-Alive + Accept: + - application/hal+json, application/json;q=0.5 + X-User-Email: + - test@example.org + X-User-Token: + - YOUR_TOKEN_HERE + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 302 + message: + headers: + x-frame-options: + - SAMEORIGIN + x-xss-protection: + - 1; mode=block + x-content-type-options: + - nosniff + location: + - http://localhost:3000/downloads/d20151221-7356-23qufp/programming-import20151221-7356-1cysvr4 + content-type: + - text/html; charset=utf-8 + cache-control: + - no-cache + x-request-id: + - 411abbf1-f768-4a6e-be53-1ac5a79e13bd + x-runtime: + - '0.367925' + server: + - WEBrick/1.3.1 (Ruby/2.2.4/2015-10-06) + date: + - Sun, 20 Dec 2015 23:59:12 GMT + content-length: + - '159' + connection: + - Keep-Alive + set-cookie: + - __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/ + body: + encoding: UTF-8 + string: You are being redirected. + http_version: + recorded_at: Sun, 20 Dec 2015 23:59:13 GMT +- request: + method: get + uri: http://localhost:3000/downloads/d20151221-7356-23qufp/programming-import20151221-7356-1cysvr4 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - ActiveRestClient/1.2.0 + Connection: + - Keep-Alive + Accept: + - application/hal+json, application/json;q=0.5 + X-User-Email: + - test@example.org + X-User-Token: + - YOUR_TOKEN_HERE + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: + headers: + last-modified: + - Sun, 20 Dec 2015 23:58:04 GMT + content-type: + - text/plain + content-length: + - '564' + cache-control: + - no-store, must-revalidate, private, max-age=0 + x-miniprofiler-ids: + - '["kkk4pzhbb8gdw4vfdkbk","nluzcn8efynh6p1p6bsk","bzh7gvapkh9f3tbksdq"]' + server: + - WEBrick/1.3.1 (Ruby/2.2.4/2015-10-06) + date: + - Sun, 20 Dec 2015 23:59:14 GMT + connection: + - Keep-Alive + set-cookie: + - __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/, __profilin=p%3Dt; path=/ + body: + encoding: ASCII-8BIT + string: !binary |- + UEsDBAoAAAAAAKt7iEcAAAAAAAAAAAAAAAAIAAAATWFrZWZpbGVQSwMEFAAA + AAAAs3uIRwAAAAAAAAAAAAAAAAsAAABzdWJtaXNzaW9uL1BLAwQKAAAAAAC1 + e4hHAAAAAAAAAAAAAAAAFgAAAHN1Ym1pc3Npb24vX19pbml0X18ucHlQSwME + FAAAAAAAsHuIRwAAAAAAAAAAAAAAAAYAAAB0ZXN0cy9QSwECPwAKAAAAAACr + e4hHAAAAAAAAAAAAAAAACAAkAAAAAAAAACAAAAAAAAAATWFrZWZpbGUKACAA + AAAAAAEAGAA8WkUnijHRATxaRSeKMdEBPFpFJ4ox0QFQSwECPwAUAAAAAACz + e4hHAAAAAAAAAAAAAAAACwAkAAAAAAAAABAAAAAmAAAAc3VibWlzc2lvbi8K + ACAAAAAAAAEAGAAg0+MwijHRASDT4zCKMdEBINPjMIox0QFQSwECPwAKAAAA + AAC1e4hHAAAAAAAAAAAAAAAAFgAkAAAAAAAAACAAAABPAAAAc3VibWlzc2lv + bi9fX2luaXRfXy5weQoAIAAAAAAAAQAYANf2ATSKMdEB1/YBNIox0QHX9gE0 + ijHRAVBLAQI/ABQAAAAAALB7iEcAAAAAAAAAAAAAAAAGACQAAAAAAAAAEAAA + AIMAAAB0ZXN0cy8KACAAAAAAAAEAGADwz2UtijHRAfDPZS2KMdEB8M9lLYox + 0QFQSwUGAAAAAAQABAB3AQAApwAAAAAA + http_version: + recorded_at: Sun, 20 Dec 2015 23:59:14 GMT +recorded_with: VCR 3.0.0 diff --git a/spec/support/vcr.rb b/spec/support/vcr.rb new file mode 100644 index 0000000..2e9a24e --- /dev/null +++ b/spec/support/vcr.rb @@ -0,0 +1,9 @@ +require 'vcr' + +Coursemology::Evaluator::Client.initialize('http://localhost:3000', 'test@example.org', + 'YOUR_TOKEN_HERE') + +VCR.configure do |c| + c.cassette_library_dir = 'spec/fixtures/vcr/cassettes' + c.hook_into :faraday +end