perobs 4.0.0 → 4.1.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/lib/perobs.rb +1 -0
  3. data/lib/perobs/Array.rb +66 -19
  4. data/lib/perobs/BTree.rb +83 -12
  5. data/lib/perobs/BTreeBlob.rb +1 -1
  6. data/lib/perobs/BTreeDB.rb +2 -2
  7. data/lib/perobs/BTreeNode.rb +365 -85
  8. data/lib/perobs/BigArray.rb +267 -0
  9. data/lib/perobs/BigArrayNode.rb +998 -0
  10. data/lib/perobs/BigHash.rb +262 -0
  11. data/lib/perobs/BigTree.rb +184 -0
  12. data/lib/perobs/BigTreeNode.rb +873 -0
  13. data/lib/perobs/ConsoleProgressMeter.rb +61 -0
  14. data/lib/perobs/DataBase.rb +4 -3
  15. data/lib/perobs/DynamoDB.rb +57 -15
  16. data/lib/perobs/EquiBlobsFile.rb +143 -51
  17. data/lib/perobs/FNV_Hash_1a_64.rb +54 -0
  18. data/lib/perobs/FlatFile.rb +363 -203
  19. data/lib/perobs/FlatFileBlobHeader.rb +98 -54
  20. data/lib/perobs/FlatFileDB.rb +42 -20
  21. data/lib/perobs/Hash.rb +58 -13
  22. data/lib/perobs/IDList.rb +144 -0
  23. data/lib/perobs/IDListPage.rb +107 -0
  24. data/lib/perobs/IDListPageFile.rb +180 -0
  25. data/lib/perobs/IDListPageRecord.rb +142 -0
  26. data/lib/perobs/Object.rb +18 -15
  27. data/lib/perobs/ObjectBase.rb +38 -4
  28. data/lib/perobs/PersistentObjectCache.rb +53 -67
  29. data/lib/perobs/PersistentObjectCacheLine.rb +24 -12
  30. data/lib/perobs/ProgressMeter.rb +97 -0
  31. data/lib/perobs/SpaceTree.rb +21 -12
  32. data/lib/perobs/SpaceTreeNode.rb +53 -61
  33. data/lib/perobs/Store.rb +71 -32
  34. data/lib/perobs/version.rb +1 -1
  35. data/perobs.gemspec +4 -4
  36. data/test/Array_spec.rb +15 -6
  37. data/test/BTree_spec.rb +5 -2
  38. data/test/BigArray_spec.rb +214 -0
  39. data/test/BigHash_spec.rb +144 -0
  40. data/test/BigTreeNode_spec.rb +153 -0
  41. data/test/BigTree_spec.rb +259 -0
  42. data/test/EquiBlobsFile_spec.rb +105 -1
  43. data/test/FNV_Hash_1a_64_spec.rb +59 -0
  44. data/test/FlatFileDB_spec.rb +63 -14
  45. data/test/Hash_spec.rb +1 -2
  46. data/test/IDList_spec.rb +77 -0
  47. data/test/LegacyDBs/LegacyDB.rb +151 -0
  48. data/test/LegacyDBs/version_3/class_map.json +1 -0
  49. data/test/LegacyDBs/version_3/config.json +1 -0
  50. data/test/LegacyDBs/version_3/database.blobs +0 -0
  51. data/test/LegacyDBs/version_3/database_spaces.blobs +0 -0
  52. data/test/LegacyDBs/version_3/index.blobs +0 -0
  53. data/test/LegacyDBs/version_3/version +1 -0
  54. data/test/LockFile_spec.rb +9 -6
  55. data/test/SpaceTree_spec.rb +4 -1
  56. data/test/Store_spec.rb +290 -199
  57. data/test/spec_helper.rb +9 -4
  58. metadata +47 -10
  59. data/lib/perobs/TreeDB.rb +0 -277
@@ -0,0 +1,59 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2019 by Chris Schlaeger <chris@taskjuggler.org>
4
+ #
5
+ # This file contains tests for Array that are similar to the tests for the
6
+ # Array implementation in MRI. The ideas of these tests were replicated in
7
+ # this code.
8
+ #
9
+ # MIT License
10
+ #
11
+ # Permission is hereby granted, free of charge, to any person obtaining
12
+ # a copy of this software and associated documentation files (the
13
+ # "Software"), to deal in the Software without restriction, including
14
+ # without limitation the rights to use, copy, modify, merge, publish,
15
+ # distribute, sublicense, and/or sell copies of the Software, and to
16
+ # permit persons to whom the Software is furnished to do so, subject to
17
+ # the following conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be
20
+ # included in all copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+
30
+ require 'spec_helper'
31
+
32
+ require 'perobs'
33
+
34
+ describe PEROBS::FNV_Hash_1a_64 do
35
+
36
+ it 'should generate stable hashes for Strings' do
37
+ refs = [
38
+ [ 'foo', 15902901984413996407 ],
39
+ [ 'foo', 15902901984413996407 ],
40
+ [ 'bar', 16101355973854746 ],
41
+ [ 'foobar', 9625390261332436968 ],
42
+ [ 'PEROBS rocks your application!', 4089220442501866848 ],
43
+ [ 'Permission is hereby granted, free of charge, to any person ' +
44
+ 'obtaining a copy of this software and associated documentation ' +
45
+ 'files (the "Software"), to deal in the Software without ' +
46
+ 'restriction, including without limitation the rights to use, ' +
47
+ 'copy, modify, merge, publish, distribute, sublicense, and/or ' +
48
+ 'sell copies of the Software, and to permit persons to whom the ' +
49
+ 'Software is furnished to do so, subject to the following conditions:',
50
+ 17637146001033534275 ]
51
+ ]
52
+
53
+ refs.each do |v|
54
+ expect(PEROBS::FNV_Hash_1a_64::digest(v[0])).to eql(v[1])
55
+ end
56
+ end
57
+
58
+ end
59
+
@@ -28,6 +28,7 @@ require 'fileutils'
28
28
  require 'spec_helper'
29
29
  require 'perobs/FlatFileDB'
30
30
  require 'perobs/Store'
31
+ require 'LegacyDBs/LegacyDB'
31
32
 
32
33
  class FlatFileDB_O < PEROBS::Object
33
34
 
@@ -47,7 +48,12 @@ describe PEROBS::FlatFileDB do
47
48
  before(:each) do
48
49
  @db_dir = generate_db_name(__FILE__)
49
50
  FileUtils.mkdir_p(@db_dir)
50
- @store = PEROBS::Store.new(@db_dir, :engine => PEROBS::FlatFileDB)
51
+ @store_options = {
52
+ :engine => PEROBS::FlatFileDB,
53
+ :log => $stderr,
54
+ :log_level => Logger::ERROR
55
+ }
56
+ @store = PEROBS::Store.new(@db_dir, @store_options)
51
57
  end
52
58
 
53
59
  after(:each) do
@@ -67,17 +73,13 @@ describe PEROBS::FlatFileDB do
67
73
 
68
74
  it 'should do a version upgrade' do
69
75
  # Close the store
70
- @store['o'] = @store.new(FlatFileDB_O)
71
76
  @store.exit
77
+ src_dir = File.join(File.dirname(__FILE__), 'LegacyDBs', 'version_3')
78
+ FileUtils.cp_r(Dir.glob(src_dir + '/*'), @db_dir)
72
79
 
73
- # Manually downgrade the version file to version 1
74
- version_file = File.join(@db_dir, 'version')
75
- File.write(version_file, '1')
76
-
77
- # Open the store again
78
- store = PEROBS::Store.new(@db_dir, :engine => PEROBS::FlatFileDB)
79
- expect(File.read(version_file).to_i).to eql(PEROBS::FlatFileDB::VERSION)
80
- expect(store['o'].b).to eql(42)
80
+ db = LegacyDB.new(@db_dir)
81
+ capture_io { db.open }
82
+ capture_io { expect(db.check).to be true }
81
83
  end
82
84
 
83
85
  it 'should refuse a version downgrade' do
@@ -89,7 +91,7 @@ describe PEROBS::FlatFileDB do
89
91
  File.write(version_file, '1000000')
90
92
 
91
93
  # Open the store again
92
- expect { PEROBS::Store.new(@db_dir, :engine => PEROBS::FlatFileDB) }.to raise_error(PEROBS::FatalError)
94
+ expect { PEROBS::Store.new(@db_dir) }.to raise_error(PEROBS::FatalError)
93
95
  end
94
96
 
95
97
  it 'should recover from a lost index file' do
@@ -97,7 +99,10 @@ describe PEROBS::FlatFileDB do
97
99
  @store.exit
98
100
 
99
101
  File.delete(File.join(@db_dir, 'index.blobs'))
100
- store = PEROBS::Store.new(@db_dir, :engine => PEROBS::FlatFileDB)
102
+ store = nil
103
+ capture_io do
104
+ store = PEROBS::Store.new(@db_dir)
105
+ end
101
106
  expect(store['o'].b).to eql(42)
102
107
  end
103
108
 
@@ -106,10 +111,54 @@ describe PEROBS::FlatFileDB do
106
111
  @store.exit
107
112
 
108
113
  File.write(File.join(@db_dir, 'index.blobs'), '*' * 500)
109
- store = PEROBS::Store.new(@db_dir, :engine => PEROBS::FlatFileDB)
110
- store.check(true)
114
+ store = nil
115
+ capture_io do
116
+ store = PEROBS::Store.new(@db_dir)
117
+ end
118
+ capture_io { store.check(true) }
111
119
  expect(store['o'].b).to eql(42)
112
120
  end
113
121
 
122
+ it 'should repair a corrupted database.blobs file' do
123
+ @store.exit
124
+
125
+ db = PEROBS::FlatFileDB.new(@db_dir)
126
+ db_file = File.join(@db_dir, 'database.blobs')
127
+ db.open
128
+ 0.upto(5) do |i|
129
+ db.put_object("#{i + 1}:#{'X' * (i + 1) * 30}", i + 1)
130
+ end
131
+ db.close
132
+ db.open
133
+ 0.upto(5) do |i|
134
+ db.put_object("#{i + 10}:#{'Y' * (i + 1) * 25}", i + 10)
135
+ end
136
+ pos = db.instance_variable_get('@flat_file').find_obj_addr_by_id(10)
137
+ db.close
138
+
139
+ f = File.open(db_file, 'rb+')
140
+ f.seek(pos)
141
+ f.write('ZZZZZ')
142
+ f.close
143
+
144
+ db.open
145
+ expect(db.check_db).to eql(2)
146
+ expect(db.check_db(true)).to eql(1)
147
+ db.close
148
+ db = PEROBS::FlatFileDB.new(@db_dir, { :log => $stderr,
149
+ :log_level => Logger::ERROR })
150
+ db.open
151
+ expect(db.check_db).to eql(0)
152
+
153
+ 0.upto(5) do |i|
154
+ expect(db.get_object(i + 1)).to eql("#{i + 1}:#{'X' * (i + 1) * 30}")
155
+ end
156
+ expect(db.get_object(10)).to be_nil
157
+ 1.upto(5) do |i|
158
+ expect(db.get_object(i + 10)).to eql("#{i + 10}:#{'Y' * (i + 1) * 25}")
159
+ end
160
+ db.close
161
+ end
162
+
114
163
  end
115
164
 
@@ -169,9 +169,8 @@ describe PEROBS::Hash do
169
169
  it 'should catch a leaked PEROBS::ObjectBase object' do
170
170
  @store['a'] = a = @store.new(PEROBS::Hash)
171
171
  o = @store.new(PO)
172
- a['a'] = o.get_self
173
172
  PEROBS.log.open(StringIO.new)
174
- expect { @store.sync }.to raise_error(PEROBS::FatalError)
173
+ expect { a['a'] = o.get_self }.to raise_error(PEROBS::FatalError)
175
174
  PEROBS.log.open($stderr)
176
175
  end
177
176
 
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2016, 2017 by Chris Schlaeger <chris@taskjuggler.org>
4
+ #
5
+ # MIT License
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ require 'spec_helper'
27
+ require 'perobs/IDList'
28
+
29
+ module PEROBS
30
+
31
+ describe IDList do
32
+
33
+ before(:all) do
34
+ @db_dir = generate_db_name('IDList')
35
+ FileUtils.mkdir_p(@db_dir)
36
+ @list = PEROBS::IDList.new(@db_dir, 'idlist', 16, 64)
37
+ end
38
+
39
+ after(:all) do
40
+ @list.erase
41
+ FileUtils.rm_rf(@db_dir)
42
+ end
43
+
44
+ it 'should not contain any values' do
45
+ expect(@list.to_a).to eql []
46
+ expect(@list.include?(0)).to be false
47
+ expect(@list.include?(1)).to be false
48
+ expect { @list.check }.to_not raise_error
49
+ end
50
+
51
+ it 'should store a large number of values' do
52
+ vals = []
53
+ 50000.times do
54
+ v = rand(2 ** 64)
55
+ vals << v
56
+
57
+ next if @list.include?(v)
58
+ @list.insert(v)
59
+ #expect(@list.include?(v)).to be true
60
+ 0.upto(rand(10)) do
61
+ v = vals[rand(vals.length)]
62
+ expect(@list.include?(v)).to be true
63
+ end
64
+
65
+ #expect { @list.check }.to_not raise_error if rand(1000) == 0
66
+ end
67
+ expect { @list.check }.to_not raise_error
68
+
69
+ vals.each do |v|
70
+ expect(@list.include?(v)).to be true
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
@@ -0,0 +1,151 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2015 by Chris Schlaeger <chris@taskjuggler.org>
4
+ #
5
+ # MIT License
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
27
+
28
+ require 'perobs'
29
+
30
+ # This class creates and manages a simple DB with some toy data to check the
31
+ # conversion routines for legacy DB formats.
32
+ class LegacyDB
33
+
34
+ class Fragment < PEROBS::Object
35
+
36
+ attr_persist :str, :pred, :succ
37
+
38
+ def initialize(p, str, pred = nil)
39
+ super(p)
40
+ self.str = str
41
+ self.pred = pred
42
+ self.succ = nil
43
+ end
44
+
45
+ end
46
+
47
+ N1 = 293
48
+ N2 = 427
49
+
50
+ def initialize(name)
51
+ @name = name
52
+ @store = nil
53
+ end
54
+
55
+ def create
56
+ @store = PEROBS::Store.new(@name)
57
+ @store['fragments'] = @store.new(PEROBS::Array)
58
+ @store['metadata'] = @store.new(PEROBS::Hash)
59
+ @store['by_length'] = @store.new(PEROBS::Hash)
60
+
61
+ # Create a long string of digits.
62
+ number = (N1**N2).to_s
63
+ # Find a suitable digit that we can use a separator to split the long
64
+ # string into smaller strings.
65
+ separator = find_separator(number)
66
+ @store['metadata']['separator'] = separator
67
+ pred = nil
68
+ # Store all the fragments in the @store['fragments'] array.
69
+ number.split(separator).each do |fragment|
70
+ @store['fragments'] << (f = @store.new(Fragment, fragment, pred))
71
+ # Additionally, we create the doubly-linked list of the fragments.
72
+ pred.succ = f if pred
73
+ pred = f
74
+ # And we store the fragments hashed by their length.
75
+ length = fragment.length.to_s
76
+ if @store['by_length'][length].nil?
77
+ @store['by_length'][length] = @store.new(PEROBS::Array)
78
+ end
79
+ @store['by_length'][length] << f
80
+ end
81
+ @store.exit
82
+ end
83
+
84
+ def open
85
+ @store = PEROBS::Store.new(@name)
86
+ end
87
+
88
+ def check
89
+ # Recreate the original number from the @store['fragments'] list.
90
+ number = @store['fragments'].map { |f| f.str }.
91
+ join(@store['metadata']['separator'])
92
+ if number.to_i != N1 ** N2
93
+ raise RuntimeError, "Number mismatch\n#{number}\n#{N1 ** N2}"
94
+ end
95
+
96
+ # Check the total number of digits based on the bash by length.
97
+ fragment_counter = 0
98
+ total_fragment_length = 0
99
+ @store['by_length'].each do |length, fragments|
100
+ fragment_counter += fragments.length
101
+ total_fragment_length += length.to_i * fragments.length
102
+ end
103
+ if number.length != total_fragment_length + fragment_counter - 1
104
+ raise RuntimeError, "Number length mismatch"
105
+ end
106
+
107
+ # Recreate the original number from the linked list forward traversal.
108
+ number = ''
109
+ f = @store['fragments'][0]
110
+ while f
111
+ number += @store['metadata']['separator'] unless number.empty?
112
+ number += f.str
113
+ f = f.succ
114
+ end
115
+ if number.to_i != N1 ** N2
116
+ raise RuntimeError, "Number mismatch\n#{number}\n#{N1 ** N2}"
117
+ end
118
+
119
+ # Recreate the original number from the linked list backwards traversal.
120
+ number = ''
121
+ f = @store['fragments'][-1]
122
+ while f
123
+ number = @store['metadata']['separator'] + number unless number.empty?
124
+ number = f.str + number
125
+ f = f.pred
126
+ end
127
+ if number.to_i != N1 ** N2
128
+ raise RuntimeError, "Number mismatch\n#{number}\n#{N1 ** N2}"
129
+ end
130
+
131
+ true
132
+ end
133
+
134
+ private
135
+
136
+ def find_separator(str)
137
+ 0.upto(9) do |digit|
138
+ c = digit.to_s
139
+ return c if str[0] != c && str[-1] != c
140
+ end
141
+
142
+ raise RuntimeError, "Could not find separator"
143
+ end
144
+
145
+ end
146
+
147
+ #db = LegacyDB.new('test')
148
+ #db.create
149
+ #db.open
150
+ #db.check
151
+
@@ -0,0 +1 @@
1
+ {"PEROBS::Hash":0,"PEROBS::Array":1,"LegacyDB::Fragment":2}
@@ -0,0 +1 @@
1
+ {"serializer":{"json_class":"Symbol","s":"json"}}
@@ -30,7 +30,11 @@ require 'perobs/LockFile'
30
30
  describe PEROBS::LockFile do
31
31
 
32
32
  before(:each) do
33
- @dir = Dir.mktmpdir('LockFile')
33
+ PEROBS.log.open($stderr)
34
+ PEROBS.log.level = Logger::INFO
35
+ @dir = File.join(Dir.tmpdir,
36
+ "#{File.basename('LockFile_spec')}.#{rand(2**32)}")
37
+ FileUtils.mkdir_p(@dir)
34
38
  @file = File.join(@dir, 'LockFile.lock')
35
39
  end
36
40
 
@@ -42,7 +46,6 @@ describe PEROBS::LockFile do
42
46
  capture_io do
43
47
  expect(PEROBS::LockFile.new('/foo/bar/foobar').lock).to be false
44
48
  end
45
- PEROBS.log.open($stderr)
46
49
  end
47
50
 
48
51
  it 'should support taking and releasing the lock' do
@@ -59,7 +62,7 @@ describe PEROBS::LockFile do
59
62
  expect(lock.is_locked?).to be true
60
63
  lock.forced_unlock
61
64
  expect(lock.is_locked?).to be false
62
- out = capture_io{ expect(lock.unlock).to be false }
65
+ out = capture_io{ expect(lock.unlock).to be false }.log
63
66
  expect(out).to include('There is no current lock to release')
64
67
  end
65
68
 
@@ -67,7 +70,7 @@ describe PEROBS::LockFile do
67
70
  lock1 = PEROBS::LockFile.new(@file)
68
71
  expect(lock1.lock).to be true
69
72
  lock2 = PEROBS::LockFile.new(@file)
70
- out = capture_io { expect(lock2.lock).to be false }
73
+ out = capture_io { expect(lock2.lock).to be false }.log
71
74
  expect(out).to include('due to timeout')
72
75
  expect(lock1.unlock).to be true
73
76
  expect(lock2.lock).to be true
@@ -105,7 +108,7 @@ describe PEROBS::LockFile do
105
108
  end
106
109
  lock2 = PEROBS::LockFile.new(@file,
107
110
  { :max_retries => 2, :pause_secs => 0.5 })
108
- out = capture_io { expect(lock2.lock).to be false }
111
+ out = capture_io { expect(lock2.lock).to be false }.log
109
112
  expect(out).to include('due to timeout')
110
113
  Process.wait(pid)
111
114
  end
@@ -123,7 +126,7 @@ describe PEROBS::LockFile do
123
126
  end
124
127
 
125
128
  lock2 = PEROBS::LockFile.new(@file, { :timeout_secs => 1 })
126
- out = capture_io { expect(lock2.lock).to be true }
129
+ out = capture_io { expect(lock2.lock).to be true }.log
127
130
  expect(out).to include('Old lock file found for PID')
128
131
  expect(lock2.unlock).to be true
129
132
  Process.wait(pid)