et 0.5.9 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 62871439d06d15d1b7b78b7493a5165f316d28d3
4
- data.tar.gz: 8a415980a7d4c513faec60ebf3b1f80b370d6592
3
+ metadata.gz: 6e414688a6eb0fc5a464071284eaad87cf914f16
4
+ data.tar.gz: 647e0fbd0c9fadbe733f480e4d29db3d06e6a18a
5
5
  SHA512:
6
- metadata.gz: 09f4f85e6be87779eb493370b0befc626507a581508e3558703ae5ff70f2470d77e3951fe816b565a2ac97dd2d69f8c3ac2841593062039dcab1f06c8e55bbb6
7
- data.tar.gz: c9d81101825e76f1a805845a2549b8baf46c9f8a8f55c2a6bf7be0cf6c27a695c6a27d9a659869b1a2d08303c80665080c923d06f81dc29d2c0d8ab2b2662f62
6
+ metadata.gz: f8b87ae613c19d680bc2219b596e980351f04ddf9baee09efc1ce1624f9885e150db28312b8430c983ceccb90e78a701128afb8868607274dd6bcbdcf5515ec0
7
+ data.tar.gz: 7cdb0f85e3fecc7aa82431e8d3e1cda5d745b65582ccfbefe8539868ab29e19e5ea161796e7d54c12d2ab6c7d019185d0f380e78e31208add0ec1a747e5d74b2
@@ -1,9 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- et (0.5.9)
4
+ et (0.6.0)
5
+ faraday (~> 0.9)
6
+ faraday_middleware (~> 0.10)
5
7
  gli (= 2.11.0)
6
8
  multipart-post (~> 2.0)
9
+ rake (~> 10)
7
10
  rspec (~> 3.0)
8
11
  rspec-mocks (~> 3.0)
9
12
 
@@ -12,6 +15,10 @@ GEM
12
15
  specs:
13
16
  coderay (1.1.1)
14
17
  diff-lcs (1.2.5)
18
+ faraday (0.9.2)
19
+ multipart-post (>= 1.2, < 3)
20
+ faraday_middleware (0.10.0)
21
+ faraday (>= 0.7.4, < 0.10)
15
22
  gli (2.11.0)
16
23
  method_source (0.8.2)
17
24
  multipart-post (2.0.0)
@@ -20,19 +27,19 @@ GEM
20
27
  method_source (~> 0.8.1)
21
28
  slop (~> 3.4)
22
29
  rake (10.5.0)
23
- rspec (3.4.0)
24
- rspec-core (~> 3.4.0)
25
- rspec-expectations (~> 3.4.0)
26
- rspec-mocks (~> 3.4.0)
27
- rspec-core (3.4.4)
28
- rspec-support (~> 3.4.0)
29
- rspec-expectations (3.4.0)
30
+ rspec (3.5.0)
31
+ rspec-core (~> 3.5.0)
32
+ rspec-expectations (~> 3.5.0)
33
+ rspec-mocks (~> 3.5.0)
34
+ rspec-core (3.5.4)
35
+ rspec-support (~> 3.5.0)
36
+ rspec-expectations (3.5.0)
30
37
  diff-lcs (>= 1.2.0, < 2.0)
31
- rspec-support (~> 3.4.0)
32
- rspec-mocks (3.4.1)
38
+ rspec-support (~> 3.5.0)
39
+ rspec-mocks (3.5.0)
33
40
  diff-lcs (>= 1.2.0, < 2.0)
34
- rspec-support (~> 3.4.0)
35
- rspec-support (3.4.1)
41
+ rspec-support (~> 3.5.0)
42
+ rspec-support (3.5.0)
36
43
  slop (3.6.0)
37
44
 
38
45
  PLATFORMS
@@ -41,7 +48,6 @@ PLATFORMS
41
48
  DEPENDENCIES
42
49
  et!
43
50
  pry (~> 0)
44
- rake (~> 10)
45
51
 
46
52
  BUNDLED WITH
47
- 1.12.5
53
+ 1.13.5
data/README.md CHANGED
@@ -28,3 +28,20 @@ COMMANDS
28
28
  submit - Submit the lesson in this directory.
29
29
  test - Run an exercise test suite.
30
30
  ```
31
+
32
+ ### Releasing New Versions
33
+
34
+ Bundler provided `gem_tasks` have been incorporated into this libraries
35
+ `Rakefile`. Thankfully these tasks make releasing new gem versions a snap!
36
+
37
+ To release a new version of this gem:
38
+
39
+ 1. Bump the version according to [semantic versioning](http://semver.org/)
40
+ 2. Perform a git commit
41
+ 3. Run `rake release` from the project root
42
+
43
+ Bundler's provided rake task will appropriately push a tag to GitHub and the gem
44
+ itself to [rubygems.org](https://rubygems.org)
45
+
46
+ _Note:_ in order to release the gem you must be an authorized owner of it on
47
+ [rubygems.org](https://rubygems.org)
data/et.gemspec CHANGED
@@ -19,10 +19,12 @@ DESC
19
19
  s.bindir = "bin"
20
20
  s.executables << "et"
21
21
  s.license = "MIT"
22
- s.add_development_dependency("rake", "~> 10")
23
22
  s.add_development_dependency("pry", '~> 0')
24
23
  s.add_runtime_dependency("rspec", "~> 3.0")
24
+ s.add_runtime_dependency("rake", "~> 10")
25
25
  s.add_runtime_dependency("rspec-mocks", "~> 3.0")
26
26
  s.add_runtime_dependency("multipart-post", "~> 2.0")
27
27
  s.add_runtime_dependency("gli", "2.11.0")
28
+ s.add_runtime_dependency("faraday", "~> 0.9")
29
+ s.add_runtime_dependency("faraday_middleware", "~> 0.10")
28
30
  end
data/lib/et.rb CHANGED
@@ -3,6 +3,7 @@ require_relative "et/version"
3
3
  require_relative "et/runner"
4
4
  require_relative "et/operating_system"
5
5
  require_relative "et/api"
6
+ require_relative "et/submission_file_list"
6
7
  require_relative "et/config"
7
8
  require_relative "et/formatter"
8
9
  require_relative "et/lesson"
@@ -1,9 +1,9 @@
1
- require "net/http/post/multipart"
2
1
  require "securerandom"
3
2
  require "base64"
4
3
  require "json"
5
4
  require "openssl"
6
5
 
6
+ require_relative "fallback_connection"
7
7
  module ET
8
8
  class API
9
9
  attr_reader :host, :username, :token
@@ -15,30 +15,29 @@ module ET
15
15
  end
16
16
 
17
17
  def list_lessons
18
- request = Net::HTTP::Get.new(lessons_url)
19
- request["Authorization"] = auth_header
20
-
21
- response = issue_request(request)
22
- JSON.parse(response.body, symbolize_names: true)[:lessons]
18
+ resp = nil
19
+ api_client.with_ssl_fallback do |client|
20
+ resp = client.get('/lessons.json', :submittable => 1)
21
+ end
22
+ resp.body['lessons']
23
23
  end
24
24
 
25
25
  def get_lesson(slug)
26
- request = Net::HTTP::Get.new(lesson_url(slug))
27
- request["Authorization"] = auth_header
28
-
29
- response = issue_request(request)
30
-
31
- body = JSON.parse(response.body, symbolize_names: true)
32
- body[:lesson]
26
+ resp = nil
27
+ api_client.with_ssl_fallback do |client|
28
+ resp = client.get(lesson_url(slug), :submittable => 1)
29
+ end
30
+ resp.body['lesson']
33
31
  end
34
32
 
35
33
  def download_file(url)
36
- uri = URI(url)
34
+ response = nil
37
35
  dest = random_filename
38
36
 
39
- request = Net::HTTP::Get.new(uri.path)
40
- response = issue_request(request, url)
41
- if response.code == "200"
37
+ download_client(url).with_ssl_fallback do |client|
38
+ response = client.get(URI(url).path)
39
+ end
40
+ if response.status == 200
42
41
  open(dest, 'wb') do |file|
43
42
  file.write(response.body)
44
43
  end
@@ -50,66 +49,47 @@ module ET
50
49
 
51
50
  def submit_lesson(lesson)
52
51
  submission_file = lesson.archive!
53
- url = submission_url(lesson.slug)
54
-
55
- File.open(submission_file) do |f|
56
- request = Net::HTTP::Post::Multipart.new(url.path,
57
- "submission[archive]" => UploadIO.new(f, "application/x-tar", "archive.tar.gz"))
58
- request["Authorization"] = auth_header
59
-
60
- issue_request(request)
52
+ io = Faraday::UploadIO.new(submission_file, "application/x-tar")
53
+ resp = nil
54
+ api_client.with_ssl_fallback do |client|
55
+ resp = client.post(submission_url(lesson.slug),
56
+ "submission" => { "archive" => io})
61
57
  end
58
+ resp
62
59
  end
63
60
 
64
61
  private
65
- def issue_request(request, url = nil)
66
- uri = URI.parse(url || @host)
67
- begin
68
- Net::HTTP.start(uri.host, uri.port,
69
- use_ssl: uri.scheme == "https") do |http|
70
-
71
- http.request(request)
72
- end
73
- rescue OpenSSL::SSL::SSLError => e
74
- if operating_system.platform_family?(:windows)
75
- https = Net::HTTP.new(uri.host, uri.port)
76
- https.verify_mode = OpenSSL::SSL::VERIFY_NONE
77
- https.use_ssl = uri.scheme == 'https'
78
- https.start do |http|
79
- http.request(request)
80
- end
81
- else
82
- raise e
83
- end
84
- end
85
- end
86
-
87
62
  def lesson_url(slug)
88
- URI.join(host, "lessons/#{slug}.json?submittable=1")
89
- end
90
-
91
- def lessons_url
92
- URI.join(host, "lessons.json?submittable=1")
63
+ "/lessons/#{slug}.json"
93
64
  end
94
65
 
95
66
  def submission_url(slug)
96
- URI.join(host, "lessons/#{slug}/submissions.json")
67
+ "/lessons/#{slug}/submissions.json"
97
68
  end
98
69
 
99
70
  def random_filename
100
71
  File.join(Dir.mktmpdir, SecureRandom.hex)
101
72
  end
102
73
 
103
- def credentials
104
- Base64.strict_encode64("#{username}:#{token}")
105
- end
74
+ def api_client
75
+ @api_client ||= ET::FallbackConnection.new(:url => @host) do |client|
76
+ client.request :multipart
106
77
 
107
- def auth_header
108
- "Basic #{credentials}"
78
+ client.request :url_encoded
79
+ client.request :basic_auth, username, token
80
+
81
+ client.response :json, :content_type => /\bjson$/
82
+
83
+ client.adapter Faraday.default_adapter
84
+ end
109
85
  end
110
86
 
111
- def operating_system
112
- @os ||= ET::OperatingSystem.new
87
+ def download_client(url)
88
+ uri = URI(url)
89
+ scheme_and_host = [uri.scheme, uri.host].join('://')
90
+ ET::FallbackConnection.new(:url => scheme_and_host) do |client|
91
+ client.adapter Faraday.default_adapter
92
+ end
113
93
  end
114
94
  end
115
95
  end
@@ -0,0 +1,29 @@
1
+ require "faraday"
2
+ require "faraday_middleware"
3
+
4
+ module ET
5
+ class FallbackConnection
6
+ def initialize(opts = {}, &block)
7
+ @connection = Faraday.new(opts, &block)
8
+
9
+ @fallback_connection = Faraday.new(opts.merge(:ssl => {:verify => false}))
10
+ end
11
+
12
+ def with_ssl_fallback(&block)
13
+ begin
14
+ block.call(@connection)
15
+ rescue OpenSSL::SSL::SSLError => e
16
+ if operating_system.platform_family?(:windows)
17
+ block.call(@fallback_connection)
18
+ else
19
+ raise e
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+ def operating_system
26
+ @os ||= ET::OperatingSystem.new
27
+ end
28
+ end
29
+ end
@@ -17,16 +17,16 @@ module ET
17
17
  File.open(filepath, "wb") do |file|
18
18
  Zlib::GzipWriter.wrap(file) do |gz|
19
19
  Gem::Package::TarWriter.new(gz) do |tar|
20
- Dir.glob(File.join(dir, "**/*")).each do |file|
21
- relative_path = file.gsub(dir + "/", "")
22
- if !ignored_files.include?(relative_path)
23
- if FileTest.directory?(file)
24
- tar.mkdir(relative_path, 0755)
25
- else
26
- file_contents = File.read(file)
27
- tar.add_file_simple("./" + relative_path, 0555, file_contents.bytesize) do |io|
28
- io.write(file_contents)
29
- end
20
+ ET::SubmissionFileList.new(dir).each do |file|
21
+ relative_path = file
22
+ absolute_path = File.join(dir, file)
23
+
24
+ if FileTest.directory?(absolute_path)
25
+ tar.mkdir(relative_path, 0755)
26
+ else
27
+ file_contents = File.read(absolute_path)
28
+ tar.add_file_simple("./" + relative_path, 0555, file_contents.bytesize) do |io|
29
+ io.write(file_contents)
30
30
  end
31
31
  end
32
32
  end
@@ -51,10 +51,6 @@ module ET
51
51
  !dir.nil?
52
52
  end
53
53
 
54
- def ignored_files
55
- (config["ignore"] || []) + [".lesson.yml"]
56
- end
57
-
58
54
  protected
59
55
 
60
56
  def config
@@ -40,7 +40,7 @@ module ET
40
40
  desc "List available lessons."
41
41
  command :list do |c|
42
42
  c.action do |_global_options, _options, _cmdargs|
43
- Formatter.print_table(api.list_lessons, :slug, :title, :type)
43
+ Formatter.print_table(api.list_lessons, 'slug', 'title', 'type')
44
44
  end
45
45
  end
46
46
 
@@ -49,7 +49,7 @@ module ET
49
49
  c.action do |_global_options, _options, cmdargs|
50
50
  cmdargs.each do |slug|
51
51
  lesson = api.get_lesson(slug)
52
- archive = api.download_file(lesson[:archive_url])
52
+ archive = api.download_file(lesson['archive_url'])
53
53
  archive_manager = ET::ArchiveManager.new(archive, cwd)
54
54
  archive_manager.unpack
55
55
 
@@ -0,0 +1,50 @@
1
+ require "rake/file_list"
2
+
3
+ module ET
4
+ class SubmissionFileList
5
+ include Enumerable
6
+ DEFAULT_IGNORE_GLOBS = [
7
+ '.lesson.yml',
8
+ 'node_modules/**/*'
9
+ ]
10
+
11
+ def initialize(path)
12
+ @path = path
13
+ end
14
+
15
+ def files
16
+ unless @files
17
+ @files = Rake::FileList[File.join(@path, "**/*")]
18
+ ignore_globs.each do |glob|
19
+ @files = @files.exclude(File.join(@path, glob))
20
+ end
21
+ @files = @files.sub(File.join(@path, "/"), "")
22
+ end
23
+
24
+ @files
25
+ end
26
+
27
+ def each(&block)
28
+ files.each do |file|
29
+ block.call(file)
30
+ end
31
+ end
32
+
33
+ protected
34
+ def ignore_globs
35
+ lesson_ignore_globs + [] + DEFAULT_IGNORE_GLOBS
36
+ end
37
+
38
+ def lesson_ignore_globs
39
+ unless @lesson_ignore_globs
40
+ lesson_yml = File.join(@path, '.lesson.yml')
41
+ if FileTest.exists?(lesson_yml)
42
+ @lesson_ignore_globs = YAML.load_file(lesson_yml)['ignore'] || []
43
+ else
44
+ @lesson_ignore_globs = []
45
+ end
46
+ end
47
+ @lesson_ignore_globs
48
+ end
49
+ end
50
+ end
@@ -1,3 +1,3 @@
1
1
  module ET
2
- VERSION = "0.5.9"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -1,38 +1,38 @@
1
- describe "get lesson" do
1
+ describe 'get lesson' do
2
2
  let(:lesson_info) do
3
3
  {
4
- title: "Some Challenge",
5
- slug: "some-challenge",
6
- archive_url: "http://localhost:3000/some-challenge.tar.gz"
4
+ 'title' => 'Some Challenge',
5
+ 'slug' => 'some-challenge',
6
+ 'archive_url' => "http://localhost:3000/some-challenge.tar.gz"
7
7
  }
8
8
  end
9
9
 
10
10
  let(:sample_archive_path) do
11
- project_root.join("spec/data/some-challenge.tar.gz")
11
+ project_root.join('spec/data/some-challenge.tar.gz')
12
12
  end
13
13
 
14
- context "when in a working area" do
15
- it "downloads and extracts the lesson" do
16
- tmp_archive_path = File.join(Dir.tmpdir, "some-challenge.tar.gz")
17
- system("cp", sample_archive_path.to_s, tmp_archive_path)
14
+ context 'when in a working area' do
15
+ it 'downloads and extracts the lesson' do
16
+ tmp_archive_path = File.join(Dir.tmpdir, 'some-challenge.tar.gz')
17
+ system('cp', sample_archive_path.to_s, tmp_archive_path)
18
18
 
19
19
  expect_any_instance_of(ET::API).to receive(:get_lesson).
20
- with("some-challenge").
20
+ with('some-challenge').
21
21
  and_return(lesson_info)
22
22
 
23
23
  expect_any_instance_of(ET::API).to receive(:download_file).
24
- with("http://localhost:3000/some-challenge.tar.gz").
24
+ with('http://localhost:3000/some-challenge.tar.gz').
25
25
  and_return(tmp_archive_path)
26
26
 
27
- Dir.mktmpdir("test") do |tmpdir|
27
+ Dir.mktmpdir('test') do |tmpdir|
28
28
  write_sample_config_to(tmpdir)
29
29
 
30
30
  runner = ET::Runner.new(tmpdir)
31
31
  _, _ = capture_output do
32
- expect(runner.go(["get", "some-challenge"])).to eq(0)
32
+ expect(runner.go(['get', 'some-challenge'])).to eq(0)
33
33
  end
34
34
 
35
- ["some-challenge/README.md", "some-challenge/sample.rb"].each do |filename|
35
+ ['some-challenge/README.md', 'some-challenge/sample.rb'].each do |filename|
36
36
  path = File.join(tmpdir, filename)
37
37
  expect(File.exist?(path)).to eq(true)
38
38
  end
@@ -2,7 +2,7 @@ describe "list lessons" do
2
2
  let(:sample_lessons_file) { project_root.join("spec/data/lessons.json") }
3
3
 
4
4
  let(:sample_lessons) do
5
- JSON.parse(File.read(sample_lessons_file), symbolize_names: true)[:lessons]
5
+ JSON.parse(File.read(sample_lessons_file))['lessons']
6
6
  end
7
7
 
8
8
  it "prints the titles and slug" do
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: "Bloated Challenge"
3
+ type: "challenge"
4
+ description: "Some description."
5
+ ignore:
6
+ - "bloated-challenge.md"
7
+ - "rando_folder/**/*"
@@ -0,0 +1,3 @@
1
+ ### Instructions
2
+
3
+ Do something.
@@ -0,0 +1 @@
1
+ alert('please do not include this file');
@@ -0,0 +1 @@
1
+ # YOUR CODE GOES HERE
@@ -0,0 +1 @@
1
+ console.log('I am random');
@@ -10,26 +10,24 @@ describe ET::API do
10
10
 
11
11
  describe "lessons" do
12
12
  it "queries for a list of lessons" do
13
- request = {}
14
- response = double
15
- http = double
16
- expect(Net::HTTP::Get).to receive(:new).
17
- with(lessons_uri).
18
- and_return(request)
19
- expect(Net::HTTP).to receive(:start).with(
20
- lessons_uri.host,
21
- lessons_uri.port,
22
- use_ssl: lessons_uri.scheme == "https").
23
- and_yield(http)
24
- expect(http).to receive(:request).and_return(response)
25
- expect(response).to receive(:body).and_return(lessons_response)
13
+ client = Faraday.new do |builder|
14
+ builder.response :json
15
+
16
+ builder.adapter :test do |stubs|
17
+ stubs.get("/lessons.json") do
18
+ [200, {}, lessons_response]
19
+ end
20
+ end
21
+ end
22
+
23
+ allow_any_instance_of(ET::FallbackConnection).to receive(:with_ssl_fallback).and_yield(client)
26
24
 
27
25
  results = api.list_lessons
28
26
 
29
27
  expect(results.count).to eq(3)
30
- expect(results[0][:title]).to eq("Max Number")
31
- expect(results[0][:slug]).to eq("max-number")
32
- expect(results[0][:type]).to eq("exercise")
28
+ expect(results[0]['title']).to eq("Max Number")
29
+ expect(results[0]['slug']).to eq("max-number")
30
+ expect(results[0]['type']).to eq("exercise")
33
31
  end
34
32
 
35
33
  let(:lesson_response) do
@@ -37,99 +35,67 @@ describe ET::API do
37
35
  end
38
36
 
39
37
  it "queries for a single lesson" do
40
- request = {}
41
- response = double
42
- http = double
43
-
44
- lesson_uri = URI("http://localhost:3000/lessons/rock-paper-scissors.json?submittable=1")
45
- expect(Net::HTTP::Get).to receive(:new).
46
- with(lesson_uri).
47
- and_return(request)
48
- expect(Net::HTTP).to receive(:start).with(
49
- lesson_uri.host,
50
- lesson_uri.port,
51
- use_ssl: lesson_uri.scheme == "https").
52
- and_yield(http)
53
- expect(http).to receive(:request).and_return(response)
54
- expect(response).to receive(:body).and_return(lesson_response)
55
-
56
- result = api.get_lesson("rock-paper-scissors")
38
+ client = Faraday.new do |builder|
39
+ builder.response :json
57
40
 
58
- expect(result[:title]).to eq("Rock, Paper, Scissors")
59
- expect(result[:archive_url]).to eq("http://example.com/rock-paper-scissors.tar.gz")
60
- end
61
- end
41
+ builder.adapter :test do |stubs|
42
+ stubs.get("/lessons/rock-paper-scissors.json") do
43
+ [200, {}, lesson_response]
44
+ end
45
+ end
46
+ end
62
47
 
63
- context 'ssl verification' do
64
- it 're-raises an exception for non Windows machines' do
65
- dbl_os = double
66
- allow(dbl_os).to receive(:platform_family?).with(:windows).and_return(false)
67
- expect(ET::OperatingSystem).to receive(:new).and_return(dbl_os)
48
+ allow_any_instance_of(ET::FallbackConnection).
49
+ to receive(:with_ssl_fallback).and_yield(client)
68
50
 
69
- expect(Net::HTTP).to receive(:start).and_raise(OpenSSL::SSL::SSLError)
70
- expect{ api.list_lessons }.to raise_error(OpenSSL::SSL::SSLError)
71
- end
51
+ result = api.get_lesson("rock-paper-scissors")
72
52
 
73
- it 'swallows the exception for windows machines and reissues' do
74
- http = double
75
- allow(http).to receive(:start).and_yield(http)
76
- allow(http).to receive(:verify_mode=)
77
- allow(http).to receive(:use_ssl=)
78
- response = double
79
-
80
- allow(http).to receive(:request).and_return(response)
81
- allow(response).to receive(:body).and_return(lessons_response)
82
-
83
- allow(Net::HTTP).to receive(:start).
84
- with(
85
- lessons_uri.host,
86
- lessons_uri.port,
87
- use_ssl: lessons_uri.scheme == 'https').
88
- and_raise(OpenSSL::SSL::SSLError)
89
-
90
- expect(Net::HTTP).to receive(:new).with(
91
- lessons_uri.host,
92
- lessons_uri.port).
93
- and_return(http)
94
-
95
- dbl_os = double
96
- allow(dbl_os).to receive(:platform_family?).and_return(:windows)
97
- allow(ET::OperatingSystem).to receive(:new).and_return(dbl_os)
98
-
99
- api.list_lessons
53
+ expect(result['title']).to eq("Rock, Paper, Scissors")
54
+ expect(result['archive_url']).to eq('http://example.com/rock-paper-scissors.tar.gz')
100
55
  end
101
- end
56
+ end
102
57
 
103
58
  context 'downloading files' do
104
59
  it 'returns nil when a 404 is encountered' do
60
+ filename = 'somefile.tar.gz'
61
+ client = Faraday.new do |builder|
62
+ builder.response :json
105
63
 
106
- http = double
107
- response = double
108
- allow(response).to receive(:code).and_return("404")
109
- allow(http).to receive(:request).and_return(response)
110
- allow(Net::HTTP).to receive(:start).and_yield(http)
64
+ builder.adapter :test do |stubs|
65
+ stubs.get("/#{filename}") do
66
+ [404, {}, '']
67
+ end
68
+ end
69
+ end
111
70
 
112
- expect(api.download_file("http://example.com/somefile.tar.gz")).to be_nil
71
+ allow_any_instance_of(ET::FallbackConnection).
72
+ to receive(:with_ssl_fallback).and_yield(client)
73
+
74
+ expect(api.download_file("http://example.com/#{filename}")).to be_nil
113
75
  end
76
+
114
77
  it 'returns a local file when a challenge is successfully downloaded' do
115
78
  path = '/tmp/et'
116
- filename = 'fab'
79
+ filename = 'some-challenge.tar.gz'
117
80
 
118
81
  FileUtils.rm_rf(File.join(path, filename))
119
82
  FileUtils.mkdir_p(path)
120
83
 
84
+ filename = 'somefile.tar.gz'
85
+ client = Faraday.new do |builder|
86
+ builder.adapter :test do |stubs|
87
+ stubs.get("/#{filename}") do
88
+ [200, {}, '']
89
+ end
90
+ end
91
+ end
92
+
93
+ allow_any_instance_of(ET::FallbackConnection).
94
+ to receive(:with_ssl_fallback).and_yield(client)
121
95
  allow(Dir).to receive(:mktmpdir).and_return(path)
122
96
  allow(SecureRandom).to receive(:hex).and_return(filename)
123
97
 
124
- http = double
125
- response = double
126
- file_contents = File.read(File.join(File.dirname(__FILE__), "../data/some-challenge.tar.gz"))
127
- allow(response).to receive(:body).and_return(file_contents)
128
- allow(response).to receive(:code).and_return("200")
129
- allow(http).to receive(:request).and_return(response)
130
- allow(Net::HTTP).to receive(:start).and_yield(http)
131
-
132
- url = 'http://example.com/some-challenge.tar.gz'
98
+ url = "http://example.com/#{filename}"
133
99
 
134
100
  expect(api.download_file(url)).to eql(File.join(path, filename))
135
101
  end
@@ -0,0 +1,42 @@
1
+ describe ET::FallbackConnection do
2
+ let(:cnn) do
3
+ ET::FallbackConnection.new(:url => 'http://localhost')
4
+ end
5
+
6
+ context 'ssl verification' do
7
+ it 're-raises an exception for non Windows machines' do
8
+ dbl_os = double
9
+ allow(dbl_os).to receive(:platform_family?).with(:windows).and_return(false)
10
+ expect(ET::OperatingSystem).to receive(:new).and_return(dbl_os)
11
+
12
+ allow_any_instance_of(Faraday::Connection).
13
+ to receive(:get).and_raise(OpenSSL::SSL::SSLError)
14
+
15
+ expect{ cnn.with_ssl_fallback{|client| client.get('/') }}.
16
+ to raise_error(OpenSSL::SSL::SSLError)
17
+ end
18
+
19
+ it 'swallows the exception for windows machines and reissues' do
20
+ dbl_os = double
21
+ allow(dbl_os).to receive(:platform_family?).and_return(:windows)
22
+ allow(ET::OperatingSystem).to receive(:new).and_return(dbl_os)
23
+
24
+ called_twice = false
25
+ allow_any_instance_of(Faraday::Connection).to receive(:get) do |*args|
26
+ if args[0].ssl.verify != false
27
+ #simulate a windows SSL verification failed
28
+ raise OpenSSL::SSL::SSLError
29
+ elsif args[0].ssl.verify == false
30
+ #flip the switch that the request was reissued without SSL verification
31
+ called_twice = true
32
+ double(:body => '{}')
33
+ end
34
+ end
35
+
36
+ cnn.with_ssl_fallback do |client|
37
+ client.get('/')
38
+ end
39
+ expect(called_twice).to be(true)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ describe ET::SubmissionFileList do
2
+ let(:file_list) do
3
+ path = File.expand_path(File.join(
4
+ File.dirname(__FILE__), "../data/bloated-challenge"))
5
+ ET::SubmissionFileList.new(path)
6
+ end
7
+
8
+ it 'includes a relevant file' do
9
+ expect(file_list).to include('problem.rb')
10
+ end
11
+
12
+ it 'ignores a standard file' do
13
+ expect(file_list).to_not include('sample-challenge.md')
14
+ end
15
+
16
+ it 'ignores a file included in the default globs' do
17
+ expect(file_list).to_not include('node_modules/somefile.js')
18
+ end
19
+
20
+ it 'ignores a file included in a glob' do
21
+ expect(file_list).to_not include('node_modules/boo/somefile.js')
22
+ end
23
+
24
+ it 'ignores a file included in the lesson.yml ignore' do
25
+ expect(file_list).to_not include('rando_folder/rando_file.js')
26
+ end
27
+ end
@@ -49,9 +49,4 @@ RSpec.configure do |config|
49
49
  config.include SampleFiles
50
50
  config.include PathHelper
51
51
  config.include ArchiveHelper
52
-
53
- config.before :each do
54
- allow(Net::HTTP).to receive(:start)
55
- allow(Net::HTTP).to receive(:get)
56
- end
57
52
  end
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: et
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.9
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Sheehan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-15 00:00:00.000000000 Z
11
+ date: 2016-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rake
14
+ name: pry
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '10'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '10'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: pry
28
+ name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
33
+ version: '3.0'
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '3.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.0'
47
+ version: '10'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.0'
54
+ version: '10'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec-mocks
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
96
  version: 2.11.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: faraday
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.9'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.9'
111
+ - !ruby/object:Gem::Dependency
112
+ name: faraday_middleware
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.10'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.10'
97
125
  description: |
98
126
  Users can download challenges and submit their solutions via the command-line
99
127
  interface.
@@ -120,16 +148,23 @@ files:
120
148
  - lib/et/challenge.rb
121
149
  - lib/et/config.rb
122
150
  - lib/et/exercise.rb
151
+ - lib/et/fallback_connection.rb
123
152
  - lib/et/formatter.rb
124
153
  - lib/et/lesson.rb
125
154
  - lib/et/operating_system.rb
126
155
  - lib/et/runner.rb
156
+ - lib/et/submission_file_list.rb
127
157
  - lib/et/version.rb
128
158
  - spec/cli/get_lesson_spec.rb
129
159
  - spec/cli/init_spec.rb
130
160
  - spec/cli/list_lessons_spec.rb
131
161
  - spec/cli/run_exercise_test_suite_spec.rb
132
162
  - spec/cli/submit_lesson_spec.rb
163
+ - spec/data/bloated-challenge/.lesson.yml
164
+ - spec/data/bloated-challenge/bloated-challenge.md
165
+ - spec/data/bloated-challenge/node_modules/boo/somefile.js
166
+ - spec/data/bloated-challenge/problem.rb
167
+ - spec/data/bloated-challenge/rando_folder/rando_file.js
133
168
  - spec/data/challenge.json
134
169
  - spec/data/lessons.json
135
170
  - spec/data/sample-challenge/.lesson.yml
@@ -145,8 +180,10 @@ files:
145
180
  - spec/lib/challenge_spec.rb
146
181
  - spec/lib/config_spec.rb
147
182
  - spec/lib/exercise_spec.rb
183
+ - spec/lib/fallback_connection_spec.rb
148
184
  - spec/lib/lesson_spec.rb
149
185
  - spec/lib/operating_system_spec.rb
186
+ - spec/lib/submission_file_list_spec.rb
150
187
  - spec/spec_helper.rb
151
188
  - spec/support/helpers/archive_helper.rb
152
189
  - spec/support/helpers/output_catcher.rb
@@ -173,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
210
  version: '0'
174
211
  requirements: []
175
212
  rubyforge_project:
176
- rubygems_version: 2.4.5
213
+ rubygems_version: 2.4.5.1
177
214
  signing_key:
178
215
  specification_version: 4
179
216
  summary: Command-line interface for the event horizon.