fbe 0.19.1 → 0.19.3

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: 4f97f9d210de0a591fd2649095d07a8e6415a13b74d7abce02322d84cdcb29fd
4
- data.tar.gz: 864239e8b577903cb9c3c1cad53e2d267f31de6839df37ecca8123d1a1340d84
3
+ metadata.gz: df9755e6d4d7bf5ae3a716031216786929ddfcdf328a3f026b308e9bbfc93f92
4
+ data.tar.gz: ed1cfe9f9877a3e3e1b77f30f4b9c8ca525885306d100058d5397019ca1005e6
5
5
  SHA512:
6
- metadata.gz: ac1618f1d123e8ef210f33fe73e23d3b324bea096d3bfc18f97f9671100f0a75312524ea8fbb9eead93cb9e1c22635def15365e99f35e2000abbd89b209d3f51
7
- data.tar.gz: f69b7743409715b8fb42b44641414e235cc6c259316ea8427fa19295c23a50cb9d40750721a9a18d1873ca511f3434a37042fee3857fb117c0975e00c2fa031d
6
+ metadata.gz: 3bfc015d2f0c47035fae903627404da6fafcd823c14abdcdc8a37694fea73bbb4edd1f1467497379fff51e62388b741a205b28bcd0ee8a4b5c28aceaf0f6c22c
7
+ data.tar.gz: dc92c946e0d1bd14deb3d29a73b36f9317d7e06597ac2ec4fc05030ed9afea415830a71f101eb54ddd2793a02a3c6b480d2a2b95482f3deb0d62903230b1432e
@@ -21,9 +21,6 @@ class Fbe::Middleware::SqliteStore
21
21
  dir = File.dirname(path)
22
22
  raise ArgumentError, "Directory #{dir} does not exist" unless File.directory?(dir)
23
23
  @path = File.absolute_path(path)
24
- open
25
- prepare
26
- at_exit { close }
27
24
  end
28
25
 
29
26
  def read(key)
@@ -37,9 +34,13 @@ class Fbe::Middleware::SqliteStore
37
34
  end
38
35
 
39
36
  def write(key, value)
37
+ return if value.is_a?(Array) && value.any? do |vv|
38
+ req = JSON.parse(vv[0])
39
+ req['url'].include?('?') || req['method'] != 'get'
40
+ end
40
41
  value = JSON.dump(value)
41
- perform do |tdb|
42
- tdb.execute(<<~SQL, [key, value])
42
+ perform do |t|
43
+ t.execute(<<~SQL, [key, value])
43
44
  INSERT INTO cache(key, value) VALUES(?1, ?2)
44
45
  ON CONFLICT(key) DO UPDATE SET value = ?2
45
46
  SQL
@@ -47,32 +48,10 @@ class Fbe::Middleware::SqliteStore
47
48
  nil
48
49
  end
49
50
 
50
- def open
51
- return if @db
52
- @db = SQLite3::Database.new(@path)
53
- end
54
-
55
- def prepare
56
- perform do |tdb|
57
- tdb.execute 'CREATE TABLE IF NOT EXISTS cache(key TEXT UNIQUE NOT NULL, value TEXT);'
58
- tdb.execute 'CREATE INDEX IF NOT EXISTS key_idx ON cache(key);'
59
- end
60
- end
61
-
62
- def close
63
- return if !@db || @db.closed?
64
- @db.close
65
- @db = nil
66
- end
67
-
68
51
  def clear
69
52
  perform { _1.execute 'DELETE FROM cache;' }
70
53
  end
71
54
 
72
- def drop
73
- perform { _1.execute 'DROP TABLE IF EXISTS cache;' }
74
- end
75
-
76
55
  def all
77
56
  perform { _1.execute('SELECT key, value FROM cache') }
78
57
  end
@@ -80,6 +59,14 @@ class Fbe::Middleware::SqliteStore
80
59
  private
81
60
 
82
61
  def perform(&)
62
+ @db ||=
63
+ SQLite3::Database.new(@path).tap do |d|
64
+ d.transaction do |t|
65
+ t.execute 'CREATE TABLE IF NOT EXISTS cache(key TEXT UNIQUE NOT NULL, value TEXT);'
66
+ t.execute 'CREATE INDEX IF NOT EXISTS key_idx ON cache(key);'
67
+ end
68
+ at_exit { @db&.close }
69
+ end
83
70
  @db.transaction(&)
84
71
  end
85
72
  end
data/lib/fbe/octo.rb CHANGED
@@ -47,7 +47,7 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
47
47
  loog.debug("The 'GITHUB_TOKEN' environment was provided")
48
48
  end
49
49
  else
50
- loog.debug("The 'github_token' option was provided")
50
+ loog.debug("The 'github_token' option was provided (#{token.length} chars)")
51
51
  end
52
52
  if token.nil?
53
53
  loog.warn('Accessing GitHub API without a token!')
@@ -55,10 +55,6 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
55
55
  loog.warn('The GitHub API token is an empty string, won\'t use it')
56
56
  else
57
57
  o = Octokit::Client.new(access_token: token)
58
- loog.info(
59
- "Accessing GitHub API with a token (#{token.length} chars, ending by #{token[-4..].inspect}, " \
60
- "#{Octokit::Client.new(access_token: token).rate_limit.remaining} quota remaining)"
61
- )
62
58
  end
63
59
  o.auto_paginate = true
64
60
  o.per_page = 100
@@ -80,16 +76,24 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
80
76
  methods: [:get],
81
77
  backoff_factor: 2
82
78
  )
83
- serializer = Marshal
84
79
  if options.sqlite_cache
85
80
  store = Fbe::Middleware::SqliteStore.new(options.sqlite_cache)
86
- serializer = JSON
87
- loog.info("Using HTTP cache in SQLite file: #{store.path}")
81
+ loog.info(
82
+ "Using HTTP cache in SQLite file: #{store.path} (" \
83
+ "#{File.exist?(store.path) ? "#{File.size(store.path)} bytes" : 'file is absent'}" \
84
+ ')'
85
+ )
86
+ builder.use(
87
+ Faraday::HttpCache,
88
+ store:, serializer: JSON, shared_cache: false, logger: Loog::NULL
89
+ )
90
+ else
91
+ loog.info("No HTTP cache in SQLite file, because 'sqlite_cache' option is not provided")
92
+ builder.use(
93
+ Faraday::HttpCache,
94
+ serializer: Marshal, shared_cache: false, logger: Loog::NULL
95
+ )
88
96
  end
89
- builder.use(
90
- Faraday::HttpCache,
91
- store: store, serializer: serializer, shared_cache: false, logger: Loog::NULL
92
- )
93
97
  builder.use(Octokit::Response::RaiseError)
94
98
  builder.use(Faraday::Response::Logger, loog, formatter: Fbe::Middleware::Formatter)
95
99
  builder.use(Fbe::Middleware::Trace, trace)
@@ -97,6 +101,12 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
97
101
  end
98
102
  o.middleware = stack
99
103
  o = Verbose.new(o, log: loog)
104
+ unless token.nil? || token.empty?
105
+ loog.info(
106
+ "Accessing GitHub API with a token (#{token.length} chars, ending by #{token[-4..].inspect}, " \
107
+ "#{o.rate_limit.remaining} quota remaining)"
108
+ )
109
+ end
100
110
  else
101
111
  loog.debug('The connection to GitHub API is mocked')
102
112
  o = Fbe::FakeOctokit.new
data/lib/fbe.rb CHANGED
@@ -10,5 +10,5 @@
10
10
  # License:: MIT
11
11
  module Fbe
12
12
  # Current version of the gem (changed by +.rultor.yml+ on every release)
13
- VERSION = '0.19.1' unless const_defined?(:VERSION)
13
+ VERSION = '0.19.3' unless const_defined?(:VERSION)
14
14
  end
@@ -3,6 +3,7 @@
3
3
  # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
+ require 'qbash'
6
7
  require_relative '../../test__helper'
7
8
  require_relative '../../../lib/fbe/middleware'
8
9
  require_relative '../../../lib/fbe/middleware/sqlite_store'
@@ -12,24 +13,107 @@ require_relative '../../../lib/fbe/middleware/sqlite_store'
12
13
  # Copyright:: Copyright (c) 2024-2025 Zerocracy
13
14
  # License:: MIT
14
15
  class SqliteStoreTest < Fbe::Test
15
- def test_sqlite_store
16
- Dir.mktmpdir do |dir|
17
- store = Fbe::Middleware::SqliteStore.new(File.expand_path('test.db', dir))
18
- assert_nil(store.read('my_key'))
19
- assert_nil(store.delete('my_key'))
20
- assert_nil(store.write('my_key', 'some value'))
21
- assert_equal('some value', store.read('my_key'))
22
- assert_nil(store.write('my_key', 'some value 2'))
23
- assert_equal('some value 2', store.read('my_key'))
24
- assert_nil(store.delete('my_key'))
25
- assert_nil(store.read('my_key'))
16
+ def test_simple_caching_algorithm
17
+ with_tmpfile('x.db') do |f|
18
+ store = Fbe::Middleware::SqliteStore.new(f)
19
+ k = 'some-key'
20
+ assert_nil(store.read(k))
21
+ assert_nil(store.delete(k))
22
+ v1 = 'first value to save'
23
+ assert_nil(store.write(k, v1))
24
+ assert_equal(v1, store.read(k))
25
+ v2 = 'another value to save'
26
+ assert_nil(store.write(k, v2))
27
+ assert_equal(v2, store.read(k))
28
+ assert_nil(store.delete(k))
29
+ assert_nil(store.read(k))
30
+ assert_path_exists(f)
26
31
  end
27
32
  end
28
33
 
29
- def test_sqlite_store_empty_all
30
- Dir.mktmpdir do |dir|
31
- store = Fbe::Middleware::SqliteStore.new(File.expand_path('test.db', dir))
34
+ def test_returns_empty_list
35
+ with_tmpfile('b.db') do |f|
36
+ store = Fbe::Middleware::SqliteStore.new(f)
37
+ assert_empty(store.all)
38
+ end
39
+ end
40
+
41
+ def test_clear_all_keys
42
+ with_tmpfile('a.db') do |f|
43
+ store = Fbe::Middleware::SqliteStore.new(f)
44
+ k = 'a key'
45
+ store.write(k, 'some value')
46
+ store.clear
47
+ assert_empty(store.all)
48
+ end
49
+ end
50
+
51
+ def test_empty_all_if_not_written
52
+ with_tmpfile do |f|
53
+ store = Fbe::Middleware::SqliteStore.new(f)
32
54
  assert_empty(store.all)
33
55
  end
34
56
  end
57
+
58
+ def test_wrong_db_path
59
+ assert_raises(ArgumentError) do
60
+ Fbe::Middleware::SqliteStore.new(nil).read('my_key')
61
+ end
62
+ assert_raises(ArgumentError) do
63
+ Fbe::Middleware::SqliteStore.new('').read('my_key')
64
+ end
65
+ assert_raises(ArgumentError) do
66
+ Fbe::Middleware::SqliteStore.new('/fakepath/fakefolder/test.db').read('my_key')
67
+ end
68
+ end
69
+
70
+ def test_not_db_file
71
+ with_tmpfile do |f|
72
+ File.binwrite(f, Array.new(20) { rand(0..255) }.pack('C*'))
73
+ ex =
74
+ assert_raises(SQLite3::NotADatabaseException) do
75
+ Fbe::Middleware::SqliteStore.new(f).read('my_key')
76
+ end
77
+ assert_match('file is not a database', ex.message)
78
+ end
79
+ end
80
+
81
+ def test_defer_db_close_callback
82
+ txt = <<~RUBY
83
+ require 'tempfile'
84
+ require 'sqlite3'
85
+ require 'fbe/middleware/sqlite_store'
86
+
87
+ SQLite3::Database.class_eval do
88
+ prepend(Module.new do
89
+ def close
90
+ super
91
+ puts 'closed sqlite after process exit'
92
+ end
93
+ end)
94
+ end
95
+
96
+ Tempfile.open('test.db') do |f|
97
+ Fbe::Middleware::SqliteStore.new(f.path).then do |s|
98
+ s.write('my_key', 'my_value')
99
+ s.read('my_key')
100
+ end
101
+ end
102
+ RUBY
103
+ out =
104
+ qbash(
105
+ 'bundle exec ruby ' \
106
+ "-I#{Shellwords.escape(File.expand_path('../../../lib', __dir__))} " \
107
+ "-e #{Shellwords.escape(txt)} 2>&1"
108
+ )
109
+ assert_match('closed sqlite after process exit', out)
110
+ end
111
+
112
+ private
113
+
114
+ def with_tmpfile(name = 'test.db', &)
115
+ Dir.mktmpdir do |dir|
116
+ yield File.expand_path(name, dir)
117
+ end
118
+ end
35
119
  end
@@ -138,10 +138,8 @@ class TestOcto < Fbe::Test
138
138
  body: '{}', headers: { 'X-RateLimit-Remaining' => '1234' }
139
139
  )
140
140
  buf = Loog::Buffer.new
141
- o = Fbe.octo(loog: buf, global: {}, options: Judges::Options.new({ 'github_token' => 'secret_github_token' }))
141
+ Fbe.octo(loog: buf, global: {}, options: Judges::Options.new({ 'github_token' => 'secret_github_token' }))
142
142
  assert_match(/Accessing GitHub API with a token \(19 chars, ending by "oken", 1234 quota remaining\)/, buf.to_s)
143
- assert_nil(o.last_response, 'Not to be requests until initialize main Octokit client, ' \
144
- 'because middleware cached after first request and not apply after')
145
143
  end
146
144
 
147
145
  def test_retrying
@@ -258,7 +256,10 @@ class TestOcto < Fbe::Test
258
256
  end
259
257
 
260
258
  def test_reads_quota
261
- WebMock.enable_net_connect!
259
+ WebMock.disable_net_connect!
260
+ stub_request(:get, 'https://api.github.com/rate_limit').to_return(
261
+ { body: '{}', headers: { 'X-RateLimit-Remaining' => '222' } }
262
+ )
262
263
  o = Fbe.octo(loog: Loog::VERBOSE, global: {}, options: Judges::Options.new({ 'github_api_pause' => 0.01 }))
263
264
  refute_nil(o.off_quota?)
264
265
  end
@@ -367,7 +368,7 @@ class TestOcto < Fbe::Test
367
368
  assert_includes second_output, 'GitHub API trace is empty'
368
369
  end
369
370
 
370
- def test_sqlite_store
371
+ def test_works_via_sqlite_store
371
372
  WebMock.disable_net_connect!
372
373
  Dir.mktmpdir do |dir|
373
374
  global = {}
@@ -390,4 +391,18 @@ class TestOcto < Fbe::Test
390
391
  assert_equal('user1', o.user_name_by_id(42))
391
392
  end
392
393
  end
394
+
395
+ def test_through_sqlite_store_when_broken_token
396
+ WebMock.disable_net_connect!
397
+ Dir.mktmpdir do |dir|
398
+ global = {}
399
+ file = File.expand_path('test.db', dir)
400
+ stub_request(:get, 'https://api.github.com/user/4242').to_return(status: 401)
401
+ o = Fbe.octo(loog: Loog::NULL, global:, options: Judges::Options.new({ 'sqlite_cache' => file }))
402
+ assert_raises(StandardError) do
403
+ assert_equal('user1', o.user_name_by_id(4242))
404
+ end
405
+ assert_path_exists(file)
406
+ end
407
+ end
393
408
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fbe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.1
4
+ version: 0.19.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko