pgtk 0.18.1 → 0.18.2

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.
data/renovate.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
- "extends": [
4
- "config:base"
5
- ]
6
- }
data/test/test__helper.rb DELETED
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
- # SPDX-License-Identifier: MIT
5
-
6
- $stdout.sync = true
7
-
8
- require 'simplecov'
9
- require 'simplecov-cobertura'
10
- unless SimpleCov.running || ENV['PICKS']
11
- SimpleCov.command_name('test')
12
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
13
- [
14
- SimpleCov::Formatter::HTMLFormatter,
15
- SimpleCov::Formatter::CoberturaFormatter
16
- ]
17
- )
18
- SimpleCov.minimum_coverage 90
19
- SimpleCov.minimum_coverage_by_file 90
20
- SimpleCov.start do
21
- add_filter 'test/'
22
- add_filter 'vendor/'
23
- add_filter 'target/'
24
- track_files 'lib/**/*.rb'
25
- track_files '*.rb'
26
- end
27
- end
28
-
29
- require 'minitest/autorun'
30
- require 'minitest/reporters'
31
- Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
32
-
33
- require 'logger'
34
- require 'loog'
35
- require 'rake'
36
- require 'rake/tasklib'
37
- require_relative '../lib/pgtk'
38
- require_relative '../lib/pgtk/liquibase_task'
39
- require_relative '../lib/pgtk/pgsql_task'
40
-
41
- class Pgtk::Test < Minitest::Test
42
- def fake_config
43
- Dir.mktmpdir do |dir|
44
- id = (Time.now.to_f * 1_000_000).to_i % 1_000_000
45
- f = File.join(dir, 'cfg.yml')
46
- Pgtk::PgsqlTask.new("pgsql#{id}") do |t|
47
- t.dir = File.join(dir, 'pgsql')
48
- t.user = 'hello'
49
- t.password = 'A B C привет ! & | !'
50
- t.dbname = 'test'
51
- t.yaml = f
52
- t.quiet = true
53
- end
54
- Rake::Task["pgsql#{id}"].invoke
55
- Pgtk::LiquibaseTask.new("liquibase#{id}") do |t|
56
- t.master = File.join(__dir__, '../test-resources/master.xml')
57
- t.yaml = f
58
- t.quiet = true
59
- end
60
- Rake::Task["liquibase#{id}"].invoke
61
- assert_path_exists(f)
62
- yield f
63
- end
64
- end
65
-
66
- def fake_pool(log: Loog::NULL)
67
- fake_config do |f|
68
- pool = Pgtk::Pool.new(
69
- Pgtk::Wire::Yaml.new(f),
70
- log: log
71
- )
72
- pool.start(1)
73
- yield pool
74
- end
75
- end
76
- end
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'loog'
7
- require 'pg'
8
- require 'qbash'
9
- require 'rake'
10
- require 'tmpdir'
11
- require 'yaml'
12
- require_relative 'test__helper'
13
- require_relative '../lib/pgtk/pool'
14
- require_relative '../lib/pgtk/impatient'
15
-
16
- # Pool test.
17
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
18
- # Copyright:: Copyright (c) 2017-2025 Yegor Bugayenko
19
- # License:: MIT
20
- class TestImpatient < Pgtk::Test
21
- def test_takes_version
22
- fake_pool do |pool|
23
- v = Pgtk::Impatient.new(pool, 1).version
24
- refute_nil(v)
25
- end
26
- end
27
-
28
- def test_interrupts
29
- fake_pool do |pool|
30
- assert_raises(Pgtk::Impatient::TooSlow) do
31
- Pgtk::Impatient.new(pool, 0.01).exec(
32
- 'SELECT COUNT(*) FROM generate_series(1, 1000000) AS a'
33
- )
34
- end
35
- end
36
- end
37
-
38
- def test_skips_by_regex
39
- fake_pool do |pool|
40
- Pgtk::Impatient.new(pool, 0.01, /^SELECT.*$/).exec(
41
- 'SELECT COUNT(*) FROM generate_series(1, 1000000) AS a'
42
- )
43
- end
44
- end
45
-
46
- def test_doesnt_shadow_larger_timeout
47
- fake_pool do |pool|
48
- assert_raises(Timeout::Error) do
49
- Timeout.timeout(0.1) do
50
- Pgtk::Impatient.new(pool, 999).exec(
51
- 'SELECT COUNT(*) FROM generate_series(1, 100000000) AS a'
52
- )
53
- end
54
- end
55
- end
56
- end
57
-
58
- def test_doesnt_interrupt
59
- fake_pool do |pool|
60
- id = Pgtk::Impatient.new(pool, 1).exec(
61
- 'INSERT INTO book (title) VALUES ($1) RETURNING id',
62
- ['1984']
63
- ).first['id'].to_i
64
- assert_predicate(id, :positive?)
65
- end
66
- end
67
-
68
- def test_doesnt_interrupt_in_transaction
69
- fake_pool do |pool|
70
- Pgtk::Impatient.new(pool, 1).transaction do |t|
71
- id = t.exec(
72
- 'INSERT INTO book (title) VALUES ($1) RETURNING id',
73
- ['1984']
74
- ).first['id'].to_i
75
- assert_predicate(id, :positive?)
76
- end
77
- end
78
- end
79
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'tmpdir'
7
- require 'rake'
8
- require 'yaml'
9
- require_relative 'test__helper'
10
- require_relative '../lib/pgtk/pgsql_task'
11
- require_relative '../lib/pgtk/liquibase_task'
12
-
13
- # Liquibase rake task test.
14
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
15
- # Copyright:: Copyright (c) 2017-2025 Yegor Bugayenko
16
- # License:: MIT
17
- class TestLiquibaseTask < Pgtk::Test
18
- def test_basic
19
- Dir.mktmpdir do |dir|
20
- Pgtk::PgsqlTask.new(:pgsql2) do |t|
21
- t.dir = File.join(dir, 'pgsql')
22
- t.user = 'hello'
23
- t.password = 'A B C привет ! & | !'
24
- t.dbname = 'test'
25
- t.yaml = File.join(dir, 'cfg.yml')
26
- t.quiet = true
27
- end
28
- Rake::Task['pgsql2'].invoke
29
- Pgtk::LiquibaseTask.new(:liquibase2) do |t|
30
- t.master = File.join(__dir__, '../test-resources/master.xml')
31
- t.yaml = ['file-is-absent', File.join(dir, 'cfg.yml'), 'another']
32
- t.quiet = true
33
- t.postgresql_version = '42.7.0'
34
- t.liquibase_version = '3.2.2'
35
- t.contexts = '!test'
36
- end
37
- Rake::Task['liquibase2'].invoke
38
- end
39
- end
40
-
41
- def test_latest_version
42
- Dir.mktmpdir do |dir|
43
- Pgtk::PgsqlTask.new(:pgsql) do |t|
44
- t.dir = File.join(dir, 'pgsql')
45
- t.user = 'xxx'
46
- t.password = 'xxx'
47
- t.dbname = 'xxx'
48
- t.yaml = File.join(dir, 'xxx.yml')
49
- t.quiet = true
50
- end
51
- Rake::Task['pgsql'].invoke
52
- Pgtk::LiquibaseTask.new(:liquibase) do |t|
53
- t.master = File.join(__dir__, '../test-resources/master.xml')
54
- t.yaml = File.join(dir, 'xxx.yml')
55
- t.postgresql_version = '42.7.1'
56
- t.liquibase_version = '4.25.1'
57
- t.quiet = true
58
- end
59
- Rake::Task['liquibase'].invoke
60
- end
61
- end
62
-
63
- def test_with_invalid_master_file
64
- Pgtk::LiquibaseTask.new(:lb) do |t|
65
- t.master = 'the-file-doesnt-exist.xml'
66
- t.yaml = { 'pgsql' => {} }
67
- t.quiet = true
68
- end
69
- ex = assert_raises(StandardError) do
70
- Rake::Task['lb'].invoke
71
- end
72
- assert_includes(ex.message, 'the-file-doesnt-exist.xml')
73
- end
74
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'rake'
7
- require 'tmpdir'
8
- require 'yaml'
9
- require_relative 'test__helper'
10
- require_relative '../lib/pgtk/pgsql_task'
11
-
12
- # Pgsql rake task test.
13
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
14
- # Copyright:: Copyright (c) 2017-2025 Yegor Bugayenko
15
- # License:: MIT
16
- class TestPgsqlTask < Pgtk::Test
17
- def test_basic
18
- Dir.mktmpdir do |dir|
19
- Pgtk::PgsqlTask.new(:p2) do |t|
20
- t.dir = File.join(dir, 'pgsql')
21
- t.user = 'hello'
22
- t.password = 'A B C привет ! & | !'
23
- t.dbname = 'test'
24
- t.yaml = File.join(dir, 'cfg.yml')
25
- t.quiet = true
26
- t.config = {
27
- log_min_error_statement: 'ERROR'
28
- }
29
- end
30
- Rake::Task['p2'].invoke
31
- yaml = YAML.load_file(File.join(dir, 'cfg.yml'))
32
- assert(yaml['pgsql']['url'].start_with?('jdbc:postgresql://localhost'))
33
- end
34
- end
35
-
36
- def test_not_quiet
37
- Dir.mktmpdir do |dir|
38
- Pgtk::PgsqlTask.new(:p3) do |t|
39
- t.dir = File.join(dir, 'pgsql')
40
- t.user = 'hello'
41
- t.password = 'the password'
42
- t.dbname = 'test'
43
- t.yaml = File.join(dir, 'cfg.yml')
44
- t.quiet = true
45
- t.config = {
46
- log_directory: dir,
47
- logging_collector: 'on',
48
- log_statement: 'all',
49
- log_filename: 'pgsql.log'
50
- }
51
- end
52
- Rake::Task['p3'].invoke
53
- yaml = YAML.load_file(File.join(dir, 'cfg.yml'))
54
- assert(yaml['pgsql']['url'].start_with?('jdbc:postgresql://localhost'))
55
- assert_path_exists(File.join(dir, 'pgsql.log'))
56
- end
57
- end
58
- end
data/test/test_pool.rb DELETED
@@ -1,224 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'loog'
7
- require 'pg'
8
- require 'qbash'
9
- require 'rake'
10
- require 'tmpdir'
11
- require 'yaml'
12
- require_relative 'test__helper'
13
- require_relative '../lib/pgtk/liquibase_task'
14
- require_relative '../lib/pgtk/pgsql_task'
15
- require_relative '../lib/pgtk/pool'
16
- require_relative '../lib/pgtk/spy'
17
-
18
- # Pool test.
19
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
20
- # Copyright:: Copyright (c) 2017-2025 Yegor Bugayenko
21
- # License:: MIT
22
- class TestPool < Pgtk::Test
23
- def test_reads_version
24
- fake_pool do |pool|
25
- ver = pool.version
26
- assert(ver.start_with?('1'))
27
- refute_includes(ver, ' ')
28
- end
29
- end
30
-
31
- def test_basic
32
- fake_pool do |pool|
33
- id = pool.exec(
34
- 'INSERT INTO book (title) VALUES ($1) RETURNING id',
35
- ['Elegant Objects']
36
- )[0]['id'].to_i
37
- assert_predicate(id, :positive?)
38
- end
39
- end
40
-
41
- def test_logs_pgsql_errors_to_logger
42
- buf = Loog::Buffer.new
43
- fake_pool(log: buf) do |pool|
44
- pool.exec(
45
- "
46
- CREATE FUNCTION intentional_failure() RETURNS trigger AS
47
- 'BEGIN
48
- IF NEW.title = ''War and War'' THEN
49
- RAISE EXCEPTION ''The title of the book is bad'';
50
- END IF;
51
- RETURN NEW;
52
- END' LANGUAGE PLPGSQL
53
- "
54
- )
55
- pool.exec(
56
- "
57
- CREATE TRIGGER check_book_title
58
- BEFORE INSERT ON book
59
- FOR EACH ROW EXECUTE PROCEDURE intentional_failure();
60
- "
61
- )
62
- assert_raises(PG::RaiseException) do
63
- pool.exec('INSERT INTO book (title) VALUES ($1)', ['War and War'])
64
- end
65
- assert_includes(buf.to_s, 'The title of the book is bad')
66
- assert_includes(buf.to_s, 'function intentional_failure() line 3')
67
- end
68
- end
69
-
70
- def test_queries_with_block
71
- fake_pool do |pool|
72
- pool.exec('INSERT INTO book (title) VALUES ($1)', ['1984'])
73
- rows = []
74
- pool.exec('SELECT * FROM book') do |row|
75
- rows.append(row)
76
- end
77
- assert_equal(1, rows.size)
78
- end
79
- end
80
-
81
- def test_with_spy
82
- queries = []
83
- fake_pool do |pool|
84
- pool = Pgtk::Spy.new(pool) { |sql| queries.append(sql) }
85
- pool.exec(
86
- ['INSERT INTO book', '(title) VALUES ($1)'],
87
- ['Elegant Objects']
88
- )
89
- end
90
- assert_equal(1, queries.size)
91
- assert_equal('INSERT INTO book (title) VALUES ($1)', queries.first)
92
- end
93
-
94
- def test_complex_query
95
- fake_pool do |pool|
96
- pool.exec(
97
- "
98
- INSERT INTO book (title) VALUES ('one');
99
- INSERT INTO book (title) VALUES ('two');
100
- "
101
- )
102
- end
103
- end
104
-
105
- def test_logs_sql
106
- log = Loog::Buffer.new
107
- fake_pool(log: log) do |pool|
108
- pool.exec(
109
- 'INSERT INTO book (title) VALUES ($1)',
110
- ['Object Thinking']
111
- )
112
- assert_includes(log.to_s, 'INSERT INTO book (title) VALUES ($1)')
113
- end
114
- end
115
-
116
- def test_logs_errors
117
- log = Loog::Buffer.new
118
- fake_pool(log: log) do |pool|
119
- assert_raises(PG::UndefinedTable) do
120
- pool.exec('INSERT INTO tableDoesNotExist (a) VALUES (42)')
121
- end
122
- assert_includes(log.to_s, 'INSERT INTO tableDoesNotExist')
123
- end
124
- end
125
-
126
- def test_transaction
127
- fake_pool do |pool|
128
- id = Pgtk::Spy.new(pool).transaction do |t|
129
- t.exec('DELETE FROM book')
130
- t.exec(
131
- [
132
- 'INSERT INTO book (title)',
133
- 'VALUES ($1) RETURNING id'
134
- ],
135
- ['Object Thinking']
136
- )[0]['id'].to_i
137
- end
138
- assert_predicate(id, :positive?)
139
- end
140
- end
141
-
142
- def test_transaction_with_error
143
- fake_pool do |pool|
144
- pool.exec('DELETE FROM book')
145
- assert_empty(pool.exec('SELECT * FROM book'))
146
- assert_raises(StandardError) do
147
- pool.transaction do |t|
148
- t.exec('INSERT INTO book (title) VALUES ($1)', ['hey'])
149
- t.exec('INSERT INTO book (error_here) VALUES ($1)', ['hey'])
150
- end
151
- end
152
- assert_empty(pool.exec('SELECT * FROM book'))
153
- pool.exec('INSERT INTO book (title) VALUES ($1)', ['another'])
154
- refute_empty(pool.exec('SELECT * FROM book'))
155
- end
156
- end
157
-
158
- def test_reconnects_on_pg_error
159
- fake_pool do |pool|
160
- assert_raises PG::UndefinedTable do
161
- pool.exec('SELECT * FROM thisiserror')
162
- end
163
- 5.times do
164
- pool.exec('SELECT * FROM book')
165
- end
166
- end
167
- end
168
-
169
- def test_reconnects_on_pg_reboot
170
- port = RandomPort::Pool::SINGLETON.acquire
171
- Dir.mktmpdir do |dir|
172
- id = rand(100..999)
173
- Pgtk::PgsqlTask.new("pgsql#{id}") do |t|
174
- t.dir = File.join(dir, 'pgsql')
175
- t.user = 'hello'
176
- t.password = 'A B C привет ! & | !'
177
- t.dbname = 'test'
178
- t.yaml = File.join(dir, 'cfg.yml')
179
- t.quiet = true
180
- t.fresh_start = true
181
- t.port = port
182
- end
183
- task = Rake::Task["pgsql#{id}"]
184
- task.invoke
185
- pool = Pgtk::Pool.new(
186
- Pgtk::Wire::Yaml.new(File.join(dir, 'cfg.yml')),
187
- log: Loog::NULL
188
- )
189
- pool.start(1)
190
- pool.exec('SELECT * FROM pg_catalog.pg_tables')
191
- qbash("pg_ctl -D #{Shellwords.escape(File.join(dir, 'pgsql'))} stop", log: nil)
192
- cycle = 0
193
- loop do
194
- begin
195
- TCPSocket.new('localhost', port)
196
- sleep(0.1)
197
- cycle += 1
198
- if cycle > 50
199
- qbash('ps -ax | grep postgres')
200
- raise "Can't stop running postgres at port #{port}, for some reason"
201
- end
202
- rescue StandardError => e
203
- puts e.message
204
- break
205
- end
206
- end
207
- assert_raises(PG::UnableToSend, PG::ConnectionBad) do
208
- pool.exec('SELECT * FROM pg_catalog.pg_tables')
209
- end
210
- task.reenable
211
- task.invoke
212
- loop do
213
- begin
214
- pool.exec('SELECT * FROM pg_catalog.pg_tables')
215
- break
216
- rescue StandardError => e
217
- puts e.message
218
- sleep(0.1)
219
- retry
220
- end
221
- end
222
- end
223
- end
224
- end