beanstalk_integration_tests 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +22 -0
  4. data/README.md +38 -0
  5. data/Rakefile +9 -0
  6. data/beanstalk_integration_tests.gemspec +26 -0
  7. data/lib/beanstalk_integration_tests.rb +2 -0
  8. data/lib/beanstalk_integration_tests/bury_test.rb +137 -0
  9. data/lib/beanstalk_integration_tests/delete_test.rb +160 -0
  10. data/lib/beanstalk_integration_tests/ignore_test.rb +127 -0
  11. data/lib/beanstalk_integration_tests/kick_job_test.rb +68 -0
  12. data/lib/beanstalk_integration_tests/kick_test.rb +207 -0
  13. data/lib/beanstalk_integration_tests/list_tube_used_test.rb +26 -0
  14. data/lib/beanstalk_integration_tests/list_tubes_test.rb +26 -0
  15. data/lib/beanstalk_integration_tests/list_tubes_watched_test.rb +26 -0
  16. data/lib/beanstalk_integration_tests/pause_tube_test.rb +166 -0
  17. data/lib/beanstalk_integration_tests/peek_test.rb +242 -0
  18. data/lib/beanstalk_integration_tests/put_test.rb +255 -0
  19. data/lib/beanstalk_integration_tests/quit_test.rb +24 -0
  20. data/lib/beanstalk_integration_tests/release_test.rb +191 -0
  21. data/lib/beanstalk_integration_tests/reserve_test.rb +385 -0
  22. data/lib/beanstalk_integration_tests/stats_job_test.rb +116 -0
  23. data/lib/beanstalk_integration_tests/stats_test.rb +130 -0
  24. data/lib/beanstalk_integration_tests/stats_tube_test.rb +141 -0
  25. data/lib/beanstalk_integration_tests/test_helper.rb +88 -0
  26. data/lib/beanstalk_integration_tests/tests.rb +4 -0
  27. data/lib/beanstalk_integration_tests/touch_test.rb +118 -0
  28. data/lib/beanstalk_integration_tests/use_test.rb +118 -0
  29. data/lib/beanstalk_integration_tests/version.rb +3 -0
  30. data/lib/beanstalk_integration_tests/watch_test.rb +128 -0
  31. metadata +157 -0
@@ -0,0 +1,116 @@
1
+ require 'beanstalk_integration_tests/test_helper'
2
+
3
+ class StatsJobTest < BeanstalkIntegrationTest
4
+
5
+ context 'stats-job' do
6
+
7
+ setup do
8
+ client.transmit("use #{tube_name}")
9
+ end
10
+
11
+
12
+ should 'return stats for the specified job with all expected keys' do
13
+ message = uuid
14
+ job_id = client.transmit("put 0 0 120 #{message.bytesize}\r\n#{message}")[:id]
15
+ initial_cmd_stats_job = client.transmit('stats')[:body]['cmd-stats-job']
16
+ response = client.transmit("stats-job #{job_id}")
17
+ assert_equal 'OK', response[:status]
18
+ job_stats = response[:body]
19
+ expected_keys = %w[
20
+ id tube state pri age delay ttr time-left file reserves timeouts
21
+ releases buries kicks
22
+ ]
23
+ assert_equal expected_keys, job_stats.keys
24
+ assert_nil job_stats.values.compact!, 'Expected job stats to have no nil values'
25
+ assert_equal(initial_cmd_stats_job + 1, client.transmit('stats')[:body]['cmd-stats-job'], 'Expected cmd-stats-job to be incremented')
26
+ end
27
+
28
+ # Some stats are tested elsewhere:
29
+ #
30
+ # :id => See below
31
+ # :tube => PutTest
32
+ # :state => PutTest, BuryTest, ReleaseTest
33
+ # :pri => PutTest, BuryTest, ReleaseTest
34
+ # :age => See below
35
+ # :time-left => PutTest, TouchTest
36
+ # :file => NOT TESTED (except for presence)
37
+ # :reserves => ReserveTest
38
+ # :timeouts => TouchTest
39
+ # :releases => ReleaseTest
40
+ # :buries => BuryTest
41
+ # :kicks => KickTest, KickJobTest
42
+ #
43
+ # For those that aren't...
44
+
45
+ should 'return correct id' do
46
+ message = uuid
47
+ job_id = client.transmit("put 0 0 120 #{message.bytesize}\r\n#{message}")[:id]
48
+ assert_equal(job_id.to_i, client.transmit("stats-job #{job_id}")[:body]['id'], 'Expected job-stats[id] to return correct job id')
49
+ end
50
+
51
+
52
+ should 'return correct age' do
53
+ message = uuid
54
+ job_id = client.transmit("put 0 0 120 #{message.bytesize}\r\n#{message}")[:id]
55
+ initial_job_age = client.transmit("stats-job #{job_id}")[:body]['age']
56
+ sleep 1
57
+ assert_equal(initial_job_age + 1, client.transmit("stats-job #{job_id}")[:body]['age'], 'Expected job-stats[age] to return incremented job age')
58
+ end
59
+
60
+
61
+ should 'return NOT_FOUND if the job has never existed' do
62
+ message = uuid
63
+ job_id = client.transmit("put 0 0 120 #{message.bytesize}\r\n#{message}")[:id]
64
+ initial_cmd_stats_job = client.transmit('stats')[:body]['cmd-stats-job']
65
+ assert_raises(Beaneater::NotFoundError, 'Expected job-stats for non-existent job to return NOT_FOUND') do
66
+ client.transmit("stats-job #{job_id.to_i + 1}")
67
+ end
68
+ assert_equal(initial_cmd_stats_job + 1, client.transmit('stats')[:body]['cmd-stats-job'], 'Expected cmd-stats-job to be incremented')
69
+ end
70
+
71
+
72
+ should 'return NOT_FOUND if the job is deleted' do
73
+ message = uuid
74
+ job_id = client.transmit("put 0 0 120 #{message.bytesize}\r\n#{message}")[:id]
75
+ client.transmit("delete #{job_id}")
76
+ initial_cmd_stats_job = client.transmit('stats')[:body]['cmd-stats-job']
77
+ assert_raises(Beaneater::NotFoundError, 'Expected job-stats for deleted job to return NOT_FOUND') do
78
+ client.transmit("stats-job #{job_id}")
79
+ end
80
+ assert_equal(initial_cmd_stats_job + 1, client.transmit('stats')[:body]['cmd-stats-job'], 'Expected cmd-stats-job to be incremented')
81
+ end
82
+
83
+
84
+ should 'return BAD_FORMAT without trailing space' do
85
+ initial_cmd_stats_job = client.transmit('stats')[:body]['cmd-stats-job']
86
+ assert_raises(Beaneater::BadFormatError, 'Expected job-stats without space to return BAD_FORMAT') do
87
+ client.transmit('stats-job')
88
+ end
89
+ assert_equal(initial_cmd_stats_job, client.transmit('stats')[:body]['cmd-stats-job'], 'Expected cmd-stats-job to be unchanged')
90
+ end
91
+
92
+
93
+ should 'return NOT_FOUND if job id is null, negative, or non-integer' do
94
+ ['', -5, 'foo'].each do |job_id|
95
+ initial_cmd_stats_job = client.transmit('stats')[:body]['cmd-stats-job']
96
+ assert_raises(Beaneater::NotFoundError, 'Expected job-stats for invalid job id to return NOT_FOUND') do
97
+ client.transmit("stats-job #{job_id}")
98
+ end
99
+ assert_equal(initial_cmd_stats_job + 1, client.transmit('stats')[:body]['cmd-stats-job'], 'Expected cmd-stats-job to be incremented')
100
+ end
101
+ end
102
+
103
+
104
+ should 'ignore trailing space, arguments, and chars' do
105
+ message = uuid
106
+ job_id = client.transmit("put 0 0 120 #{message.bytesize}\r\n#{message}")[:id]
107
+ [' ', ' and ignore these arguments', '_and_ignore_these_letters'].each do |trailer|
108
+ initial_cmd_stats_job = client.transmit('stats')[:body]['cmd-stats-job']
109
+ client.transmit("stats-job #{job_id}#{trailer}")
110
+ assert_equal(initial_cmd_stats_job + 1, client.transmit('stats')[:body]['cmd-stats-job'], 'Expected cmd-stats-job to be incremented')
111
+ end
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,130 @@
1
+ require 'beanstalk_integration_tests/test_helper'
2
+ require 'socket'
3
+ require 'English'
4
+
5
+ class StatsTest < BeanstalkIntegrationTest
6
+
7
+ context 'stats' do
8
+
9
+ should 'return server stats with expected keys' do
10
+ expected_keys = %w[
11
+ current-jobs-urgent current-jobs-ready current-jobs-reserved current-jobs-delayed
12
+ current-jobs-buried cmd-put cmd-peek cmd-peek-ready cmd-peek-delayed cmd-peek-buried cmd-reserve
13
+ cmd-reserve-with-timeout cmd-delete cmd-release cmd-use cmd-watch cmd-ignore cmd-bury cmd-kick
14
+ cmd-touch cmd-stats cmd-stats-job cmd-stats-tube cmd-list-tubes cmd-list-tube-used
15
+ cmd-list-tubes-watched cmd-pause-tube job-timeouts total-jobs max-job-size current-tubes
16
+ current-connections current-producers current-workers current-waiting total-connections pid
17
+ version rusage-utime rusage-stime uptime binlog-oldest-index binlog-current-index
18
+ binlog-records-migrated binlog-records-written binlog-max-size id hostname
19
+ ]
20
+ initial_cmd_stats = client.transmit('stats')[:body]['cmd-stats']
21
+ response = client.transmit('stats')
22
+ assert_equal 'OK', response[:status]
23
+ assert_equal expected_keys, response[:body].keys
24
+ assert_nil response[:body].values.compact!, 'Expected stats to include no nil values'
25
+ assert_equal(initial_cmd_stats + 1, response[:body]['cmd-stats'], 'Expected cmd-stats to be incremented')
26
+ end
27
+
28
+ # Some stats are tested elsewhere:
29
+ #
30
+ # :current-jobs-urgent => PutTest, ReleaseTest
31
+ # :current-jobs-ready => PutTest, ReleaseTest
32
+ # :current-jobs-reserved => ReserveTest, ReleaseTest
33
+ # :current-jobs-delayed => KickTest, PutTest, ReleaseTest
34
+ # :current-jobs-buried => BuryTest, KickTest
35
+ # :total-jobs => PutTest
36
+ # :cmd-put => PutTest
37
+ # :cmd-peek => PeekTest
38
+ # :cmd-peek-ready => PeekTest
39
+ # :cmd-peek-delayed => PeekTest
40
+ # :cmd-peek-buried => PeekTest
41
+ # :cmd-reserve => ReserveTest
42
+ # :cmd-use => UseTest
43
+ # :cmd-watch => WatchTest
44
+ # :cmd-ignore => IgnoreTest
45
+ # :cmd-delete => DeleteTest
46
+ # :cmd-release => ReleaseTest
47
+ # :cmd-bury => BuryTest
48
+ # :cmd-kick => KickTest
49
+ # :cmd-stats => See above/below
50
+ # :cmd-stats-job => StatsJobTest
51
+ # :cmd-stats-tube => StatsTubeTest
52
+ # :cmd-list-tubes => ListTubesTest
53
+ # :cmd-list-tube-used => ListTubeUsedTest
54
+ # :cmd-list-tubes-watched => ListTubesWatchedTest
55
+ # :cmd-pause-tube => PauseTubeTest
56
+ # :job-timeouts => TouchTest
57
+ # :total-jobs => PutTest
58
+ # :max-job-size => PutTest (Tests retrieval directly, indiectly tests value set correctly)
59
+ # :current-tube => UseTest, Watch Test
60
+ # :current-connections => See below
61
+ # :current-producers => PutTest
62
+ # :current-workers => ReserveTest
63
+ # :current-waiting => ReserveTest
64
+ # :total-connections => See below
65
+ # :pid => See below
66
+ # :version => NOT TESTED only tested for presence
67
+ # :rusage-utime => NOT TESTED only tested for presence
68
+ # :rusage-stime => NOT TESTED only tested for presence
69
+ # :uptime => See below
70
+ # :binlog-oldest-index => NOT TESTED only tested for presence
71
+ # :binlog-current-index => NOT TESTED only tested for presence
72
+ # :binlog-max-size => NOT TESTED only tested for presence
73
+ # :binlog-records-written => NOT TESTED only tested for presence
74
+ # :binlog-records-written => NOT TESTED only tested for presence
75
+ # :id => NOT TESTED only tested for presence
76
+ # :hostname => See below
77
+ #
78
+ # For those that aren't...
79
+
80
+
81
+ should 'return correct hostname' do
82
+ # This test assume tests and beanstalk are being run on same host
83
+ assert_equal Socket.gethostname, client.transmit('stats')[:body]['hostname']
84
+ end
85
+
86
+
87
+ should 'return correct uptime' do
88
+ initial_uptime = client.transmit('stats')[:body]['uptime']
89
+ sleep 1
90
+ updated_uptime = client.transmit('stats')[:body]['uptime']
91
+ assert(updated_uptime > initial_uptime, 'Expected uptime to to be incremented')
92
+ end
93
+
94
+
95
+ should 'return correct pid' do
96
+ %x[which pgrep]
97
+ skip('pgrep is required to determine possible pids') unless $CHILD_STATUS.success?
98
+ pids = %x[pgrep -f beanstalk].split
99
+
100
+ stats = client.transmit('stats')[:body]
101
+ assert(pids.include?(stats['pid'].to_s), 'Expected pids for processes with beanstalk in title to include beanstalk pid')
102
+ end
103
+
104
+
105
+ should 'return correct count of current-connections and total-connections' do
106
+ stats = client.transmit('stats')[:body]
107
+ initial_current_connections = stats['current-connections']
108
+ initial_total_connections = stats['total-connections']
109
+ other_client = build_client
110
+ stats = client.transmit('stats')[:body]
111
+ assert_equal(initial_current_connections + 1, stats['current-connections'], 'Expected current-connections to be incremented')
112
+ assert_equal(initial_total_connections + 1, stats['total-connections'], 'Expected total-connections to be incremented')
113
+ other_client.close
114
+ assert_equal(stats['current-connections'] - 1, client.transmit('stats')[:body]['current-connections'], 'Expected current-connections to be decremented')
115
+ end
116
+
117
+
118
+ should 'return BAD_FORMAT with any trailing characters' do
119
+ initial_cmd_stats = client.transmit('stats')[:body]['cmd-stats']
120
+ [' ', ' foo'].each do |trailer|
121
+ assert_raises(Beaneater::BadFormatError, 'Expected stats with any trailing characters to return BAD_FORMAT') do
122
+ client.transmit("stats#{trailer}")
123
+ end
124
+ end
125
+ assert_equal(initial_cmd_stats + 1, client.transmit('stats')[:body]['cmd-stats'], 'Expected cmd-stats to be unchanged')
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,141 @@
1
+ require 'beanstalk_integration_tests/test_helper'
2
+
3
+ class StatsTubeTest < BeanstalkIntegrationTest
4
+
5
+ context 'stats-tube' do
6
+
7
+ setup do
8
+ client.transmit("use #{tube_name}")
9
+ end
10
+
11
+
12
+ should 'return stats for the specified tube with all expected keys' do
13
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
14
+ response = client.transmit("stats-tube #{tube_name}")
15
+ assert_equal 'OK', response[:status]
16
+ tube_stats = response[:body]
17
+ expected_keys = %w[
18
+ name current-jobs-urgent current-jobs-ready current-jobs-reserved current-jobs-delayed
19
+ current-jobs-buried total-jobs current-using current-watching current-waiting cmd-delete
20
+ cmd-pause-tube pause pause-time-left
21
+ ]
22
+ assert_equal expected_keys, tube_stats.keys
23
+ assert_nil tube_stats.values.compact!, 'Expected tube stats to have no nil values'
24
+ assert_equal(initial_cmd_stats_tube + 1, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be incremented')
25
+ end
26
+
27
+
28
+ # Some stats are tested elsewhere:
29
+ #
30
+ # :name => See below
31
+ # :current-jobs-urgent => PutTest, ReleaseTest
32
+ # :current-jobs-ready => PutTest, ReleaseTest
33
+ # :current-jobs-reserved => ReserveTest, ReleaseTest
34
+ # :current-jobs-delayed => KickTest, PutTest, ReleaseTest
35
+ # :current-jobs-buried => BuryTest, KickTest
36
+ # :total-jobs => PutTest
37
+ # :current-using => UseTest
38
+ # :current-waiting => ReserveTest
39
+ # :current-watching => IgnoreTest, UseTest, WatchTest
40
+ # :pause => PauseTubeTest
41
+ # :cmd-delete => DeleteTest
42
+ # :cmd-pause-tube => PauseTubeTest
43
+ # :pause-time-left => PauseTubeTest
44
+ #
45
+ # For those that aren't...
46
+
47
+
48
+ should 'return expected tube name' do
49
+ assert_equal(tube_name, client.transmit("stats-tube #{tube_name}")[:body]['name'], 'Expected stats-tube to return correct tube name')
50
+ end
51
+
52
+
53
+ should 'return NOT_FOUND if the tube has never existed' do
54
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
55
+ assert_raises(Beaneater::NotFoundError, 'Expected tube-stats for non-existent tube to return NOT_FOUND') do
56
+ client.transmit("stats-tube #{uuid}")
57
+ end
58
+ assert_equal(initial_cmd_stats_tube + 1, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be incremented')
59
+ end
60
+
61
+
62
+ should 'return NOT_FOUND if the tube is deleted' do
63
+ client.transmit('use default')
64
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
65
+ assert_raises(Beaneater::NotFoundError, 'Expected tube-stats for deleted tube to return NOT_FOUND') do
66
+ client.transmit("stats-tube #{tube_name}")
67
+ end
68
+ assert_equal(initial_cmd_stats_tube + 1, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be incremented')
69
+ end
70
+
71
+
72
+ should 'return BAD_FORMAT without trailing space' do
73
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
74
+ assert_raises(Beaneater::BadFormatError, 'Expected tube-stats without space to return BAD_FORMAT') do
75
+ client.transmit('stats-tube')
76
+ end
77
+ assert_equal(initial_cmd_stats_tube, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be unchanged')
78
+ end
79
+
80
+
81
+ should 'return BAD_FORMAT if tube name is null' do
82
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
83
+ assert_raises(Beaneater::BadFormatError, 'Expected tube-stats with null tube name to return BAD_FORMAT') do
84
+ client.transmit('stats-tube ')
85
+ end
86
+ assert_equal(initial_cmd_stats_tube, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be unchanged')
87
+ end
88
+
89
+
90
+ should 'be able to handle tube name of maximum length' do
91
+ name = 'x' * 200
92
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
93
+ client.transmit("watch #{name}")
94
+ response = client.transmit("stats-tube #{name}")
95
+ assert_equal 'OK', response[:status]
96
+ assert_equal name, response[:body]['name']
97
+ assert_equal(initial_cmd_stats_tube + 1, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be incremented')
98
+ end
99
+
100
+
101
+ should 'return BAD_FORMAT if tube name > 200 bytes' do
102
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
103
+ assert_raises Beaneater::BadFormatError do
104
+ client.transmit("stats-tube #{'x' * 201}")
105
+ end
106
+ # Get stats with other client because long tube name leaves client in weird state
107
+ assert_equal(initial_cmd_stats_tube, build_client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be unchanged')
108
+ end
109
+
110
+
111
+ should 'return BAD_FORMAT if line has a trailing space' do
112
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
113
+ assert_raises Beaneater::BadFormatError do
114
+ client.transmit("stats-tube #{tube_name} ")
115
+ end
116
+ assert_equal(initial_cmd_stats_tube, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be unchanged')
117
+ end
118
+
119
+
120
+ should 'return BAD_FORMAT if tube name includes invalid characters or starts with hyphen' do
121
+ initial_cmd_stats_tube = client.transmit('stats')[:body]['cmd-stats-tube']
122
+ valid_chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + %w[- + / ; . $ _ ( )] + [' ']
123
+ # Beanstalk hangs on char 13
124
+ bad_chars = (0..12).to_a.concat((14..255).to_a).to_a.map!(&:chr) - valid_chars
125
+
126
+ assert_raises(Beaneater::BadFormatError, 'Expected tube name starting with hyphen to be invalid') do
127
+ client.transmit('stats-tube -starts-with-hyphen')
128
+ end
129
+ assert_equal(initial_cmd_stats_tube, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be unchanged')
130
+
131
+ bad_chars.each do |bad_char|
132
+ assert_raises(Beaneater::BadFormatError, "Expected tube name with char #{bad_char} to be invalid") do
133
+ client.transmit("stats-tube name_with_#{bad_char}_in_it")
134
+ end
135
+ end
136
+ assert_equal(initial_cmd_stats_tube, client.transmit('stats')[:body]['cmd-stats-tube'], 'Expected cmd-stats-tube to be unchanged')
137
+ end
138
+
139
+ end
140
+
141
+ end
@@ -0,0 +1,88 @@
1
+ require 'test/unit'
2
+ require 'mocha/setup'
3
+ require 'minitest/autorun'
4
+ require 'minitest/should'
5
+
6
+ require 'securerandom'
7
+
8
+ require 'beaneater'
9
+
10
+
11
+ class BeanstalkIntegrationTest < MiniTest::Should::TestCase
12
+
13
+ class << self
14
+
15
+ def address(custom_address = '0.0.0.0')
16
+ return @address ||= custom_address
17
+ end
18
+
19
+ end
20
+
21
+ setup do
22
+ puts "#{self.class}::#{self.__name__}" if ENV['VERBOSE']
23
+ end
24
+
25
+ teardown do
26
+ cleanup_tubes
27
+ @clients.each do |client|
28
+ client.close unless client.connection.nil?
29
+ end
30
+ end
31
+
32
+ def address
33
+ return self.class.address
34
+ end
35
+
36
+ def build_client
37
+ new_client = Beaneater::Connection.new(address)
38
+ @clients << new_client
39
+ return new_client
40
+ end
41
+
42
+ def cleanup_tubes
43
+ @pool = Beaneater::Pool.new([address])
44
+ @tubes.each do |tube_name|
45
+ @pool.tubes.find(tube_name).clear
46
+ end
47
+ @pool.close
48
+ @tubes.clear
49
+ end
50
+
51
+ def client
52
+ @client ||= build_client
53
+ end
54
+
55
+ def create_buried_jobs(buried_count = 5)
56
+ job_ids = []
57
+ buried_count.times do
58
+ message = uuid
59
+ client.transmit("put 0 0 120 #{message.bytesize}\r\n#{message}")
60
+ timeout(1) do
61
+ job_ids << client.transmit('reserve')[:id]
62
+ end
63
+ client.transmit("bury #{job_ids.last} 0")
64
+ end
65
+ return job_ids
66
+ end
67
+
68
+ def initialize(*)
69
+ @tubes = []
70
+ @clients = []
71
+ super
72
+ end
73
+
74
+ def generate_tube_name
75
+ tube = uuid
76
+ @tubes << tube
77
+ return tube
78
+ end
79
+
80
+ def tube_name
81
+ return @tube_name ||= generate_tube_name
82
+ end
83
+
84
+ def uuid
85
+ SecureRandom.uuid
86
+ end
87
+
88
+ end