tapsoob 0.7.17 → 0.8.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.
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+ require 'tapsoob/operation/base'
3
+ require 'tapsoob/operation/pull'
4
+ require 'tapsoob/operation/push'
5
+
6
+ RSpec.describe Tapsoob::Operation::Base do
7
+ let(:url) { sqlite_memory_url }
8
+ let(:dir) { Dir.mktmpdir }
9
+ let(:base_opts) { { data: true, schema: true, progress: false, default_chunksize: 1000 } }
10
+
11
+ after { FileUtils.rm_rf(dir) }
12
+
13
+ subject(:op) { described_class.new(url, dir, base_opts) }
14
+
15
+ # ── table_filter / exclude_tables ────────────────────────────────────────────
16
+
17
+ describe '#apply_table_filter' do
18
+ context 'when no filter is set' do
19
+ it 'returns all tables unchanged' do
20
+ tables = ['users', 'orders', 'products']
21
+ expect(op.apply_table_filter(tables)).to eq(tables)
22
+ end
23
+ end
24
+
25
+ context 'with :tables filter' do
26
+ subject(:op) { described_class.new(url, dir, base_opts.merge(tables: ['users'])) }
27
+
28
+ it 'keeps only whitelisted tables' do
29
+ tables = ['users', 'orders']
30
+ expect(op.apply_table_filter(tables)).to eq(['users'])
31
+ end
32
+ end
33
+
34
+ context 'with :exclude_tables' do
35
+ subject(:op) { described_class.new(url, dir, base_opts.merge(exclude_tables: ['orders'])) }
36
+
37
+ it 'excludes the specified tables' do
38
+ tables = ['users', 'orders', 'products']
39
+ expect(op.apply_table_filter(tables)).to eq(['users', 'products'])
40
+ end
41
+ end
42
+
43
+ context 'with a Hash argument' do
44
+ subject(:op) { described_class.new(url, dir, base_opts.merge(tables: ['users'])) }
45
+
46
+ it 'filters the hash by whitelisted keys' do
47
+ tables = { 'users' => 10, 'orders' => 5 }
48
+ expect(op.apply_table_filter(tables)).to eq({ 'users' => 10 })
49
+ end
50
+ end
51
+ end
52
+
53
+ # ── parallelism ──────────────────────────────────────────────────────────────
54
+
55
+ describe '#parallel_workers' do
56
+ it 'defaults to 1 when no --parallel option given' do
57
+ expect(op.parallel_workers).to eq(1)
58
+ end
59
+
60
+ it 'respects the :parallel option' do
61
+ o = described_class.new(url, dir, base_opts.merge(parallel: 4))
62
+ expect(o.parallel_workers).to eq(4)
63
+ end
64
+
65
+ it 'is at least 1 for invalid values' do
66
+ o = described_class.new(url, dir, base_opts.merge(parallel: 0))
67
+ expect(o.parallel_workers).to be >= 1
68
+ end
69
+ end
70
+
71
+ describe '#table_parallel_workers' do
72
+ it 'returns 1 when dump_path is nil (piped mode)' do
73
+ o = described_class.new(url, nil, base_opts)
74
+ expect(o.table_parallel_workers(:big_table, 500_000)).to eq(1)
75
+ end
76
+
77
+ it 'returns 1 for tables under 100K rows' do
78
+ expect(op.table_parallel_workers(:small_table, 99_999)).to eq(1)
79
+ end
80
+
81
+ it 'returns >= 2 for tables at the 100K threshold' do
82
+ expect(op.table_parallel_workers(:big_table, 100_000)).to be >= 2
83
+ end
84
+
85
+ it 'returns 1 when --no-split is set' do
86
+ o = described_class.new(url, dir, base_opts.merge(no_split: true))
87
+ expect(o.table_parallel_workers(:big_table, 500_000)).to eq(1)
88
+ end
89
+ end
90
+
91
+ # ── completed_tables (thread safety) ─────────────────────────────────────────
92
+
93
+ describe '#add_completed_table' do
94
+ it 'adds the table name as a string' do
95
+ op.add_completed_table(:users)
96
+ expect(op.completed_tables).to include('users')
97
+ end
98
+
99
+ it 'is thread-safe under concurrent adds' do
100
+ threads = 20.times.map { |i| Thread.new { op.add_completed_table("table_#{i}") } }
101
+ threads.each(&:join)
102
+ expect(op.completed_tables.uniq.size).to eq(20)
103
+ end
104
+ end
105
+
106
+ # ── factory ──────────────────────────────────────────────────────────────────
107
+
108
+ describe '.factory' do
109
+ it 'returns a Pull operation for :pull' do
110
+ result = described_class.factory(:pull, url, dir, base_opts)
111
+ expect(result).to be_a(Tapsoob::Operation::Pull)
112
+ end
113
+
114
+ it 'returns a Push operation for :push' do
115
+ result = described_class.factory(:push, url, dir, base_opts)
116
+ expect(result).to be_a(Tapsoob::Operation::Push)
117
+ end
118
+
119
+ it 'raises on unknown type' do
120
+ expect {
121
+ described_class.factory(:unknown, url, dir, base_opts)
122
+ }.to raise_error(RuntimeError, /Unknown Operation Type/)
123
+ end
124
+ end
125
+
126
+ # ── session persistence ───────────────────────────────────────────────────────
127
+
128
+ describe '#to_hash' do
129
+ it 'includes klass, database_url, stream_state, completed_tables' do
130
+ h = op.to_hash
131
+ expect(h).to include(:klass, :database_url, :stream_state, :completed_tables)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ require 'tapsoob/schema'
3
+
4
+ RSpec.describe Tapsoob::Schema do
5
+ let(:db) do
6
+ d = connect_sqlite
7
+ d.extension :schema_dumper
8
+ d.create_table(:articles) do
9
+ primary_key :id
10
+ String :title, null: false, size: 255
11
+ String :body, text: true
12
+ DateTime :published_at
13
+ end
14
+ d
15
+ end
16
+
17
+ after { db.disconnect }
18
+
19
+ # ── dump_table ───────────────────────────────────────────────────────────────
20
+
21
+ describe '.dump_table' do
22
+ it 'returns a Sequel migration string' do
23
+ result = described_class.dump_table(db, :articles, {})
24
+ expect(result).to include('Sequel::Migration')
25
+ expect(result).to include('articles')
26
+ end
27
+
28
+ it 'accepts a URL string' do
29
+ # sqlite::memory: opens a fresh empty DB on every connect, so dump_table
30
+ # (which opens its own connection) would see no tables. Use a temp file instead.
31
+ require 'tmpdir'
32
+ tmp_path = File.join(Dir.tmpdir, "tapsoob_schema_test_#{Process.pid}.db")
33
+ url = DbHelpers.adapt_url("sqlite://#{tmp_path}")
34
+ begin
35
+ tmp = DbHelpers.connect(url)
36
+ tmp.create_table(:t) { primary_key :id; String :v }
37
+ result = described_class.dump_table(url, :t, {})
38
+ expect(result).to include('Sequel::Migration')
39
+ ensure
40
+ DbHelpers.disconnect_all
41
+ File.delete(tmp_path) rescue nil
42
+ end
43
+ end
44
+ end
45
+
46
+ # ── load / round-trip ────────────────────────────────────────────────────────
47
+
48
+ describe '.load' do
49
+ it 'creates the table in the destination DB' do
50
+ schema_str = described_class.dump_table(db, :articles, {})
51
+
52
+ dest = connect_sqlite
53
+ dest.extension :schema_dumper
54
+ described_class.load(dest, schema_str)
55
+ expect(dest.table_exists?(:articles)).to be true
56
+ dest.disconnect
57
+ end
58
+
59
+ it 'drops then recreates table when drop: true' do
60
+ schema_str = described_class.dump_table(db, :articles, {})
61
+ dest = connect_sqlite
62
+ dest.extension :schema_dumper
63
+ described_class.load(dest, schema_str)
64
+ described_class.load(dest, schema_str, drop: true)
65
+ expect(dest.table_exists?(:articles)).to be true
66
+ dest.disconnect
67
+ end
68
+ end
69
+
70
+ # ── indexes_individual ───────────────────────────────────────────────────────
71
+
72
+ describe '.indexes_individual' do
73
+ let(:indexed_db) do
74
+ d = connect_sqlite
75
+ d.create_table(:idx_test) { primary_key :id; String :email, size: 100 }
76
+ d.add_index(:idx_test, :email)
77
+ d
78
+ end
79
+
80
+ after { indexed_db.disconnect }
81
+
82
+ it 'returns a JSON string' do
83
+ url = sqlite_memory_url
84
+ Sequel.connect(url) do |tmp|
85
+ tmp.create_table(:t) { primary_key :id; String :v }
86
+ tmp.add_index(:t, :v)
87
+ result = described_class.indexes_individual(url)
88
+ expect { JSON.parse(result) }.not_to raise_error
89
+ end
90
+ end
91
+ end
92
+
93
+ # ── reset_db_sequences ───────────────────────────────────────────────────────
94
+
95
+ describe '.reset_db_sequences' do
96
+ it 'runs without error on SQLite (which has no sequences)' do
97
+ expect {
98
+ described_class.reset_db_sequences(sqlite_memory_url)
99
+ }.not_to raise_error
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,260 @@
1
+ require 'spec_helper'
2
+ require 'tapsoob/utils'
3
+
4
+ RSpec.describe Tapsoob::Utils do
5
+ # ── checksum / valid_data ────────────────────────────────────────────────────
6
+
7
+ describe '.checksum' do
8
+ it 'returns a Zlib CRC32 integer' do
9
+ expect(described_class.checksum('hello')).to be_a(Integer)
10
+ end
11
+
12
+ it 'is deterministic for the same input' do
13
+ expect(described_class.checksum('test')).to eq(described_class.checksum('test'))
14
+ end
15
+
16
+ it 'differs for different inputs' do
17
+ expect(described_class.checksum('a')).not_to eq(described_class.checksum('b'))
18
+ end
19
+ end
20
+
21
+ describe '.valid_data?' do
22
+ let(:data) { 'some payload' }
23
+ let(:crc) { described_class.checksum(data) }
24
+
25
+ it 'returns true when checksum matches' do
26
+ expect(described_class.valid_data?(data, crc)).to be true
27
+ end
28
+
29
+ it 'returns false when checksum does not match' do
30
+ expect(described_class.valid_data?(data, crc + 1)).to be false
31
+ end
32
+
33
+ it 'accepts crc as a string (mirrors production code path)' do
34
+ expect(described_class.valid_data?(data, crc.to_s)).to be true
35
+ end
36
+ end
37
+
38
+ # ── base64 round-trip ────────────────────────────────────────────────────────
39
+
40
+ describe '.base64encode / .base64decode' do
41
+ it 'round-trips plain text' do
42
+ text = 'Hello, Tapsoob!'
43
+ expect(described_class.base64decode(described_class.base64encode(text))).to eq(text)
44
+ end
45
+
46
+ it 'round-trips binary data faithfully' do
47
+ binary = Random.bytes(512)
48
+ decoded = described_class.base64decode(described_class.base64encode(binary))
49
+ expect(decoded.bytes).to eq(binary.bytes)
50
+ end
51
+
52
+ it 'round-trips empty string' do
53
+ expect(described_class.base64decode(described_class.base64encode(''))).to eq('')
54
+ end
55
+ end
56
+
57
+ # ── format_data ──────────────────────────────────────────────────────────────
58
+
59
+ describe '.format_data' do
60
+ let(:db) do
61
+ d = connect_sqlite
62
+ d.create_table(:fmt_test) do
63
+ primary_key :id
64
+ String :name, size: 50
65
+ Integer :score
66
+ File :payload
67
+ end
68
+ d
69
+ end
70
+
71
+ # Evaluate schema in the same let-chain so it always uses the same db instance.
72
+ let(:schema) { db.schema(:fmt_test) }
73
+
74
+ after { db.disconnect }
75
+
76
+ it 'returns {} for empty data' do
77
+ expect(described_class.format_data(db, [], schema: schema, table: :fmt_test)).to eq({})
78
+ end
79
+
80
+ it 'builds header, data, types for normal rows' do
81
+ data = [{ id: 1, name: 'Alice', score: 42, payload: nil }]
82
+ result = described_class.format_data(db, data, schema: schema, table: :fmt_test)
83
+ expect(result[:header]).to include(:id, :name, :score, :payload)
84
+ expect(result[:data].first).to include(1, 'Alice', 42)
85
+ expect(result[:types]).to include('integer', 'string')
86
+ end
87
+
88
+ it 'marks File columns as "blob" type' do
89
+ data = [{ id: 1, name: 'x', score: 0, payload: Sequel::SQL::Blob.new('bin') }]
90
+ result = described_class.format_data(db, data, schema: schema, table: :fmt_test)
91
+ payload_idx = result[:header].index(:payload)
92
+ expect(result[:types][payload_idx]).to eq('blob')
93
+ end
94
+
95
+ it 'converts Time objects to ISO-8601 strings' do
96
+ db2 = connect_sqlite
97
+ db2.extension :schema_dumper
98
+ db2.create_table(:ts_test) { primary_key :id; DateTime :ts }
99
+ t = Time.utc(2024, 6, 15, 12, 0, 0)
100
+ data = [{ id: 1, ts: t }]
101
+ result = described_class.format_data(db2, data,
102
+ schema: db2.schema(:ts_test), table: :ts_test)
103
+ ts_idx = result[:header].index(:ts)
104
+ expect(result[:data].first[ts_idx]).to eq('2024-06-15 12:00:00')
105
+ db2.disconnect
106
+ end
107
+ end
108
+
109
+ # ── encode_blobs ─────────────────────────────────────────────────────────────
110
+
111
+ describe '.encode_blobs' do
112
+ it 'base64-encodes Sequel::SQL::Blob values' do
113
+ blob = Sequel::SQL::Blob.new('binary data')
114
+ row = { payload: blob }
115
+ described_class.encode_blobs(row, [:payload])
116
+ expect(row[:payload]).to eq(described_class.base64encode('binary data'))
117
+ end
118
+
119
+ it 'leaves non-blob string columns unchanged' do
120
+ row = { name: 'Alice' }
121
+ described_class.encode_blobs(row, [])
122
+ expect(row[:name]).to eq('Alice')
123
+ end
124
+
125
+ it 'encodes Blob values not in the columns list (auto-detect)' do
126
+ blob = Sequel::SQL::Blob.new('surprise')
127
+ row = { payload: blob }
128
+ described_class.encode_blobs(row, [])
129
+ expect(row[:payload]).to eq(described_class.base64encode('surprise'))
130
+ end
131
+
132
+ it 'skips nil blob values' do
133
+ row = { payload: nil }
134
+ described_class.encode_blobs(row, [:payload])
135
+ expect(row[:payload]).to be_nil
136
+ end
137
+ end
138
+
139
+ # ── calculate_chunksize ──────────────────────────────────────────────────────
140
+
141
+ describe '.calculate_chunksize' do
142
+ it 'returns an Integer' do
143
+ result = described_class.calculate_chunksize(1000) { |_c| 0.5 }
144
+ expect(result).to be_a(Integer)
145
+ end
146
+
147
+ it 'increases chunksize when block returns fast time (< 0.8s)' do
148
+ result = described_class.calculate_chunksize(1000) { |_c| 0.1 }
149
+ expect(result).to be > 1000
150
+ end
151
+
152
+ it 'decreases chunksize when block returns slow time (> 3s)' do
153
+ # time_in_db must be near-zero so the real wall-clock diff drives the decision.
154
+ # We fake it by setting start/end times directly on the Chunksize object.
155
+ result = described_class.calculate_chunksize(900) do |c|
156
+ c.start_time = Time.now - 4.5 # pretend we started 4.5s ago
157
+ 0.0 # time_in_db ≈ 0 → diff = 4.5 > 3.0 → halve
158
+ end
159
+ expect(result).to be < 900
160
+ end
161
+
162
+ it 'retries up to 2 times on EPIPE and then re-raises' do
163
+ calls = 0
164
+ expect {
165
+ described_class.calculate_chunksize(1000) do |c|
166
+ calls += 1
167
+ raise Errno::EPIPE
168
+ end
169
+ }.to raise_error(Errno::EPIPE)
170
+ expect(calls).to eq(3) # initial + 2 retries
171
+ end
172
+ end
173
+
174
+ # ── primary_key / single_integer_primary_key / order_by ─────────────────────
175
+
176
+ describe 'primary key helpers' do
177
+ let(:db) do
178
+ d = connect_sqlite
179
+ d.create_table(:pk_test) { primary_key :id; String :name }
180
+ d.create_table(:cpk_test) { String :a; String :b; primary_key [:a, :b] }
181
+ d.create_table(:nopk) { String :x; String :y }
182
+ d
183
+ end
184
+
185
+ after { db.disconnect }
186
+
187
+ describe '.primary_key' do
188
+ it 'returns [:id] for a single-column integer PK' do
189
+ expect(described_class.primary_key(db, :pk_test)).to eq([:id])
190
+ end
191
+
192
+ it 'returns both columns for a composite PK' do
193
+ expect(described_class.primary_key(db, :cpk_test)).to match_array([:a, :b])
194
+ end
195
+ end
196
+
197
+ describe '.single_integer_primary_key' do
198
+ it 'is true for a single integer PK' do
199
+ expect(described_class.single_integer_primary_key(db, :pk_test)).to be true
200
+ end
201
+
202
+ it 'is false for composite PK' do
203
+ expect(described_class.single_integer_primary_key(db, :cpk_test)).to be false
204
+ end
205
+
206
+ it 'is false for a table with no PK' do
207
+ expect(described_class.single_integer_primary_key(db, :nopk)).to be false
208
+ end
209
+ end
210
+
211
+ describe '.order_by' do
212
+ it 'returns the PK column as an array for keyed tables' do
213
+ expect(described_class.order_by(db, :pk_test)).to eq([:id])
214
+ end
215
+
216
+ it 'returns all columns for tables without a single integer PK' do
217
+ result = described_class.order_by(db, :nopk)
218
+ expect(result).to match_array([:x, :y])
219
+ end
220
+ end
221
+ end
222
+
223
+ # ── export_rows / export_schema / export_indexes (filesystem) ────────────────
224
+
225
+ describe 'filesystem export helpers' do
226
+ let(:dir) { Dir.mktmpdir }
227
+ after { FileUtils.rm_rf(dir) }
228
+
229
+ describe '.export_rows' do
230
+ it 'appends NDJSON lines to the data file' do
231
+ FileUtils.mkdir_p(File.join(dir, 'data'))
232
+ rows = { table_name: :users, header: [:id, :name], data: [[1, 'Alice']] }
233
+ described_class.export_rows(dir, :users, rows)
234
+ described_class.export_rows(dir, :users, rows)
235
+ lines = File.readlines(File.join(dir, 'data', 'users.json'))
236
+ expect(lines.size).to eq(2)
237
+ expect(JSON.parse(lines.first)).to have_key('table_name')
238
+ end
239
+ end
240
+
241
+ describe '.export_schema' do
242
+ it 'writes the schema string to schemas/<table>.rb' do
243
+ FileUtils.mkdir_p(File.join(dir, 'schemas'))
244
+ described_class.export_schema(dir, :users, 'Class.new(Sequel::Migration) { def up; end }')
245
+ content = File.read(File.join(dir, 'schemas', 'users.rb'))
246
+ expect(content).to include('Sequel::Migration')
247
+ end
248
+ end
249
+
250
+ describe '.export_indexes' do
251
+ it 'appends index migration strings as NDJSON' do
252
+ FileUtils.mkdir_p(File.join(dir, 'indexes'))
253
+ described_class.export_indexes(dir, :users, 'add_index :users, :email')
254
+ described_class.export_indexes(dir, :users, 'add_index :users, :name')
255
+ lines = File.readlines(File.join(dir, 'indexes', 'users.json'))
256
+ expect(lines.size).to eq(2)
257
+ end
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'tapsoob/version'
3
+
4
+ RSpec.describe Tapsoob do
5
+ it 'has a version string' do
6
+ expect(Tapsoob::VERSION).to match(/\A\d+\.\d+\.\d+\z/)
7
+ end
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapsoob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.17
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Félix Bellanger
@@ -125,9 +125,21 @@ files:
125
125
  - lib/tapsoob/utils.rb
126
126
  - lib/tapsoob/version.rb
127
127
  - lib/tasks/tapsoob.rake
128
- - spec/lib/tapsoob/chunksize_spec.rb
129
- - spec/lib/tapsoob/version_spec.rb
128
+ - spec/integration/mysql_spec.rb
129
+ - spec/integration/postgres_spec.rb
130
+ - spec/integration/sqlite_spec.rb
130
131
  - spec/spec_helper.rb
132
+ - spec/support/db_helpers.rb
133
+ - spec/support/fixtures.rb
134
+ - spec/support/round_trip_helper.rb
135
+ - spec/support/shared_examples/round_trip.rb
136
+ - spec/system/large_dataset_spec.rb
137
+ - spec/unit/tapsoob/chunksize_spec.rb
138
+ - spec/unit/tapsoob/data_stream_spec.rb
139
+ - spec/unit/tapsoob/operation_base_spec.rb
140
+ - spec/unit/tapsoob/schema_spec.rb
141
+ - spec/unit/tapsoob/utils_spec.rb
142
+ - spec/unit/tapsoob/version_spec.rb
131
143
  - tapsoob.gemspec
132
144
  homepage: https://github.com/Keeguon/tapsoob
133
145
  licenses:
@@ -1,92 +0,0 @@
1
- require 'spec_helper'
2
- require 'tapsoob/chunksize'
3
-
4
- describe Tapsoob::Chunksize do
5
- subject(:tapsoob) { Tapsoob::Chunksize.new(1) }
6
- let(:chunksize) { double('chunksize') }
7
- chunksize = Tapsoob::Chunksize.new(chunksize)
8
- describe '#new' do
9
- it 'works' do
10
- result = Tapsoob::Chunksize.new(chunksize)
11
- expect(result).not_to be_nil
12
- end
13
-
14
- describe '#initialize' do
15
- it { should respond_to :chunksize }
16
- it { should respond_to :idle_secs }
17
- it { should respond_to :retries }
18
- end
19
- end
20
-
21
- describe '#to_i' do
22
-
23
- it { expect(tapsoob.to_i).to eq(1) }
24
- it { expect(tapsoob.to_i).to be_a(Integer) }
25
- it 'works' do
26
- chunksize = Tapsoob::Chunksize.new(chunksize)
27
- result = chunksize.to_i
28
- expect(result).not_to be_nil
29
- end
30
-
31
- context 'converts to type integer' do
32
- it { expect(tapsoob.to_i).to eq(1) }
33
- it { expect(tapsoob.to_i).to be_an(Integer) }
34
- end
35
- end
36
-
37
- describe '#reset_chunksize' do
38
-
39
- context 'retries <= 1' do
40
- it { expect(tapsoob.retries).to eq(0) }
41
- it { expect(tapsoob.reset_chunksize).to eq(10) }
42
- end
43
-
44
- it 'works' do
45
- chunksize = Tapsoob::Chunksize.new(chunksize)
46
- result = chunksize.reset_chunksize
47
- expect(result).not_to be_nil
48
- end
49
- end
50
-
51
-
52
- describe '#diff' do
53
- it 'works' do
54
- chunksize = Tapsoob::Chunksize.new(chunksize)
55
- chunksize.start_time = 1
56
- chunksize.end_time = 10
57
- chunksize.time_in_db = 2
58
- chunksize.idle_secs = 3
59
- result = chunksize.diff
60
- expect(result).not_to be_nil
61
- end
62
- end
63
-
64
- describe '#time_in_db=' do
65
- it 'works' do
66
- chunksize = Tapsoob::Chunksize.new(chunksize)
67
- result = chunksize.time_in_db = (1)
68
- expect(result).not_to be_nil
69
- end
70
- end
71
-
72
- describe '#time_delta' do
73
- it 'works' do
74
- chunksize = double('chunksize')
75
- chunksize = Tapsoob::Chunksize.new(chunksize)
76
- result = chunksize.time_delta
77
- expect(result).not_to be_nil
78
- end
79
- end
80
-
81
- describe '#calc_new_chunksize' do
82
- it 'works' do
83
- chunksize = Tapsoob::Chunksize.new(1)
84
- chunksize.start_time = 1
85
- chunksize.end_time = 10
86
- chunksize.time_in_db = 2
87
- chunksize.idle_secs = 3
88
- result = chunksize.calc_new_chunksize
89
- expect(result).not_to be_nil
90
- end
91
- end
92
- end
@@ -1,7 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Tapsoob::Chunksize do
4
- it 'has a version number' do
5
- expect(Tapsoob::Chunksize).not_to be nil
6
- end
7
- end