waitutil 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZjhlODkyZTdjOTQwNjVjNTFmZGMzYjkwYjdkNWRjOWZlZWM1NzQ3Mw==
5
- data.tar.gz: !binary |-
6
- ZTc0Y2RlYTM5MjZmZjI2YjIxMmYzNDZmY2U4OGJmYzljOTljNzljZQ==
2
+ SHA1:
3
+ metadata.gz: 0f139cee6a8804a8beddc4adb4adfe9cf1c2e8d8
4
+ data.tar.gz: ef6a331a094e72d2b7b877a75d1cd38ff6962c1e
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NDhkZWMzZWE1MDEyMDYxYmNjNTZhMDBlNDIxYjkwOWU4ZWM4NjBiOWRiMWVj
10
- MjU2YjNmZWRlMjFjZGIxY2Y5YWRmMDhlZDQyY2ZmNmU1MDJlZmQxNDRkMDBk
11
- N2IyM2Y0N2JiNmYyYTBjYmNmNGUzYmJlZDY5OGEyNmE0ZTA5ZWE=
12
- data.tar.gz: !binary |-
13
- NDM4N2Q3YTMxZGEwNmIwMzdlZDViYWZkOWQ3ODM3ODk2NDM1ODIwNjRkYzRh
14
- NmFkMjIxODkyODQwNDlkOTYxNDgwZmI1MmM3YThhYjdhN2M3NzhhYTIxNDAw
15
- NjYyYjkzOGUyOWFkMWU2NmViMjI4ODQ2MjcyODc5ZGJmOGMyMzE=
6
+ metadata.gz: 2af4abd0f7f6f8b115cf6dd6058bb93496dbd686eba63530106d84c9a571420709339220c9e2857dca00f4af4b2a111b59ece159a4288ea46cd98cfcfd23ee9b
7
+ data.tar.gz: 2e437fd465f552294ad4698359d58e24c15d2970215a7e24224acd7f4512684cd7578654d1658ac909bc85ae65c941fc9a2d2efbdc67da317576dcf3324e68c3
data/.gitignore CHANGED
@@ -26,3 +26,5 @@ Gemfile.lock
26
26
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
27
27
  .rvmrc
28
28
 
29
+ /.idea
30
+ *.iml
@@ -4,4 +4,5 @@ rvm:
4
4
  - 2.0.0
5
5
  - 2.1.0
6
6
  - jruby-19mode # JRuby in 1.9 mode
7
- - rbx-2.1.1
7
+ # TODO: resolve issues and re-enable:
8
+ #- rbx-2.1.1
data/README.md CHANGED
@@ -1,33 +1,78 @@
1
1
  ## waitutil
2
2
 
3
- [![Build Status](https://travis-ci.org/mbautin/waitutil.png?branch=master)](https://travis-ci.org/mbautin/waitutil)
3
+ [![Build Status](https://travis-ci.org/rubytools/waitutil.png?branch=master)](https://travis-ci.org/rubytools/waitutil)
4
4
 
5
5
  `waitutil` provides tools for waiting for various conditions to occur, with a configurable
6
6
  delay time, timeout, and logging.
7
7
 
8
+ GitHub: https://github.com/rubytools/waitutil
9
+
10
+ RubyGems: http://rubygems.org/gems/waitutil
11
+
12
+ Documentation: http://rubytools.github.io/waitutil/
13
+
8
14
  ### Examples
9
15
 
16
+ Wait methods take a block that returns `true` or `false`.
17
+
10
18
  #### Waiting for conditions
11
19
 
12
20
  Maximum wait time is one minute by default, and the delay time is one second.
21
+
13
22
  ```ruby
14
23
  WaitUtil.wait_for_condition("my_event to happen") do
15
24
  check_if_my_event_happened
16
25
  end
17
26
  ```
18
27
 
19
- Customized wait time and delay time:
28
+ ##### Customized wait time and delay time
29
+
20
30
  ```ruby
21
31
  WaitUtil.wait_for_condition("my_event to happen", :timeout_sec => 30, :delay_sec => 0.5) do
22
32
  check_if_my_event_happened
23
33
  end
24
34
  ```
25
35
 
36
+ ##### Verbose logging
37
+
38
+ ```ruby
39
+ WaitUtil.wait_for_condition('my event', :verbose => true) { sleep(1) }
40
+ ```
41
+
42
+ Output:
43
+
44
+ ```
45
+ I, [2014-02-16T00:34:31.511915 #15897] INFO -- : Waiting for my event for up to 60 seconds
46
+ I, [2014-02-16T00:34:32.512223 #15897] INFO -- : Success waiting for my event (1.000153273 seconds)
47
+ ```
48
+
49
+ ##### Returning additional information for the timeout log message
50
+
51
+ ```ruby
52
+ attempt = 1
53
+ WaitUtil.wait_for_condition('my event', :verbose => true, :timeout_sec => 3, :delay_sec => 1) do
54
+ sleep(1)
55
+ attempt += 1
56
+ [false, "attempt #{attempt}"] # the second element goes into the log message
57
+ end
58
+ ```
59
+
60
+ Output:
61
+
62
+ ```
63
+ I, [2014-02-16T00:46:53.647936 #17252] INFO -- : Waiting for my event for up to 3 seconds
64
+ WaitUtil::TimeoutError: Timed out waiting for my event (3 seconds elapsed): attempt 3
65
+ from /home/mbautin/.rvm/gems/ruby-2.1.0/gems/waitutil-0.1.0/lib/waitutil.rb:39:in `wait_for_condition'
66
+ from (irb):9
67
+ from /home/mbautin/.rvm/rubies/ruby-2.1.0/bin/irb:11:in `<main>'
68
+ ```
69
+
26
70
  #### Waiting for service availability
27
71
 
28
- Wait for a TCP server to be available:
72
+ Wait for a TCP server to be available using [wait_for_service](http://rubytools.github.io/waitutil/WaitUtil.html#wait_for_service-instance_method):
73
+
29
74
  ```ruby
30
- WaitUtil.wait_for_service('example.com', 8080)
75
+ WaitUtil.wait_for_service('my service', 'example.com', 80)
31
76
  ```
32
77
 
33
78
  ### License
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -1,4 +1,5 @@
1
1
  require 'logger'
2
+ require 'socket'
2
3
 
3
4
  module WaitUtil
4
5
 
@@ -33,32 +34,43 @@ module WaitUtil
33
34
  end
34
35
 
35
36
  start_time = Time.now
37
+ stop_time = start_time + timeout_sec
36
38
  iteration = 0
39
+
40
+ # Time when we started to evaluate the condition.
41
+ condition_eval_start_time = start_time
42
+
37
43
  until is_condition_met(condition_result = yield(iteration))
38
- if Time.now - start_time >= timeout_sec
44
+ current_time = Time.now
45
+ if current_time - start_time >= timeout_sec
39
46
  raise TimeoutError.new(
40
47
  "Timed out waiting for #{description} (#{timeout_sec} seconds elapsed)" +
41
48
  get_additional_message(condition_result)
42
49
  )
43
50
  end
44
- sleep(delay_sec)
51
+
52
+ # The condition evaluation function might have taken some time, so we subtract that time
53
+ # from the time we have to wait.
54
+ sleep_time_sec = condition_eval_start_time + delay_sec - current_time
55
+ sleep(sleep_time_sec) if sleep_time_sec > 0
56
+
45
57
  iteration += 1
58
+ condition_eval_start_time = Time.now # we will evaluate the condition again immediately
46
59
  end
60
+
47
61
  if verbose
48
62
  @@logger.info("Success waiting for #{description} (#{Time.now - start_time} seconds)")
49
63
  end
50
64
  true
51
65
  end
52
66
 
53
- # Wait until a service is available at the given host/port.
67
+ # Wait until a TCP service is available at the given host/port.
54
68
  def wait_for_service(description, host, port, options = {})
55
- wait_for_condition("#{description} port #{port} to become available on #{host}",
69
+ wait_for_condition("#{description} to become available on #{host}, port #{port}",
56
70
  options) do
57
71
  begin
58
- s = TCPSocket.new(host, port)
59
- s.close
60
- true
61
- rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
72
+ is_tcp_port_open(host, port, options[:delay_sec] || DEFAULT_DELAY_SEC)
73
+ rescue SocketError
62
74
  false
63
75
  end
64
76
  end
@@ -74,5 +86,56 @@ module WaitUtil
74
86
  condition_result.kind_of?(Array) ? ': ' + condition_result[1] : ''
75
87
  end
76
88
 
89
+ # Check if the given TCP port is open on the given port with a timeout.
90
+ def is_tcp_port_open(host, port, timeout_sec = nil)
91
+ if RUBY_PLATFORM == 'java'
92
+ # Unfortunately, our select-based approach does not work on JRuby.
93
+ begin
94
+ s = TCPSocket.new(host, port)
95
+ s.close
96
+ true
97
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
98
+ false
99
+ end
100
+ else
101
+ addr_info = begin
102
+ Socket.getaddrinfo(host, port)
103
+ rescue SocketError
104
+ return false
105
+ end.select {|item| item[0] == 'AF_INET' }
106
+
107
+ return false if addr_info.empty?
108
+
109
+ socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
110
+ ip_addr = addr_info[0][3]
111
+ sockaddr = Socket.sockaddr_in(port, ip_addr)
112
+ result = begin
113
+ begin
114
+ socket.connect_nonblock(sockaddr)
115
+ true
116
+ rescue Errno::EAFNOSUPPORT
117
+ @@logger.error("Address family not supported for #{ip_addr}")
118
+ false
119
+ end
120
+ rescue Errno::EINPROGRESS
121
+ reader, writer, error = IO.select([socket], [socket], [socket], timeout_sec)
122
+ if writer.nil? || writer.empty?
123
+ false
124
+ else
125
+ # Sometimes we have to write some data to the socket to find out whether we are really
126
+ # connected.
127
+ begin
128
+ writer[0].write_nonblock("\x0")
129
+ true
130
+ rescue Errno::ECONNREFUSED
131
+ false
132
+ end
133
+ end
134
+ end
135
+ socket.close
136
+ result
137
+ end
138
+ end
139
+
77
140
  extend WaitUtil
78
141
  end
@@ -83,13 +83,55 @@ describe WaitUtil do
83
83
  describe '.wait_for_service' do
84
84
  BIND_IP = '127.0.0.1'
85
85
 
86
+ it 'waits for service availability' do
87
+ WaitUtil.wait_for_service('Google', 'google.com', 80, :timeout_sec => 0.5)
88
+ end
89
+
90
+ it 'times out when host name does not exist' do
91
+ begin
92
+ WaitUtil.wait_for_service(
93
+ 'non-existent service',
94
+ 'nosuchhost_waitutil_ruby_module.com',
95
+ 12345,
96
+ :timeout_sec => 0.2,
97
+ :delay_sec => 0.1
98
+ )
99
+ fail("Expecting WaitUtil::TimeoutError but nothing was raised")
100
+ rescue WaitUtil::TimeoutError => ex
101
+ expect(ex.to_s.gsub(/ \(.*/, '')).to eq(
102
+ 'Timed out waiting for non-existent service to become available on ' \
103
+ 'nosuchhost_waitutil_ruby_module.com, port 12345'
104
+ )
105
+ end
106
+ end
107
+
108
+ if RUBY_PLATFORM != 'java'
109
+ # Our current implementation will get stuck on this if running JRuby.
110
+ it 'times out when port is closed' do
111
+ begin
112
+ WaitUtil.wait_for_service(
113
+ 'wrong port on Google',
114
+ 'google.com',
115
+ 12345,
116
+ :timeout_sec => 0.2,
117
+ :delay_sec => 0.1
118
+ )
119
+ rescue WaitUtil::TimeoutError => ex
120
+ expect(ex.to_s.gsub(/ \(.*/, '')).to eq(
121
+ 'Timed out waiting for wrong port on Google to become available on google.com, ' \
122
+ 'port 12345'
123
+ )
124
+ end
125
+ end
126
+ end
127
+
86
128
  it 'should succeed immediately when there is a TCP server listening' do
87
129
  # Find an unused port.
88
130
  socket = Socket.new(:INET, :STREAM, 0)
89
131
  sockaddr = if RUBY_ENGINE == 'jruby'
90
- ServerSocket.pack_sockaddr_in(12345, "127.0.0.1")
132
+ ServerSocket.pack_sockaddr_in(0, "127.0.0.1")
91
133
  else
92
- Addrinfo.tcp(BIND_IP, 0)
134
+ Socket.pack_sockaddr_in(0, "127.0.0.1")
93
135
  end
94
136
  socket.bind(sockaddr)
95
137
  port = socket.local_address.ip_port
@@ -130,6 +172,6 @@ describe WaitUtil do
130
172
  )
131
173
  }.to raise_error(WaitUtil::TimeoutError)
132
174
  end
133
-
134
175
  end
176
+
135
177
  end
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
  gem.email = ['mbautin@gmail.com']
9
9
  gem.description = 'Utilities for waiting for various conditions'
10
10
  gem.summary = 'Utilities for waiting for various conditions'
11
- gem.homepage = "http://github.com/mbautin/#{GEM_NAME}"
11
+ gem.homepage = "http://github.com/rubytools/#{GEM_NAME}"
12
12
 
13
13
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
14
14
  gem.files = `git ls-files`.split("\n").map(&:strip)
metadata CHANGED
@@ -1,71 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waitutil
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikhail Bautin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-15 00:00:00.000000000 Z
11
+ date: 2014-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
- requirement: !ruby/object:Gem::Requirement
15
+ version_requirements: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '10.1'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
20
+ requirement: !ruby/object:Gem::Requirement
23
21
  requirements:
24
22
  - - ~>
25
23
  - !ruby/object:Gem::Version
26
24
  version: '10.1'
25
+ prerelease: false
26
+ type: :development
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
- requirement: !ruby/object:Gem::Requirement
29
+ version_requirements: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '2.14'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
34
+ requirement: !ruby/object:Gem::Requirement
37
35
  requirements:
38
36
  - - ~>
39
37
  - !ruby/object:Gem::Version
40
38
  version: '2.14'
39
+ prerelease: false
40
+ type: :development
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rubygems-tasks
43
- requirement: !ruby/object:Gem::Requirement
43
+ version_requirements: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0.2'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
51
49
  requirements:
52
50
  - - ~>
53
51
  - !ruby/object:Gem::Version
54
52
  version: '0.2'
53
+ prerelease: false
54
+ type: :development
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: webrick
57
- requirement: !ruby/object:Gem::Requirement
57
+ version_requirements: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
62
+ requirement: !ruby/object:Gem::Requirement
65
63
  requirements:
66
- - - ! '>='
64
+ - - '>='
67
65
  - !ruby/object:Gem::Version
68
66
  version: '0'
67
+ prerelease: false
68
+ type: :development
69
69
  description: Utilities for waiting for various conditions
70
70
  email:
71
71
  - mbautin@gmail.com
@@ -85,29 +85,27 @@ files:
85
85
  - spec/Rakefile
86
86
  - spec/waitutil_spec.rb
87
87
  - waitutil.gemspec
88
- homepage: http://github.com/mbautin/waitutil
88
+ homepage: http://github.com/rubytools/waitutil
89
89
  licenses: []
90
90
  metadata: {}
91
- post_install_message:
91
+ post_install_message:
92
92
  rdoc_options: []
93
93
  require_paths:
94
94
  - lib
95
95
  required_ruby_version: !ruby/object:Gem::Requirement
96
96
  requirements:
97
- - - ! '>='
97
+ - - '>='
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ! '>='
102
+ - - '>='
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubyforge_project:
107
- rubygems_version: 2.1.11
108
- signing_key:
106
+ rubyforge_project:
107
+ rubygems_version: 2.2.2
108
+ signing_key:
109
109
  specification_version: 4
110
110
  summary: Utilities for waiting for various conditions
111
- test_files:
112
- - spec/Rakefile
113
- - spec/waitutil_spec.rb
111
+ test_files: []