waitutil 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []