Skip to content

Commit ed0458f

Browse files
committed
Improve controller test robustness.
1 parent a6db20e commit ed0458f

4 files changed

Lines changed: 60 additions & 68 deletions

File tree

fixtures/async/container/controllers.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,39 @@ def self.path_for(controller)
1212
File.join(ROOT, "#{controller}.rb")
1313
end
1414
end
15+
16+
AController = Sus::Shared("a controller") do |controller|
17+
let(:controller_path) {Async::Container::Controllers.path_for(controller)}
18+
19+
let(:pipe) {IO.pipe}
20+
let(:input) {pipe.first}
21+
let(:output) {pipe.last}
22+
23+
let(:server) {Async::Container::Notify::Server.open}
24+
let(:notify_socket) {server.path}
25+
26+
let(:process_id) {@process_id}
27+
28+
before do
29+
environment = ENV.to_h.merge({"NOTIFY_SOCKET" => notify_socket})
30+
@notify = server.bind
31+
32+
@process_id = Process.spawn(environment, "bundle", "exec", controller_path, out: output)
33+
output.close
34+
end
35+
36+
after do
37+
if @process_id
38+
Process.kill(:TERM, @process_id)
39+
Process.wait(@process_id)
40+
end
41+
42+
@notify&.close
43+
end
44+
45+
def wait_until_ready
46+
@notify.wait_until_ready
47+
end
48+
end
1549
end
1650
end

fixtures/async/container/controllers/graceful.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class Graceful < Async::Container::Controller
1212
def setup(container)
1313
container.run(name: "graceful", count: 1, restart: true) do |instance|
1414
instance.ready!
15+
1516
$stdout.puts "Ready..."
1617

1718
sleep

lib/async/container/notify/server.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ def receive
129129
end
130130
end
131131
end
132+
133+
def wait_until_ready
134+
while message = receive
135+
if message[:ready] == true
136+
return
137+
end
138+
end
139+
end
132140
end
133141
end
134142
end

test/async/container/controller.rb

Lines changed: 17 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
require "async/container/controller"
77
require "async/container/controllers"
8+
require "async/container/notify/server"
89

910
describe Async::Container::Controller do
1011
let(:controller) {subject.new}
@@ -98,97 +99,41 @@ def controller.setup(container)
9899
end
99100

100101
with "graceful controller" do
101-
let(:controller_path) {Async::Container::Controllers.path_for("graceful")}
102-
103-
let(:pipe) {IO.pipe}
104-
let(:input) {pipe.first}
105-
let(:output) {pipe.last}
106-
107-
let(:pid) {@pid}
108-
109-
def before
110-
@pid = Process.spawn("bundle", "exec", controller_path, out: output)
111-
output.close
112-
113-
super
114-
end
115-
116-
def after(error = nil)
117-
Process.kill(:TERM, @pid)
118-
Process.wait(@pid)
119-
120-
super
121-
end
102+
include_context Async::Container::AController, "graceful"
122103

123104
it "has graceful shutdown" do
124105
expect(input.gets).to be == "Ready...\n"
125106

126-
Process.kill(:INT, @pid)
107+
wait_until_ready
108+
109+
Process.kill(:INT, process_id)
127110

128111
expect(input.gets).to be == "Exiting...\n"
129112
end
130113
end
131114

132115
with "bad controller" do
133-
let(:controller_path) {Async::Container::Controllers.path_for("bad")}
134-
135-
let(:pipe) {IO.pipe}
136-
let(:input) {pipe.first}
137-
let(:output) {pipe.last}
138-
139-
let(:pid) {@pid}
140-
141-
def before
142-
@pid = Process.spawn("bundle", "exec", controller_path, out: output)
143-
output.close
144-
145-
super
146-
end
147-
148-
def after(error = nil)
149-
Process.kill(:TERM, @pid)
150-
Process.wait(@pid)
151-
152-
super
153-
end
116+
include_context Async::Container::AController, "bad"
154117

155118
it "fails to start" do
156119
expect(input.gets).to be == "Ready...\n"
157120

158-
Process.kill(:INT, @pid)
121+
Process.kill(:INT, process_id)
159122

160123
# It was killed:
161124
expect(input.gets).to be_nil
162125
end
163126
end
164127

165128
with "signals" do
166-
let(:controller_path) {Async::Container::Controllers.path_for("dots")}
167-
168-
let(:pipe) {IO.pipe}
169-
let(:input) {pipe.first}
170-
let(:output) {pipe.last}
171-
172-
let(:pid) {@pid}
173-
174-
def before
175-
@pid = Process.spawn("bundle", "exec", controller_path, out: output)
176-
output.close
177-
178-
super
179-
end
180-
181-
def after(error = nil)
182-
Process.kill(:TERM, @pid)
183-
Process.wait(@pid)
184-
185-
super
186-
end
129+
include_context Async::Container::AController, "dots"
187130

188131
it "restarts children when receiving SIGHUP" do
189132
expect(input.read(1)).to be == "."
190133

191-
Process.kill(:HUP, pid)
134+
wait_until_ready
135+
136+
Process.kill(:HUP, process_id)
192137

193138
# The ordering between the old child writing "I" and the new child writing "." is timing-dependent (blue-green restart starts the new container before stopping the old one). Accept either order.
194139
expect(input.read(2)).to (be == "I.").or(be == ".I")
@@ -197,15 +142,19 @@ def after(error = nil)
197142
it "exits gracefully when receiving SIGINT" do
198143
expect(input.read(1)).to be == "."
199144

200-
Process.kill(:INT, pid)
145+
wait_until_ready
146+
147+
Process.kill(:INT, process_id)
201148

202149
expect(input.read).to be == "I"
203150
end
204151

205152
it "exits gracefully when receiving SIGTERM" do
206153
expect(input.read(1)).to be == "."
207154

208-
Process.kill(:TERM, pid)
155+
wait_until_ready
156+
157+
Process.kill(:TERM, process_id)
209158

210159
# SIGTERM now behaves like SIGINT (graceful)
211160
expect(input.read).to be == "I"

0 commit comments

Comments
 (0)