Software /
code /
prosody
File
spec/util_promise_spec.lua @ 11942:b4f77a7bf8ab
mod_http_openmetrics: Serve HTTP from global context
Makes GET /metrics work regardless of the value of the Host header.
This was not possible before 220468f7a103 which added the ability to
have global HTTP modules, which was partly why the per-host part was
kept while the module lived among the community modules.
Another reason was to provide some semblance of security by obscurity by
only loading the module on e.g. a 'localhost' VirtualHost or Component.
The new IP limits obsoletes this.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 25 Nov 2021 16:57:01 +0100 |
parent | 11727:f3aee8a825cc |
child | 11947:073e53b72792 |
line wrap: on
line source
local promise = require "util.promise"; describe("util.promise", function () --luacheck: ignore 212/resolve 212/reject describe("new()", function () it("returns a promise object", function () assert(promise.new()); end); end); it("notifies immediately for fulfilled promises", function () local p = promise.new(function (resolve) resolve("foo"); end); local cb = spy.new(function (v) assert.equal("foo", v); end); p:next(cb); assert.spy(cb).was_called(1); end); it("notifies on fulfillment of pending promises", function () local r; local p = promise.new(function (resolve) r = resolve; end); local cb = spy.new(function (v) assert.equal("foo", v); end); p:next(cb); assert.spy(cb).was_called(0); r("foo"); assert.spy(cb).was_called(1); end); it("allows chaining :next() calls", function () local r; local result; local p = promise.new(function (resolve) r = resolve; end); local cb1 = spy.new(function (v) assert.equal("foo", v); return "bar"; end); local cb2 = spy.new(function (v) assert.equal("bar", v); result = v; end); p:next(cb1):next(cb2); assert.spy(cb1).was_called(0); assert.spy(cb2).was_called(0); r("foo"); assert.spy(cb1).was_called(1); assert.spy(cb2).was_called(1); assert.equal("bar", result); end); it("supports multiple :next() calls on the same promise", function () local r; local result; local p = promise.new(function (resolve) r = resolve; end); local cb1 = spy.new(function (v) assert.equal("foo", v); result = v; end); local cb2 = spy.new(function (v) assert.equal("foo", v); result = v; end); p:next(cb1); p:next(cb2); assert.spy(cb1).was_called(0); assert.spy(cb2).was_called(0); r("foo"); assert.spy(cb1).was_called(1); assert.spy(cb2).was_called(1); assert.equal("foo", result); end); it("automatically rejects on error", function () local r; local p = promise.new(function (resolve) r = resolve; error("oh no"); end); local cb = spy.new(function () end); local err_cb = spy.new(function (v) assert.equal("oh no", v); end); p:next(cb, err_cb); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(1); r("foo"); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(1); end); it("supports reject()", function () local r, result; local p = promise.new(function (resolve, reject) r = reject; end); local cb = spy.new(function () end); local err_cb = spy.new(function (v) result = v; assert.equal("oh doh", v); end); p:next(cb, err_cb); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(0); r("oh doh"); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(1); assert.equal("oh doh", result); end); it("supports chaining of rejected promises", function () local r, result; local p = promise.new(function (resolve, reject) r = reject; end); local cb = spy.new(function () end); local err_cb = spy.new(function (v) result = v; assert.equal("oh doh", v); return "ok" end); local cb2 = spy.new(function (v) result = v; end); local err_cb2 = spy.new(function () end); p:next(cb, err_cb):next(cb2, err_cb2) assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(0); assert.spy(cb2).was_called(0); assert.spy(err_cb2).was_called(0); r("oh doh"); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(1); assert.spy(cb2).was_called(1); assert.spy(err_cb2).was_called(0); assert.equal("ok", result); end); it("propagates errors down the chain, even when some handlers are not provided", function () local r, result; local test_error = {}; local p = promise.new(function (resolve, reject) r = reject; end); local cb = spy.new(function () end); local err_cb = spy.new(function (e) result = e end); local p2 = p:next(function () error(test_error) end); local p3 = p2:next(cb) p3:catch(err_cb); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(0); r("oh doh"); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(1); assert.spy(err_cb).was_called_with("oh doh"); assert.equal("oh doh", result); end); it("propagates values down the chain, even when some handlers are not provided", function () local r; local p = promise.new(function (resolve, reject) r = resolve; end); local cb = spy.new(function () end); local err_cb = spy.new(function () end); local p2 = p:next(function (v) return v; end); local p3 = p2:catch(err_cb) p3:next(cb); assert.spy(cb).was_called(0); assert.spy(err_cb).was_called(0); r(1337); assert.spy(cb).was_called(1); assert.spy(cb).was_called_with(1337); assert.spy(err_cb).was_called(0); end); it("fulfilled promises do not call error handlers and do propagate value", function () local p = promise.resolve("foo"); local cb = spy.new(function () end); local p2 = p:catch(cb); assert.spy(cb).was_called(0); local cb2 = spy.new(function () end); p2:catch(cb2); assert.spy(cb2).was_called(0); end); it("rejected promises do not call fulfilled handlers and do propagate reason", function () local p = promise.reject("foo"); local cb = spy.new(function () end); local p2 = p:next(cb); assert.spy(cb).was_called(0); local cb2 = spy.new(function () end); local cb2_err = spy.new(function () end); p2:next(cb2, cb2_err); assert.spy(cb2).was_called(0); assert.spy(cb2_err).was_called(1); assert.spy(cb2_err).was_called_with("foo"); end); describe("allows callbacks to return", function () it("pending promises", function () local r; local p = promise.resolve() local cb = spy.new(function () return promise.new(function (resolve) r = resolve; end); end); local cb2 = spy.new(function () end); p:next(cb):next(cb2); assert.spy(cb).was_called(1); assert.spy(cb2).was_called(0); r("hello"); assert.spy(cb).was_called(1); assert.spy(cb2).was_called(1); assert.spy(cb2).was_called_with("hello"); end); it("resolved promises", function () local p = promise.resolve() local cb = spy.new(function () return promise.resolve("hello"); end); local cb2 = spy.new(function () end); p:next(cb):next(cb2); assert.spy(cb).was_called(1); assert.spy(cb2).was_called(1); assert.spy(cb2).was_called_with("hello"); end); it("rejected promises", function () local p = promise.resolve() local cb = spy.new(function () return promise.reject("hello"); end); local cb2 = spy.new(function () return promise.reject("goodbye"); end); local cb3 = spy.new(function () end); p:next(cb):catch(cb2):catch(cb3); assert.spy(cb).was_called(1); assert.spy(cb2).was_called(1); assert.spy(cb2).was_called_with("hello"); assert.spy(cb3).was_called(1); assert.spy(cb3).was_called_with("goodbye"); end); it("ordinary values", function () local p = promise.resolve() local cb = spy.new(function () return "hello" end); local cb2 = spy.new(function () end); p:next(cb):next(cb2); assert.spy(cb).was_called(1); assert.spy(cb2).was_called(1); assert.spy(cb2).was_called_with("hello"); end); it("nil", function () local p = promise.resolve() local cb = spy.new(function () return end); local cb2 = spy.new(function () end); p:next(cb):next(cb2); assert.spy(cb).was_called(1); assert.spy(cb2).was_called(1); assert.spy(cb2).was_called_with(nil); end); end); describe("race()", function () it("works with fulfilled promises", function () local p1, p2 = promise.resolve("yep"), promise.resolve("nope"); local p = promise.race({ p1, p2 }); local result; p:next(function (v) result = v; end); assert.equal("yep", result); end); it("works with pending promises", function () local r1, r2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); local p = promise.race({ p1, p2 }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r2("yep"); r1("nope"); assert.spy(cb).was_called(1); assert.equal("yep", result); end); end); describe("all()", function () it("works with fulfilled promises", function () local p1, p2 = promise.resolve("yep"), promise.resolve("nope"); local p = promise.all({ p1, p2 }); local result; p:next(function (v) result = v; end); assert.same({ "yep", "nope" }, result); end); it("works with pending promises", function () local r1, r2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); local p = promise.all({ p1, p2 }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r2("yep"); assert.spy(cb).was_called(0); r1("nope"); assert.spy(cb).was_called(1); assert.same({ "nope", "yep" }, result); end); it("rejects if any promise rejects", function () local r1, r2; local p1 = promise.new(function (resolve, reject) r1 = reject end); local p2 = promise.new(function (resolve, reject) r2 = reject end); local p = promise.all({ p1, p2 }); local result; local cb = spy.new(function (v) result = v; end); local cb_err = spy.new(function (v) result = v; end); p:next(cb, cb_err); assert.spy(cb).was_called(0); assert.spy(cb_err).was_called(0); r2("fail"); assert.spy(cb).was_called(0); assert.spy(cb_err).was_called(1); r1("nope"); assert.spy(cb).was_called(0); assert.spy(cb_err).was_called(1); assert.equal("fail", result); end); it("works with non-numeric keys", function () local r1, r2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); local p = promise.all({ [true] = p1, [false] = p2 }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r2("yep"); assert.spy(cb).was_called(0); r1("nope"); assert.spy(cb).was_called(1); assert.same({ [true] = "nope", [false] = "yep" }, result); end); it("passes through non-promise values", function () local r1; local p1 = promise.new(function (resolve) r1 = resolve end); local p = promise.all({ [true] = p1, [false] = "yep" }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r1("nope"); assert.spy(cb).was_called(1); assert.same({ [true] = "nope", [false] = "yep" }, result); end); end); describe("all_settled()", function () it("works with fulfilled promises", function () local p1, p2 = promise.resolve("yep"), promise.resolve("nope"); local p = promise.all_settled({ p1, p2 }); local result; p:next(function (v) result = v; end); assert.same({ { status = "fulfilled", value = "yep" }; { status = "fulfilled", value = "nope" }; }, result); end); it("works with pending promises", function () local r1, r2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); local p = promise.all_settled({ p1, p2 }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r2("yep"); assert.spy(cb).was_called(0); r1("nope"); assert.spy(cb).was_called(1); assert.same({ { status = "fulfilled", value = "nope" }; { status = "fulfilled", value = "yep" }; }, result); end); it("works when some promises reject", function () local r1, r2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (_, reject) r2 = reject end); local p = promise.all_settled({ p1, p2 }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r2("this fails"); assert.spy(cb).was_called(0); r1("this succeeds"); assert.spy(cb).was_called(1); assert.same({ { status = "fulfilled", value = "this succeeds" }; { status = "rejected", reason = "this fails" }; }, result); end); it("works with non-numeric keys", function () local r1, r2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); local p = promise.all_settled({ foo = p1, bar = p2 }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r2("yep"); assert.spy(cb).was_called(0); r1("nope"); assert.spy(cb).was_called(1); assert.same({ foo = { status = "fulfilled", value = "nope" }; bar = { status = "fulfilled", value = "yep" }; }, result); end); it("passes through non-promise values", function () local r1; local p1 = promise.new(function (resolve) r1 = resolve end); local p = promise.all_settled({ foo = p1, bar = "yep" }); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r1("nope"); assert.spy(cb).was_called(1); assert.same({ foo = { status = "fulfilled", value = "nope" }; bar = "yep"; }, result); end); end); describe("catch()", function () it("works", function () local result; local p = promise.new(function (resolve) error({ foo = true }); end); local cb1 = spy.new(function (v) result = v; end); assert.spy(cb1).was_called(0); p:catch(cb1); assert.spy(cb1).was_called(1); assert.same({ foo = true }, result); end); end); describe("join()", function () it("works", function () local r1, r2; local res1, res2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); local p = promise.join(function (_res1, _res2) res1, res2 = _res1, _res2; return promise.resolve("works"); end, p1, p2); local result; local cb = spy.new(function (v) result = v; end); p:next(cb); assert.spy(cb).was_called(0); r2("yep"); assert.spy(cb).was_called(0); r1("nope"); assert.spy(cb).was_called(1); assert.same("works", result); assert.equals("nope", res1); assert.equals("yep", res2); end); end); it("promises may be resolved by other promises", function () local r1, r2; local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); local result; local cb = spy.new(function (v) result = v; end); p1:next(cb); assert.spy(cb).was_called(0); r1(p2); assert.spy(cb).was_called(0); r2("yep"); assert.spy(cb).was_called(1); assert.equal("yep", result); end); describe("reject()", function () it("returns a rejected promise", function () local p = promise.reject("foo"); local cb = spy.new(function () end); p:catch(cb); assert.spy(cb).was_called(1); assert.spy(cb).was_called_with("foo"); end); it("returns a rejected promise and does not call on_fulfilled", function () local p = promise.reject("foo"); local cb = spy.new(function () end); p:next(cb); assert.spy(cb).was_called(0); end); end); describe("finally()", function () local p, p2, resolve, reject, on_finally; before_each(function () p = promise.new(function (_resolve, _reject) resolve, reject = _resolve, _reject; end); on_finally = spy.new(function () end); p2 = p:finally(on_finally); end); it("runs when a promise is resolved", function () assert.spy(on_finally).was_called(0); resolve("foo"); assert.spy(on_finally).was_called(1); assert.spy(on_finally).was_not_called_with("foo"); end); it("runs when a promise is rejected", function () assert.spy(on_finally).was_called(0); reject("foo"); assert.spy(on_finally).was_called(1); assert.spy(on_finally).was_not_called_with("foo"); end); it("returns a promise that fulfills with the original value", function () local cb2 = spy.new(function () end); p2:next(cb2); assert.spy(on_finally).was_called(0); assert.spy(cb2).was_called(0); resolve("foo"); assert.spy(on_finally).was_called(1); assert.spy(cb2).was_called(1); assert.spy(on_finally).was_not_called_with("foo"); assert.spy(cb2).was_called_with("foo"); end); it("returns a promise that rejects with the original error", function () local on_finally_err = spy.new(function () end); local on_finally_ok = spy.new(function () end); p2:catch(on_finally_err); p2:next(on_finally_ok); assert.spy(on_finally).was_called(0); assert.spy(on_finally_err).was_called(0); reject("foo"); assert.spy(on_finally).was_called(1); -- Since the original promise was rejected, the finally promise should also be assert.spy(on_finally_ok).was_called(0); assert.spy(on_finally_err).was_called(1); assert.spy(on_finally).was_not_called_with("foo"); assert.spy(on_finally_err).was_called_with("foo"); end); it("returns a promise that rejects with an uncaught error inside on_finally", function () p = promise.new(function (_resolve, _reject) resolve, reject = _resolve, _reject; end); local test_error = {}; on_finally = spy.new(function () error(test_error) end); p2 = p:finally(on_finally); local on_finally_err = spy.new(function () end); p2:catch(on_finally_err); assert.spy(on_finally).was_called(0); assert.spy(on_finally_err).was_called(0); reject("foo"); assert.spy(on_finally).was_called(1); assert.spy(on_finally_err).was_called(1); assert.spy(on_finally).was_not_called_with("foo"); assert.spy(on_finally).was_not_called_with(test_error); assert.spy(on_finally_err).was_called_with(test_error); end); end); describe("try()", function () it("works with functions that return a promise", function () local resolve; local p = promise.try(function () return promise.new(function (_resolve) resolve = _resolve; end); end); assert.is_function(resolve); local on_resolved = spy.new(function () end); p:next(on_resolved); assert.spy(on_resolved).was_not_called(); resolve("foo"); assert.spy(on_resolved).was_called_with("foo"); end); it("works with functions that return a value", function () local p = promise.try(function () return "foo"; end); local on_resolved = spy.new(function () end); p:next(on_resolved); assert.spy(on_resolved).was_called_with("foo"); end); it("works with functions that return a promise that rejects", function () local reject; local p = promise.try(function () return promise.new(function (_, _reject) reject = _reject; end); end); assert.is_function(reject); local on_rejected = spy.new(function () end); p:catch(on_rejected); assert.spy(on_rejected).was_not_called(); reject("foo"); assert.spy(on_rejected).was_called_with("foo"); end); it("works with functions that throw errors", function () local test_error = {}; local p = promise.try(function () error(test_error); end); local on_rejected = spy.new(function () end); p:catch(on_rejected); assert.spy(on_rejected).was_called(1); assert.spy(on_rejected).was_called_with(test_error); end); end); end);