judges 0.46.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5480ce66a6fbce4d6748a47f42240c77438ef09eed639f6744c762f94ce57ebe
4
- data.tar.gz: a445e36911b5dcc457a188fb1ff7a50251f6e19b60313c1185b4af70a773acdc
3
+ metadata.gz: 939f948ca702a406b8a92ef2b4a8e222a802dacdde67694fdb0ae875d781637e
4
+ data.tar.gz: d197222ead3037463310bcf9ec470e498a20ffc7ffb76c891859783fc4886fd4
5
5
  SHA512:
6
- metadata.gz: d4a52cb96f912acb0a97d842f132c2daf855771406253e9ff0bd5b2fa2ba17cbdb15b4e12919b8e41092b7ebc07c954c7fafbaaf4029eb57387075d9cd46e679
7
- data.tar.gz: 59d5df2eea5c531989709a7e60c183a4f8f10723e6e0df320ca58ce2a6a2f167c236713a110814eab49d91996e659e2e3ac5fb255a95a6a8516ebec9f874351c
6
+ metadata.gz: 533a6b4653caee694910d61e1a8704af571e9fcaf3340c7e4487a85e0a55cc5a25b9161bb2e0eef8ab8184237ab91b4067c027cfe29cb2a871868a674473c7ef
7
+ data.tar.gz: 8132e47e206bac2bdaeec650e0f86cd177445131cabd85cfe4146ca237b97eae7e83dd836f3cdd8a8e79bb879098804b1017a6ddfde8045b66f48b8b73fb2587
data/Gemfile.lock CHANGED
@@ -28,18 +28,18 @@ GEM
28
28
  ast (2.4.3)
29
29
  backtrace (0.4.1)
30
30
  base64 (0.3.0)
31
- baza.rb (0.5.1)
32
- backtrace (> 0)
33
- elapsed (> 0)
34
- faraday (> 0)
35
- faraday-http-cache (> 0)
36
- faraday-multipart (> 0)
37
- faraday-retry (> 0)
38
- iri (> 0)
39
- loog (> 0)
40
- retries (~> 0)
41
- tago (~> 0)
42
- typhoeus (~> 1.3)
31
+ baza.rb (0.8.0)
32
+ backtrace (~> 0.4)
33
+ elapsed (~> 0.0)
34
+ faraday (~> 2.13)
35
+ faraday-http-cache (~> 2.5)
36
+ faraday-multipart (~> 1.1)
37
+ faraday-retry (~> 2.3)
38
+ iri (~> 0.11)
39
+ loog (~> 0.6)
40
+ retries (~> 0.0)
41
+ tago (~> 0.0)
42
+ typhoeus (~> 1.4)
43
43
  bigdecimal (3.2.2)
44
44
  builder (3.3.0)
45
45
  concurrent-ruby (1.3.5)
@@ -180,7 +180,7 @@ GEM
180
180
  regexp_parser (2.10.0)
181
181
  retries (0.0.5)
182
182
  rexml (3.4.1)
183
- rubocop (1.76.0)
183
+ rubocop (1.76.1)
184
184
  json (~> 2.3)
185
185
  language_server-protocol (~> 3.17.0.2)
186
186
  lint_roller (~> 1.1.0)
@@ -191,7 +191,7 @@ GEM
191
191
  rubocop-ast (>= 1.45.0, < 2.0)
192
192
  ruby-progressbar (~> 1.7)
193
193
  unicode-display_width (>= 2.4.0, < 4.0)
194
- rubocop-ast (1.45.0)
194
+ rubocop-ast (1.45.1)
195
195
  parser (>= 3.3.7.2)
196
196
  prism (~> 1.4)
197
197
  rubocop-minitest (0.38.1)
data/bin/judges CHANGED
@@ -217,6 +217,44 @@ class JudgesGLI extend GLI::App
217
217
  c.flag([:retries], type: Integer, default_value: 3)
218
218
  run_it(c, 'pull')
219
219
  end
220
+
221
+ desc 'Download a durable from the server by ID'
222
+ command :download do |c|
223
+ c.desc 'Authentication token'
224
+ c.flag([:token])
225
+ c.desc 'Server IP/hostname'
226
+ c.flag([:host], default_value: 'api.zerocracy.com')
227
+ c.desc 'Server TCP port number'
228
+ c.flag([:port], default_value: 443, type: Integer)
229
+ c.desc 'Connection and read timeout in seconds'
230
+ c.flag([:timeout], default_value: 30, type: Integer)
231
+ c.desc 'Enable SSL connection'
232
+ c.switch([:ssl], default_value: true)
233
+ c.desc 'Unique identifier for the operation'
234
+ c.flag([:owner], default_value: 'default', type: String)
235
+ c.desc 'Number of retry attempts'
236
+ c.flag([:retries], type: Integer, default_value: 3)
237
+ run_it(c, 'download')
238
+ end
239
+
240
+ desc 'Upload a file as a durable to the server'
241
+ command :upload do |c|
242
+ c.desc 'Authentication token'
243
+ c.flag([:token])
244
+ c.desc 'Server IP/hostname'
245
+ c.flag([:host], default_value: 'api.zerocracy.com')
246
+ c.desc 'Server TCP port number'
247
+ c.flag([:port], default_value: 443, type: Integer)
248
+ c.desc 'Connection and read timeout in seconds'
249
+ c.flag([:timeout], default_value: 30, type: Integer)
250
+ c.desc 'Enable SSL connection'
251
+ c.switch([:ssl], default_value: true)
252
+ c.desc 'Unique identifier for the operation'
253
+ c.flag([:owner], default_value: 'default', type: String)
254
+ c.desc 'Number of retry attempts'
255
+ c.flag([:retries], type: Integer, default_value: 3)
256
+ run_it(c, 'upload')
257
+ end
220
258
  end
221
259
 
222
260
  exit JudgesGLI.run(ARGV) if ENV['GLI_TESTING'].nil?
@@ -7,6 +7,6 @@ Feature: Pull
7
7
  Scenario: Pull a small factbase, which is absent on the server
8
8
  Given We are online
9
9
  Given I make a temp directory
10
- Then I run bin/judges with "--verbose pull --token 00000000-0000-0000-0000-000000000000 --wait=15 {FAKE-NAME} simple.fb"
10
+ Then I run bin/judges with "--verbose pull --token ZRCY-00000000-0000-0000-0000-000000000000 --wait=15 {FAKE-NAME} simple.fb"
11
11
  Then Stdout contains "doesn't exist at api.zerocracy.com"
12
12
  And Exit code is zero
@@ -9,6 +9,6 @@ Feature: Push
9
9
  Given I make a temp directory
10
10
  Then I run bin/judges with "--verbose eval simple.fb '(0..1000).each { $fb.insert.foo = 42 }'"
11
11
  And Exit code is zero
12
- Then I run bin/judges with "push --token 00000000-0000-0000-0000-000000000000 --meta a:b --meta foo:bar --meta=pages_url:https://zerocracy.github.io/zerocracy.html --meta=duration:1055 {FAKE-NAME} simple.fb"
12
+ Then I run bin/judges with "push --token ZRCY-00000000-0000-0000-0000-000000000000 --meta a:b --meta foo:bar --meta=pages_url:https://zerocracy.github.io/zerocracy.html --meta=duration:1055 {FAKE-NAME} simple.fb"
13
13
  Then Stdout contains "Pushed"
14
14
  And Exit code is zero
@@ -51,14 +51,20 @@ Feature: Update
51
51
 
52
52
  Scenario: Skips the judge on lifetime running out
53
53
  Given I make a temp directory
54
- Then I have a "simple/simple.rb" file with content:
54
+ Then I have a "first/first.rb" file with content:
55
55
  """
56
56
  n = $fb.insert
57
+ n.type = 'first'
57
58
  sleep 1
58
59
  """
60
+ Then I have a "second/second.rb" file with content:
61
+ """
62
+ n = $fb.insert
63
+ n.type = 'second'
64
+ """
59
65
  Then I run bin/judges with "--verbose update --quiet --lifetime 1 --max-cycles 5 . simple.fb"
60
- Then Stdout contains "The 'simple' judge skipped, no time left"
61
- Then Stdout contains "Update completed in 2 cycle(s), did 1i/0d/0a"
66
+ Then Stdout contains "The 'second' judge skipped, no time left"
67
+ Then Stdout contains "Update completed in 1 cycle(s), did 1i/0d/1a"
62
68
  And Exit code is zero
63
69
 
64
70
  Scenario: Use options from a file
data/judges.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
10
10
  s.required_ruby_version = '>=3.2'
11
11
  s.name = 'judges'
12
- s.version = '0.46.0'
12
+ s.version = '0.48.0'
13
13
  s.license = 'MIT'
14
14
  s.summary = 'Command-Line Tool for a Factbase'
15
15
  s.description =
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require 'typhoeus'
7
+ require 'iri'
8
+ require 'baza-rb'
9
+ require 'elapsed'
10
+ require_relative '../../judges'
11
+
12
+ # The +download+ command.
13
+ #
14
+ # This class is instantiated by the +bin/judge+ command line interface. You
15
+ # are not supposed to instantiate it yourself.
16
+ #
17
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
18
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
19
+ # License:: MIT
20
+ class Judges::Download
21
+ # Initialize.
22
+ # @param [Loog] loog Logging facility
23
+ def initialize(loog)
24
+ @loog = loog
25
+ end
26
+
27
+ # Run the download command (called by the +bin/judges+ script).
28
+ # @param [Hash] opts Command line options (start with '--')
29
+ # @param [Array] args List of command line arguments
30
+ # @raise [RuntimeError] If not exactly two arguments provided
31
+ def run(opts, args)
32
+ raise 'Exactly two arguments required' unless args.size == 2
33
+ jname = args[0]
34
+ path = args[1]
35
+ name = File.basename(path)
36
+ baza = BazaRb.new(
37
+ opts['host'], opts['port'].to_i, opts['token'],
38
+ ssl: opts['ssl'],
39
+ timeout: (opts['timeout'] || 30).to_i,
40
+ loog: @loog,
41
+ retries: (opts['retries'] || 3).to_i
42
+ )
43
+ elapsed(@loog, level: Logger::INFO) do
44
+ id = baza.durable_find(jname, name)
45
+ if id.nil?
46
+ @loog.info("Durable '#{name}' not found in '#{jname}'")
47
+ return
48
+ end
49
+ @loog.info("Durable ##{id} ('#{name}') found in '#{jname}'")
50
+ baza.durable_lock(id, opts['owner'] || 'default')
51
+ begin
52
+ baza.durable_load(id, path)
53
+ size = File.size(path)
54
+ throw :"👍 Downloaded durable ##{id} to #{path} (#{size} bytes)"
55
+ ensure
56
+ baza.durable_unlock(id, opts['owner'] || 'default')
57
+ end
58
+ end
59
+ end
60
+ end
@@ -79,6 +79,11 @@ class Judges::Update
79
79
  loop do
80
80
  c += 1
81
81
  if c > 1
82
+ if opts['lifetime'] && Time.now - @start > opts['lifetime']
83
+ @loog.info("Not starting cycle ##{c}, no time left")
84
+ c -= 1
85
+ break
86
+ end
82
87
  @loog.info("\nStarting cycle ##{c}#{" (out of #{opts['max-cycles']})" if opts['max-cycles']}...")
83
88
  end
84
89
  delta = cycle(opts, judges, fb, options, start, errors)
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require 'typhoeus'
7
+ require 'iri'
8
+ require 'baza-rb'
9
+ require 'elapsed'
10
+ require_relative '../../judges'
11
+
12
+ # The +upload+ command.
13
+ #
14
+ # This class is instantiated by the +bin/judge+ command line interface. You
15
+ # are not supposed to instantiate it yourself.
16
+ #
17
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
18
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
19
+ # License:: MIT
20
+ class Judges::Upload
21
+ # Initialize.
22
+ # @param [Loog] loog Logging facility
23
+ def initialize(loog)
24
+ @loog = loog
25
+ end
26
+
27
+ # Run the upload command (called by the +bin/judges+ script).
28
+ # @param [Hash] opts Command line options (start with '--')
29
+ # @param [Array] args List of command line arguments
30
+ # @raise [RuntimeError] If not exactly two arguments provided
31
+ def run(opts, args)
32
+ raise 'Exactly two arguments required' unless args.size == 2
33
+ jname = args[0]
34
+ path = args[1]
35
+ raise "File not found: #{path}" unless File.exist?(path)
36
+ name = File.basename(path)
37
+ baza = BazaRb.new(
38
+ opts['host'], opts['port'].to_i, opts['token'],
39
+ ssl: opts['ssl'],
40
+ timeout: (opts['timeout'] || 30).to_i,
41
+ loog: @loog,
42
+ retries: (opts['retries'] || 3).to_i
43
+ )
44
+ elapsed(@loog, level: Logger::INFO) do
45
+ id = baza.durable_find(jname, name)
46
+ size = File.size(path)
47
+ if id.nil? || id.to_s.strip.empty?
48
+ id = baza.durable_place(jname, path)
49
+ throw :"👍 Uploaded #{path} to new durable '#{name}' in '#{jname}' (ID: #{id}, #{size} bytes)"
50
+ else
51
+ id = id.to_i
52
+ baza.durable_lock(id, opts['owner'] || 'default')
53
+ begin
54
+ baza.durable_save(id, path)
55
+ throw :"👍 Uploaded #{path} to existing durable '#{name}' in '#{jname}' (ID: #{id}, #{size} bytes)"
56
+ ensure
57
+ baza.durable_unlock(id, opts['owner'] || 'default')
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
data/lib/judges.rb CHANGED
@@ -8,5 +8,5 @@
8
8
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
9
9
  # License:: MIT
10
10
  module Judges
11
- VERSION = '0.46.0' unless const_defined?(:VERSION)
11
+ VERSION = '0.48.0' unless const_defined?(:VERSION)
12
12
  end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require 'loog'
7
+ require 'webmock/minitest'
8
+ require_relative '../../lib/judges'
9
+ require_relative '../../lib/judges/commands/download'
10
+ require_relative '../test__helper'
11
+
12
+ # Test.
13
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
14
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
15
+ # License:: MIT
16
+ class TestDownload < Minitest::Test
17
+ def test_download_simple_durable
18
+ WebMock.disable_net_connect!
19
+ content = 'Hello, World!'
20
+ stub_request(:get, 'https://example.org/durables/find?file=downloaded.txt&jname=myjudge').to_return(
21
+ status: 200, body: '42'
22
+ )
23
+ stub_request(:get, 'https://example.org/durables/42/lock?owner=default').to_return(status: 302)
24
+ stub_request(:get, 'https://example.org/durables/42').to_return(
25
+ status: 200, body: content
26
+ )
27
+ stub_request(:get, 'https://example.org/durables/42/unlock?owner=default').to_return(status: 302)
28
+ Dir.mktmpdir do |d|
29
+ file = File.join(d, 'downloaded.txt')
30
+ Judges::Download.new(Loog::NULL).run(
31
+ {
32
+ 'token' => '000',
33
+ 'host' => 'example.org',
34
+ 'port' => 443,
35
+ 'ssl' => true,
36
+ 'owner' => 'default'
37
+ },
38
+ ['myjudge', file]
39
+ )
40
+ assert_equal(content, File.read(file))
41
+ end
42
+ end
43
+
44
+ def test_download_with_custom_owner
45
+ WebMock.disable_net_connect!
46
+ content = 'Custom content'
47
+ stub_request(:get, 'http://example.org/durables/find?file=data.bin&jname=judge1').to_return(
48
+ status: 200, body: '123'
49
+ )
50
+ stub_request(:get, 'http://example.org/durables/123/lock?owner=custom').to_return(status: 302)
51
+ stub_request(:get, 'http://example.org/durables/123').to_return(
52
+ status: 200, body: content
53
+ )
54
+ stub_request(:get, 'http://example.org/durables/123/unlock?owner=custom').to_return(status: 302)
55
+ Dir.mktmpdir do |d|
56
+ file = File.join(d, 'data.bin')
57
+ Judges::Download.new(Loog::NULL).run(
58
+ {
59
+ 'token' => '000',
60
+ 'host' => 'example.org',
61
+ 'port' => 80,
62
+ 'ssl' => false,
63
+ 'owner' => 'custom'
64
+ },
65
+ ['judge1', file]
66
+ )
67
+ assert_equal(content, File.read(file))
68
+ end
69
+ end
70
+
71
+ def test_fails_on_http_error
72
+ WebMock.disable_net_connect!
73
+ stub_request(:get, 'http://example.org/durables/find?file=test.txt&jname=somejudge').to_return(
74
+ status: 200, body: '99'
75
+ )
76
+ stub_request(:get, 'http://example.org/durables/99/lock?owner=none').to_return(status: 302)
77
+ stub_request(:get, 'http://example.org/durables/99').to_return(status: 404)
78
+ stub_request(:get, 'http://example.org/durables/99/unlock?owner=none').to_return(status: 302)
79
+ Dir.mktmpdir do |d|
80
+ file = File.join(d, 'test.txt')
81
+ assert_raises(StandardError) do
82
+ Judges::Download.new(Loog::NULL).run(
83
+ {
84
+ 'token' => '000',
85
+ 'host' => 'example.org',
86
+ 'port' => 80,
87
+ 'ssl' => false,
88
+ 'owner' => 'none'
89
+ },
90
+ ['somejudge', file]
91
+ )
92
+ end
93
+ end
94
+ end
95
+
96
+ def test_fails_with_wrong_number_of_arguments
97
+ assert_raises(RuntimeError) do
98
+ Judges::Download.new(Loog::NULL).run({}, ['only_one_arg'])
99
+ end
100
+ assert_raises(RuntimeError) do
101
+ Judges::Download.new(Loog::NULL).run({}, %w[too many args])
102
+ end
103
+ end
104
+
105
+ def test_handles_not_found_durable
106
+ WebMock.disable_net_connect!
107
+ stub_request(:get, 'http://example.org/durables/find?file=missing.txt&jname=notfound').to_return(
108
+ status: 404
109
+ )
110
+ Dir.mktmpdir do |d|
111
+ file = File.join(d, 'missing.txt')
112
+ Judges::Download.new(Loog::NULL).run(
113
+ {
114
+ 'token' => '000',
115
+ 'host' => 'example.org',
116
+ 'port' => 80,
117
+ 'ssl' => false
118
+ },
119
+ ['notfound', file]
120
+ )
121
+ refute_path_exists(file)
122
+ end
123
+ end
124
+ end
@@ -79,6 +79,35 @@ class TestPrint < Minitest::Test
79
79
  assert_empty(v.errors, "#{doc}\n\n#{v.errors.join('; ')}")
80
80
  end
81
81
 
82
+ def test_html_table_has_colgroup
83
+ WebMock.disable_net_connect!
84
+ stub_request(:get, 'https://yegor256.github.io/judges/assets/index.css').to_return(body: 'nothing')
85
+ stub_request(:get, 'https://yegor256.github.io/judges/assets/index.js').to_return(body: 'nothing')
86
+ fb = Factbase.new
87
+ f = fb.insert
88
+ f.what = 'test issue'
89
+ f.when = Time.now
90
+ f.ticket = 42
91
+ html = File.join(__dir__, '../../temp/colgroup_test.html')
92
+ FileUtils.rm_f(html)
93
+ Dir.mktmpdir do |d|
94
+ factbase_file = File.join(d, 'base.fb')
95
+ File.binwrite(factbase_file, fb.export)
96
+ Judges::Print.new(Loog::NULL).run(
97
+ { 'format' => 'html', 'columns' => 'what,when,ticket' },
98
+ [factbase_file, html]
99
+ )
100
+ end
101
+ doc = Nokogiri::HTML(File.read(html))
102
+ table = doc.at_css('table#facts')
103
+ refute_nil(table, 'Table with id="facts" should exist')
104
+ colgroup = table.at_css('colgroup')
105
+ refute_nil(colgroup, 'Table should have a colgroup element')
106
+ cols = colgroup.css('col')
107
+ assert_equal(4, cols.size, 'Should have 4 col elements (3 for columns + 1 for extra)')
108
+ assert_equal('w50', cols.last['class'], 'Last col should have class="w50"')
109
+ end
110
+
82
111
  def test_print_all_formats
83
112
  WebMock.disable_net_connect!
84
113
  stub_request(:get, 'https://yegor256.github.io/judges/assets/index.css').to_return(body: 'nothing')
@@ -162,7 +162,7 @@ class TestUpdate < Minitest::Test
162
162
  save_it(File.join(d, 'first/first.rb'), '$global[:fb] ||= $fb; 2 + 2')
163
163
  save_it(File.join(d, 'second/second.rb'), '$global[:fb] ||= $fb; $global[:fb].insert')
164
164
  file = File.join(d, 'base.fb')
165
- Judges::Update.new(Loog::VERBOSE).run(
165
+ Judges::Update.new(Loog::NULL).run(
166
166
  { 'max-cycles' => 3, 'boost' => 'first' },
167
167
  [d, file]
168
168
  )
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require 'loog'
7
+ require 'webmock/minitest'
8
+ require_relative '../../lib/judges'
9
+ require_relative '../../lib/judges/commands/upload'
10
+ require_relative '../test__helper'
11
+
12
+ # Test.
13
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
14
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
15
+ # License:: MIT
16
+ class TestUpload < Minitest::Test
17
+ def test_upload_simple_durable
18
+ WebMock.disable_net_connect!
19
+ content = 'Hello, World!'
20
+ stub_request(:get, 'https://example.org/durables/find?file=upload.txt&jname=myjudge').to_return(
21
+ status: 404
22
+ )
23
+ stub_request(:get, 'https://example.org/csrf').to_return(
24
+ status: 200, body: 'test-csrf-token'
25
+ )
26
+ stub_request(:post, 'https://example.org/durables/place').to_return(
27
+ status: 302, headers: { 'X-Zerocracy-DurableId' => '42' }
28
+ )
29
+ stub_request(:get, %r{https://example.org/durables/42/lock}).to_return(status: 302)
30
+ stub_request(:put, %r{https://example.org/durables/42}).to_return(status: 200)
31
+ stub_request(:get, %r{https://example.org/durables/42/unlock}).to_return(status: 302)
32
+ Dir.mktmpdir do |d|
33
+ file = File.join(d, 'upload.txt')
34
+ File.write(file, content)
35
+ Judges::Upload.new(Loog::NULL).run(
36
+ {
37
+ 'token' => '000',
38
+ 'host' => 'example.org',
39
+ 'port' => 443,
40
+ 'ssl' => true,
41
+ 'owner' => 'default'
42
+ },
43
+ ['myjudge', file]
44
+ )
45
+ end
46
+ end
47
+
48
+ def test_upload_with_custom_owner
49
+ WebMock.disable_net_connect!
50
+ content = 'Binary data here'
51
+ stub_request(:get, 'http://example.org/durables/find?file=data.bin&jname=judge1').to_return(
52
+ status: 200, body: '123'
53
+ )
54
+ stub_request(:get, 'http://example.org/durables/123/lock?owner=custom').to_return(status: 302)
55
+ stub_request(:put, 'http://example.org/durables/123').to_return(status: 200)
56
+ stub_request(:get, 'http://example.org/durables/123/unlock?owner=custom').to_return(status: 302)
57
+ Dir.mktmpdir do |d|
58
+ file = File.join(d, 'data.bin')
59
+ File.write(file, content)
60
+ Judges::Upload.new(Loog::NULL).run(
61
+ {
62
+ 'token' => '000',
63
+ 'host' => 'example.org',
64
+ 'port' => 80,
65
+ 'ssl' => false,
66
+ 'owner' => 'custom'
67
+ },
68
+ ['judge1', file]
69
+ )
70
+ end
71
+ end
72
+
73
+ def test_fails_on_http_error
74
+ WebMock.disable_net_connect!
75
+ stub_request(:get, 'http://example.org/durables/find?file=test.txt&jname=somejudge').to_return(
76
+ status: 404
77
+ )
78
+ stub_request(:get, 'http://example.org/csrf').to_return(
79
+ status: 200, body: 'test-csrf-token'
80
+ )
81
+ stub_request(:post, 'http://example.org/durables/place').to_return(status: 500)
82
+ Dir.mktmpdir do |d|
83
+ file = File.join(d, 'test.txt')
84
+ File.write(file, 'content')
85
+ assert_raises(StandardError) do
86
+ Judges::Upload.new(Loog::NULL).run(
87
+ {
88
+ 'token' => '000',
89
+ 'host' => 'example.org',
90
+ 'port' => 80,
91
+ 'ssl' => false,
92
+ 'owner' => 'none'
93
+ },
94
+ ['somejudge', file]
95
+ )
96
+ end
97
+ end
98
+ end
99
+
100
+ def test_fails_with_wrong_number_of_arguments
101
+ assert_raises(RuntimeError) do
102
+ Judges::Upload.new(Loog::NULL).run({}, ['only_one_arg'])
103
+ end
104
+ assert_raises(RuntimeError) do
105
+ Judges::Upload.new(Loog::NULL).run({}, %w[too many args])
106
+ end
107
+ end
108
+
109
+ def test_fails_when_file_does_not_exist
110
+ assert_raises(RuntimeError) do
111
+ Judges::Upload.new(Loog::NULL).run(
112
+ {
113
+ 'token' => '000',
114
+ 'host' => 'example.org',
115
+ 'port' => 80,
116
+ 'ssl' => false
117
+ },
118
+ ['myjudge', '/nonexistent/file.txt']
119
+ )
120
+ end
121
+ end
122
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: judges
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.46.0
4
+ version: 0.48.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -297,6 +297,7 @@ files:
297
297
  - judges.gemspec
298
298
  - lib/judges.rb
299
299
  - lib/judges/categories.rb
300
+ - lib/judges/commands/download.rb
300
301
  - lib/judges/commands/eval.rb
301
302
  - lib/judges/commands/import.rb
302
303
  - lib/judges/commands/inspect.rb
@@ -307,6 +308,7 @@ files:
307
308
  - lib/judges/commands/test.rb
308
309
  - lib/judges/commands/trim.rb
309
310
  - lib/judges/commands/update.rb
311
+ - lib/judges/commands/upload.rb
310
312
  - lib/judges/impex.rb
311
313
  - lib/judges/judge.rb
312
314
  - lib/judges/judges.rb
@@ -315,6 +317,7 @@ files:
315
317
  - package-lock.json
316
318
  - package.json
317
319
  - renovate.json
320
+ - test/commands/test_download.rb
318
321
  - test/commands/test_eval.rb
319
322
  - test/commands/test_import.rb
320
323
  - test/commands/test_inspect.rb
@@ -325,6 +328,7 @@ files:
325
328
  - test/commands/test_test.rb
326
329
  - test/commands/test_trim.rb
327
330
  - test/commands/test_update.rb
331
+ - test/commands/test_upload.rb
328
332
  - test/test__helper.rb
329
333
  - test/test_bin.rb
330
334
  - test/test_categories.rb