File: watcher.lua

package info (click to toggle)
asterisk-testsuite 0.0.0%2Bsvn.5781-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch
  • size: 18,632 kB
  • sloc: xml: 33,912; python: 32,904; ansic: 1,599; sh: 395; makefile: 170; sql: 17
file content (241 lines) | stat: -rw-r--r-- 4,387 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
module(..., package.seeall)

event = {}
function event.new(event)
	local e = ast.manager.message:new()
	e["Event"] = event
	return e
end


etree = {}
etree.__index = etree
function etree:new(expect)
	local e = {
		expect = expect,
		c = nil, -- children
		multi = {},
		received = nil,
	}

	setmetatable(e, self)
	return e
end

function etree:__tostring()
	return self:_print()
end

function etree:_print(prefix)
	local result = ""
	if not prefix then prefix = "" end

	if getmetatable(self.expect) == nil
	and type(self.expect) == 'table' then
		result = result .. prefix .. "{"
		for i, event in ipairs(self.expect) do
			if i == 1 then
				result = result .. event["Event"] 
			else
				result = result .. ", " .. event["Event"]
			end
		end

		result = result .. "}\n"
	else
		result = result .. prefix .. self.expect["Event"] .. "\n"
	end

	if self.c then
		for i, etree in ipairs(self.c) do
			result = result .. etree:_print(prefix .. "  ")
		end
	end

    return result
end

function etree:add(child)
	if getmetatable(child) ~= etree then
		child = etree:new(child)
	end

	if not self.c then
		self.c = {child}
	else
		table.insert(self.c, child)
	end
	return child
end

function etree:check_all(e)
	if getmetatable(self.expect) == nil
	and type(self.expect) == 'table' then
		local res = false
		for i, expect in ipairs(self.expect) do
			if not self.multi[i] and self:check(e, expect) then
				self.multi[i] = e
				res = true
				break
			end
		end

		self.received = self.multi
		for i, _ in ipairs(self.expect) do
			if not self.multi[i] then
				self.received = nil
			end
		end

		return res
	end

	if self:check(e, self.expect) then
		self.received = e
		return true
	end

	return false
end

function etree:check(e, expect)
	if type(expect) == 'function' then
		return expect(e)
	end

	if e["Event"] == expect["Event"] then
		local matched = true
		for i, h in ipairs(expect.headers) do
			local found = false
			for i, h2 in ipairs(e.headers) do
				if h[1] == h2[1] then
					if type(h[2]) == 'function' then
						local res = h[2](h2[2])
						if res then
							found = true
							break
						end
					elseif h[2] == h2[2] then
						found = true
						break
					end
				end
			end
			if not found then
				matched = false
				break
			end
		end
		return matched
	end

	return false
end

function etree:check_next(e)
	if not self.received then
		return self:check_all(e)
	end
	
	if self.c then
		for i, etree in ipairs(self.c) do
			if etree:check_next(e) then
				return true
			end
		end
	end

	return false
end

function etree:matched()
	-- if this node has not been matched, return false
	if not self.received then
		return false
	end

	-- if this node has been matched and has no children, return true
	if not self.c then
		return true
	end

	-- check if any of the children have been matched
	if self.c then
		for i, e in ipairs(self.c) do
			if e:matched() then
				return true
			end
		end
	end

	-- none of the children matched
	return false
end

--- Watch the given manager connection for the given events within the given
-- time period.
-- @returns True on success and nil and an error message on failure.  Currently
-- the only error message is "timeout".
function watch(m, tree, timeout)
	function tv2ms(tv)
		return tv.tv_sec * 1000 + tv.tv_usec / 1000
	end

	if getmetatable(tree) == watcher.etree then
		tree = {tree}
	end

	function matched()
		for i, e in ipairs(tree) do
			if not e:matched() then
				return false
			end
		end
		return true
	end

	function handle_events(event)
		for i, e in ipairs(tree) do
			if e:check_next(event) then
				break
			end
		end
	end

	local start, err = posix.gettimeofday()
	if not start then return nil, err end
	start = tv2ms(start)

	m:register_event("", handle_events)
	while not matched() do
		local now, err = posix.gettimeofday()
		if not now then
			m:unregister_event("", handle_events)
			return nil, err
		end
		now = tv2ms(now)

		if timeout ~= 0 and timeout < now - start then
			m:unregister_event("", handle_events)
			return nil, "timeout"
		end

		local res, err = m:pump_messages()
		if not res then
			m:unregister_event("", handle_events)
			error("error processing events: " .. err)
		end

		m:process_events()

		if timeout == 0 then
			m:unregister_event("", handle_events)
			return nil, "timeout"
		end

		posix.usleep(1)
	end

	m:unregister_event("", handle_events)
	return tree
end