1function mcp_config_pools(oldss)
2    local srv = mcp.backend
3    mcp.backend_read_timeout(0.5)
4    mcp.backend_connect_timeout(5)
5    mcp.backend_retry_timeout(5)
6
7    -- Single backend for zones to ease testing.
8    -- For purposes of this config the proxy is always "zone 1" (z1)
9    local b1 = srv('b1', '127.0.0.1', 11411)
10    local b2 = srv('b2', '127.0.0.1', 11412)
11    local b3 = srv('b3', '127.0.0.1', 11413)
12
13    local b1z = {b1}
14    local b2z = {b2}
15    local b3z = {b3}
16
17    local dead = srv('dead', '127.9.9.9', 11011);
18
19    local no_label = srv('', '127.0.0.1', 11414)
20
21    -- convert the backends to pools.
22    -- as per a normal full config see simple.lua or t/startfile.lua
23    local zones = {
24        z1 = mcp.pool(b1z),
25        z2 = mcp.pool(b2z),
26        z3 = mcp.pool(b3z),
27        dead = mcp.pool({dead}),
28        no_label = mcp.pool({no_label})
29    }
30
31    return zones
32end
33
34-- WORKER CODE:
35function new_basic(zones, func)
36    local fgen = mcp.funcgen_new()
37    local o = { t = {}, c = 0 }
38
39    o.t.z1 = fgen:new_handle(zones.z1)
40    o.t.z2 = fgen:new_handle(zones.z2)
41    o.t.z3 = fgen:new_handle(zones.z3)
42    o.t.dead = fgen:new_handle(zones.dead)
43    o.t.no_label = fgen:new_handle(zones.no_label)
44
45    fgen:ready({ f = func, a = o})
46    return fgen
47end
48
49-- Do specialized testing based on the key prefix.
50function mcp_config_routes(zones)
51    local map = {}
52
53    map.b = new_basic(zones, function(rctx, a)
54        return function(r)
55            return rctx:enqueue_and_wait(r, a.t.z1)
56        end
57    end)
58
59    map.errcheck = new_basic(zones, function(rctx, a)
60        return function(r)
61            local res = rctx:enqueue_and_wait(r, a.t.z1)
62            -- expect an error
63            if res:ok() then
64                return "FAIL\r\n"
65            end
66            if res:code() == mcp.MCMC_CODE_ERROR then
67                return "ERROR\r\n"
68            elseif res:code() == mcp.MCMC_CODE_CLIENT_ERROR then
69                return "CLIENT_ERROR\r\n"
70            elseif res:code() == mcp.MCMC_CODE_SERVER_ERROR then
71                return "SERVER_ERROR\r\n"
72            end
73            return "FAIL"
74        end
75    end)
76
77    -- show that we fetched the key by generating our own response string.
78    map.getkey = new_basic(zones, function(rctx, a)
79        return function(r)
80            return "VALUE |" .. r:key() .. " 0 2\r\nts\r\nEND\r\n"
81        end
82    end)
83
84    map.rtrimkey = new_basic(zones, function(rctx, a)
85        return function(r)
86            r:rtrimkey(4)
87            return rctx:enqueue_and_wait(r, a.t.z1)
88        end
89    end)
90
91    map.ltrimkey = new_basic(zones, function(rctx, a)
92        return function(r)
93            r:ltrimkey(10)
94            return rctx:enqueue_and_wait(r, a.t.z1)
95        end
96    end)
97
98    map.nolabel = new_basic(zones, function(rctx, a)
99        return function(r)
100            return rctx:enqueue_and_wait(r, a.t.no_label)
101        end
102    end)
103
104    map.ntokens = new_basic(zones, function(rctx, a)
105        return function(r)
106            return "VA 1 C123 v\r\n" .. r:ntokens() .. "\r\n"
107        end
108    end)
109
110    map.hasflag = {
111        [mcp.CMD_MG] = new_basic(zones, function(rctx, a)
112            return function(r)
113                if r:has_flag("c") then
114                    return "HD C123\r\n"
115                elseif r:has_flag("O") then
116                    return "HD Oabc\r\n"
117                end
118                return "NF\r\n"
119            end
120        end),
121        [mcp.CMD_GET] = new_basic(zones, function(rctx, a)
122            return function(r)
123                if r:has_flag("F") then
124                    return "ERROR flag found\r\n"
125                end
126                return "END\r\n"
127            end
128        end)
129    }
130
131    -- Input flags: N10 k c R10
132    -- Output flags: N100 k R100
133    map.flagtoken = new_basic(zones, function(rctx, a)
134        return function(r)
135            -- flag_token on non-existing flags: no effect
136            local Ttoken = r:flag_token("T", "T100")
137            local Otoken = r:flag_token("O", nil)
138            local vtoken = r:flag_token("v", "")
139            if vtoken or Otoken or Ttoken then
140                return "ERROR found non-existing flag.\r\n"
141            end
142
143            -- flag_token to replace: N10 -> N100
144            local found, Ntoken = r:flag_token("N", "N100")
145            if not found or Ntoken ~= "10" then
146                return "ERROR unexpected N token.\r\n"
147            end
148
149            -- flag_token with nil 2nd arg: equvalent to fetch
150            r:flag_token("k", nil)
151            if not r:has_flag("k") then
152                return "ERROR unexpected k token.\r\n"
153            end
154
155            -- flag_token with self 2nd arg: no effect
156            r:flag_token("c", "c")
157            if not r:has_flag("c") then
158                return "ERROR unexpected c token 1.\r\n"
159            end
160
161            -- flag_token with "" 2nd arg: remove
162            r:flag_token("c", "")
163            if r:has_flag("c") then
164                return "ERROR unexpected c token 2.\r\n"
165            end
166
167            -- repeated flag_token calls: new value is returned.
168            local _, Rtoken = r:flag_token("R", "R100")
169            if Rtoken ~= '10' then
170                return "ERROR unexpected R token 1.\r\n"
171            end
172            _, Rtoken = r:flag_token("R", "R100")
173            if Rtoken ~= '100' then
174                return "ERROR unexpected R token 2.\r\n"
175            end
176
177            return "HD\r\n"
178        end
179    end)
180
181    map.request = {
182        [mcp.CMD_MS] = new_basic(zones, function(rctx, a)
183            return function(r)
184                local key = r:key()
185                local newReq = mcp.request("ms /request/edit 2\r\n", "ab\r\n")
186                return rctx:enqueue_and_wait(newReq, a.t.z1)
187            end
188        end),
189        [mcp.CMD_MG] = new_basic(zones, function(rctx, a)
190            return function(r)
191                local key = r:key()
192                if key == "/request/old" then
193                    local newReq = mcp.request("mg /request/new c\r\n")
194                    return rctx:enqueue_and_wait(newReq, a.t.z1)
195                else
196                    local res = rctx:enqueue_and_wait(r, a.t.z1)
197                    local newReq = mcp.request("ms /request/a " .. res:vlen() .. "\r\n", res)
198                    return rctx:enqueue_and_wait(newReq, a.t.z2)
199                end
200            end
201        end)
202    }
203
204    map.response = {
205        [mcp.CMD_GET] = new_basic(zones, function(rctx, a)
206            return function(r)
207                local res = rctx:enqueue_and_wait(r, a.t.z1)
208                local key = r:key()
209                if key == "/response/hit" then
210                    local hit = res:hit()
211                    if hit then
212                        return res
213                    end
214                    return "ERROR hit is false\r\n"
215                elseif key == "/response/not_hit" then
216                    local hit = res:hit()
217                    if not hit then
218                        return "SERVER_ERROR\r\n"
219                    end
220                    return res
221                end
222                return "ERROR unhandled key\r\n"
223
224            end
225        end),
226        [mcp.CMD_MG] = new_basic(zones, function(rctx, a)
227            return function(r)
228                local res = rctx:enqueue_and_wait(r, a.t.z1)
229                local key = r:key()
230                if key == "/response/elapsed" then
231                    local elapsed = res:elapsed()
232                    if elapsed > 100000 then
233                        return res
234                    end
235                    return "ERROR elapsed is invalid.\r\n"
236                elseif key == "/response/ok" then
237                    local ok = res:ok()
238                    if ok then
239                        return res
240                    end
241                    return "ERROR ok is false\r\n"
242                elseif key == "/response/not_ok" then
243                    local ok = res:ok()
244                    if not ok then
245                        return "SERVER_ERROR\r\n"
246                    end
247                    return "HD\r\n"
248                elseif key == "/response/hit" then
249                    local hit = res:hit()
250                    if hit then
251                        return res
252                    end
253                    return "ERROR hit is false\r\n"
254                elseif key == "/response/not_hit" then
255                    local hit = res:hit()
256                    if not hit then
257                        return "SERVER_ERROR\r\n"
258                    end
259                    return "HD\r\n"
260                elseif key == "/response/vlen" then
261                    local vlen = res:vlen()
262                    if vlen == 1 then
263                        return res
264                    end
265                    return "ERROR vlen is not 1\r\n"
266                elseif key == "/response/code_ok" then
267                    local code = res:code()
268                    if code == mcp.MCMC_CODE_OK then
269                        return res
270                    end
271                    return "ERROR expect MCMC_CODE_OK, but got " .. code .. "\r\n"
272                elseif key == "/response/code_miss" then
273                    local code = res:code()
274                    if code == mcp.MCMC_CODE_END then
275                        return res
276                    end
277                    return "ERROR expect MCMC_CODE_END, but got " .. code .. "\r\n"
278                elseif key == "/response/line" then
279                    local line = res:line()
280                    if line == "v c123" then
281                        return res
282                    end
283                    return "ERROR unexpected line, got [" .. line .. "]\r\n"
284                elseif key == "/response/blank" then
285                    res:flag_blank("O")
286                    return res
287                end
288                return "ERROR unhandled key\r\n"
289
290            end
291        end),
292        [mcp.CMD_MS] = new_basic(zones, function(rctx, a)
293            return function(r)
294                local key = r:key()
295                local res = rctx:enqueue_and_wait(r, a.t.z1)
296                local code = res:code()
297
298                if key == "/response/code_ok" then
299                    if code == mcp.MCMC_CODE_OK then
300                        return res
301                    end
302                    return "ERROR expect MCMC_CODE_OK, but got " .. code .. "\r\n"
303                elseif key == "/response/line" then
304                    local line = res:line()
305                    if line == "O123 C123" then
306                        return res
307                    end
308                    return "ERROR unexpected line, got [" .. line .. "]\r\n"
309                end
310                return "ERROR unhandled key\r\n"
311            end
312        end),
313        [mcp.CMD_SET] = new_basic(zones, function(rctx, a)
314            return function(r)
315                local res = rctx:enqueue_and_wait(r, a.t.z1)
316                local key = r:key()
317                if key == "/response/code_stored" then
318                    local code = res:code()
319                    if code == mcp.MCMC_CODE_STORED then
320                        return res
321                    end
322                    return "ERROR expect MCMC_CODE_STORED, but got " .. code .. "\r\n"
323                elseif key == "/response/code_exists" then
324                    local code = res:code()
325                    if code == mcp.MCMC_CODE_EXISTS then
326                        return res
327                    end
328                    return "ERROR expect MCMC_CODE_EXISTS, but got " .. code .. "\r\n"
329                elseif key == "/response/code_not_stored" then
330                    local code = res:code()
331                    if code == mcp.MCMC_CODE_NOT_STORED then
332                        return res
333                    end
334                    return "ERROR expect MCMC_CODE_NOT_STORED, but got " .. code .. "\r\n"
335                elseif key == "/response/code_not_found" then
336                    local code = res:code()
337                    if code == mcp.MCMC_CODE_NOT_FOUND then
338                        return res
339                    end
340                    return "ERROR expect MCMC_CODE_NOT_FOUND, but got " .. code .. "\r\n"
341                end
342                return "ERROR unhandled key\r\n"
343            end
344        end),
345        [mcp.CMD_TOUCH] = new_basic(zones, function(rctx, a)
346            return function(r)
347                local res = rctx:enqueue_and_wait(r, a.t.z1)
348                local key = r:key()
349                local code = res:code()
350                if code == mcp.MCMC_CODE_TOUCHED then
351                    return res
352                end
353                return "ERROR expect MCMC_CODE_TOUCHED, but got " .. code .. "\r\n"
354            end
355        end),
356        [mcp.CMD_DELETE] = new_basic(zones, function(rctx, a)
357            return function(r)
358                local res = rctx:enqueue_and_wait(r, a.t.z1)
359                local key = r:key()
360                local code = res:code()
361                if code == mcp.MCMC_CODE_DELETED then
362                    return res
363                end
364                return "ERROR expect MCMC_CODE_DELETED, but got " .. code .. "\r\n"
365            end
366        end),
367    }
368
369    map.token = new_basic(zones, function(rctx, a)
370        return function(r)
371            local key = r:key()
372            if key == "/token/replacement" then
373                r:token(4, "C456")
374            elseif key == "/token/removal" then
375                r:token(4, "")
376            else
377                local token = r:token(2)
378                r:flag_token("P", "P" .. token)
379            end
380            return rctx:enqueue_and_wait(r, a.t.z1)
381        end
382    end)
383
384    map.zonetest = new_basic(zones, function(rctx, a)
385        return function(r)
386            local key = r:key()
387            if key == "/zonetest/a" then
388                return rctx:enqueue_and_wait(r, a.t.z1)
389            elseif key == "/zonetest/b" then
390                return rctx:enqueue_and_wait(r, a.t.z2)
391            elseif key == "/zonetest/c" then
392                return rctx:enqueue_and_wait(r, a.t.z3)
393            else
394                return "END\r\n"
395            end
396        end
397    end)
398
399    map.logtest = new_basic(zones, function(rctx, a)
400        return function(r)
401            mcp.log("testing manual log messages")
402            return "END\r\n"
403        end
404    end)
405
406    map.logreqtest = new_basic(zones, function(rctx, a)
407        return function(r)
408            local res = rctx:enqueue_and_wait(r, a.t.z1)
409            mcp.log_req(r, res, "logreqtest")
410            return res
411        end
412    end)
413
414    map.logreqstest = new_basic(zones, function(rctx, a)
415        return function(r)
416            local res = rctx:enqueue_and_wait(r, a.t.z1)
417            mcp.log_reqsample(150, 0, true, r, res, "logsampletest")
418            return res
419        end
420    end)
421
422    map.sanity = new_basic(zones, function(rctx, a)
423        local z = {a.t.z1, a.t.z2, a.t.z3}
424        return function(r)
425            rctx:enqueue(r, z)
426            rctx:wait_cond(3)
427            return rctx:result(a.t.z3)
428        end
429    end)
430
431    map.dead = new_basic(zones, function(rctx, a)
432        return function(r)
433            return rctx:enqueue_and_wait(r, a.t.dead)
434        end
435    end)
436
437    map.deadrespcode = new_basic(zones, function(rctx, a)
438        return function(r)
439            local res = rctx:enqueue_and_wait(r, a.t.dead)
440            if res:code() == mcp.MCMC_CODE_SERVER_ERROR then
441             return "ERROR code_correct\r\n"
442            end
443            return "ERROR code_incorrect: " .. res:code() .. "\r\n"
444        end
445    end)
446
447    map.millis = new_basic(zones, function(rctx, a)
448        return function(r)
449            local time = mcp.time_real_millis()
450            return "HD t" .. time .. "\r\n"
451        end
452    end)
453
454    local def_fg = mcp.funcgen_new()
455    def_fg:ready({
456        f = function(rctx)
457            return function(r)
458                return "SERVER_ERROR no set route\r\n"
459            end
460        end
461    })
462
463    mcp.attach(mcp.CMD_ANY_STORAGE, mcp.router_new({
464    map = map, mode = "anchor", start = "/", stop = "/", default = def_fg
465    }))
466end
467