Merge 0.10->0.11
[prosody.git] / spec / util_pubsub_spec.lua
blob6386100b833c98429eb0f70ec679d9aaa7ec1c28
1 local pubsub;
2 setup(function ()
3 pubsub = require "util.pubsub";
4 end);
6 --[[TODO:
7 Retract
8 Purge
9 auto-create/auto-subscribe
10 Item store/node store
11 resize on max_items change
12 service creation config provides alternative node_defaults
13 get subscriptions
16 describe("util.pubsub", function ()
17 describe("simple node creation and deletion", function ()
18 randomize(false); -- These tests are ordered
20 -- Roughly a port of scansion/scripts/pubsub_createdelete.scs
21 local service = pubsub.new();
23 describe("#create", function ()
24 randomize(false); -- These tests are ordered
25 it("creates a new node", function ()
26 assert.truthy(service:create("princely_musings", true));
27 end);
29 it("fails to create the same node again", function ()
30 assert.falsy(service:create("princely_musings", true));
31 end);
32 end);
34 describe("#delete", function ()
35 randomize(false); -- These tests are ordered
36 it("deletes the node", function ()
37 assert.truthy(service:delete("princely_musings", true));
38 end);
40 it("can't delete an already deleted node", function ()
41 assert.falsy(service:delete("princely_musings", true));
42 end);
43 end);
44 end);
46 describe("simple publishing", function ()
47 randomize(false); -- These tests are ordered
49 local notified;
50 local broadcaster = spy.new(function (notif_type, node_name, subscribers, item) -- luacheck: ignore 212
51 notified = subscribers;
52 end);
53 local service = pubsub.new({
54 broadcaster = broadcaster;
55 });
57 it("creates a node", function ()
58 assert.truthy(service:create("node", true));
59 end);
61 it("lets someone subscribe", function ()
62 assert.truthy(service:add_subscription("node", true, "someone"));
63 end);
65 it("publishes an item", function ()
66 assert.truthy(service:publish("node", true, "1", "item 1"));
67 assert.truthy(notified["someone"]);
68 end);
70 it("called the broadcaster", function ()
71 assert.spy(broadcaster).was_called();
72 end);
74 it("should return one item", function ()
75 local ok, ret = service:get_items("node", true);
76 assert.truthy(ok);
77 assert.same({ "1", ["1"] = "item 1" }, ret);
78 end);
80 it("lets someone unsubscribe", function ()
81 assert.truthy(service:remove_subscription("node", true, "someone"));
82 end);
84 it("does not send notifications after subscription is removed", function ()
85 assert.truthy(service:publish("node", true, "1", "item 1"));
86 assert.is_nil(notified["someone"]);
87 end);
88 end);
90 describe("publish with config", function ()
91 randomize(false); -- These tests are ordered
93 local broadcaster = spy.new(function (notif_type, node_name, subscribers, item) -- luacheck: ignore 212
94 end);
95 local service = pubsub.new({
96 broadcaster = broadcaster;
97 autocreate_on_publish = true;
98 });
100 it("automatically creates node with requested config", function ()
101 assert(service:publish("node", true, "1", "item 1", { myoption = true }));
103 local ok, config = assert(service:get_node_config("node", true));
104 assert.equals(true, config.myoption);
105 end);
107 it("fails to publish to a node with differing config", function ()
108 local ok, err = service:publish("node", true, "1", "item 2", { myoption = false });
109 assert.falsy(ok);
110 assert.equals("precondition-not-met", err);
111 end);
113 it("allows to publish to a node with differing config when only defaults are suggested", function ()
114 assert(service:publish("node", true, "1", "item 2", { _defaults_only = true, myoption = false }));
115 end);
116 end);
118 describe("#issue1082", function ()
119 randomize(false); -- These tests are ordered
121 local service = pubsub.new();
123 it("creates a node with max_items = 1", function ()
124 assert.truthy(service:create("node", true, { max_items = 1 }));
125 end);
127 it("changes max_items to 2", function ()
128 assert.truthy(service:set_node_config("node", true, { max_items = 2 }));
129 end);
131 it("publishes one item", function ()
132 assert.truthy(service:publish("node", true, "1", "item 1"));
133 end);
135 it("should return one item", function ()
136 local ok, ret = service:get_items("node", true);
137 assert.truthy(ok);
138 assert.same({ "1", ["1"] = "item 1" }, ret);
139 end);
141 it("publishes another item", function ()
142 assert.truthy(service:publish("node", true, "2", "item 2"));
143 end);
145 it("should return two items", function ()
146 local ok, ret = service:get_items("node", true);
147 assert.truthy(ok);
148 assert.same({
149 "2",
150 "1",
151 ["1"] = "item 1",
152 ["2"] = "item 2",
153 }, ret);
154 end);
156 it("publishes yet another item", function ()
157 assert.truthy(service:publish("node", true, "3", "item 3"));
158 end);
160 it("should still return only two items", function ()
161 local ok, ret = service:get_items("node", true);
162 assert.truthy(ok);
163 assert.same({
164 "3",
165 "2",
166 ["2"] = "item 2",
167 ["3"] = "item 3",
168 }, ret);
169 end);
171 end);
173 describe("node config", function ()
174 local service;
175 before_each(function ()
176 service = pubsub.new();
177 service:create("test", true);
178 end);
179 it("access is forbidden for unaffiliated entities", function ()
180 local ok, err = service:get_node_config("test", "stranger");
181 assert.is_falsy(ok);
182 assert.equals("forbidden", err);
183 end);
184 it("returns an error for nodes that do not exist", function ()
185 local ok, err = service:get_node_config("nonexistent", true);
186 assert.is_falsy(ok);
187 assert.equals("item-not-found", err);
188 end);
189 end);
191 describe("access model", function ()
192 describe("open", function ()
193 local service;
194 before_each(function ()
195 service = pubsub.new();
196 -- Do not supply any config, 'open' should be default
197 service:create("test", true);
198 end);
199 it("should be the default", function ()
200 local ok, config = service:get_node_config("test", true);
201 assert.equal("open", config.access_model);
202 end);
203 it("should allow anyone to subscribe", function ()
204 local ok = service:add_subscription("test", "stranger", "stranger");
205 assert.is_true(ok);
206 end);
207 it("should still reject outcast-affiliated entities", function ()
208 assert(service:set_affiliation("test", true, "enemy", "outcast"));
209 local ok, err = service:add_subscription("test", "enemy", "enemy");
210 assert.is_falsy(ok);
211 assert.equal("forbidden", err);
212 end);
213 end);
214 describe("whitelist", function ()
215 local service;
216 before_each(function ()
217 service = assert(pubsub.new());
218 assert.is_true(service:create("test", true, { access_model = "whitelist" }));
219 end);
220 it("should be present in the configuration", function ()
221 local ok, config = service:get_node_config("test", true);
222 assert.equal("whitelist", config.access_model);
223 end);
224 it("should not allow anyone to subscribe", function ()
225 local ok, err = service:add_subscription("test", "stranger", "stranger");
226 assert.is_false(ok);
227 assert.equals("forbidden", err);
228 end);
229 end);
230 describe("change", function ()
231 local service;
232 before_each(function ()
233 service = pubsub.new();
234 service:create("test", true, { access_model = "open" });
235 end);
236 it("affects existing subscriptions", function ()
238 local ok = service:add_subscription("test", "stranger", "stranger");
239 assert.is_true(ok);
242 local ok, sub = service:get_subscription("test", "stranger", "stranger");
243 assert.is_true(ok);
244 assert.is_true(sub);
246 assert(service:set_node_config("test", true, { access_model = "whitelist" }));
248 local ok, sub = service:get_subscription("test", "stranger", "stranger");
249 assert.is_true(ok);
250 assert.is_nil(sub);
252 end);
253 end);
254 end);
256 describe("publish model", function ()
257 describe("publishers", function ()
258 local service;
259 before_each(function ()
260 service = pubsub.new();
261 -- Do not supply any config, 'publishers' should be default
262 service:create("test", true);
263 end);
264 it("should be the default", function ()
265 local ok, config = service:get_node_config("test", true);
266 assert.equal("publishers", config.publish_model);
267 end);
268 it("should not allow anyone to publish", function ()
269 assert.is_true(service:add_subscription("test", "stranger", "stranger"));
270 local ok, err = service:publish("test", "stranger", "item1", "foo");
271 assert.is_falsy(ok);
272 assert.equals("forbidden", err);
273 end);
274 it("should allow publishers to publish", function ()
275 assert(service:set_affiliation("test", true, "mypublisher", "publisher"));
276 local ok, err = service:publish("test", "mypublisher", "item1", "foo");
277 assert.is_true(ok);
278 end);
279 it("should allow owners to publish", function ()
280 assert(service:set_affiliation("test", true, "myowner", "owner"));
281 local ok = service:publish("test", "myowner", "item1", "foo");
282 assert.is_true(ok);
283 end);
284 end);
285 describe("open", function ()
286 local service;
287 before_each(function ()
288 service = pubsub.new();
289 service:create("test", true, { publish_model = "open" });
290 end);
291 it("should allow anyone to publish", function ()
292 local ok = service:publish("test", "stranger", "item1", "foo");
293 assert.is_true(ok);
294 end);
295 end);
296 describe("subscribers", function ()
297 local service;
298 before_each(function ()
299 service = pubsub.new();
300 service:create("test", true, { publish_model = "subscribers" });
301 end);
302 it("should not allow non-subscribers to publish", function ()
303 local ok, err = service:publish("test", "stranger", "item1", "foo");
304 assert.is_falsy(ok);
305 assert.equals("forbidden", err);
306 end);
307 it("should allow subscribers to publish without an affiliation", function ()
308 assert.is_true(service:add_subscription("test", "stranger", "stranger"));
309 local ok = service:publish("test", "stranger", "item1", "foo");
310 assert.is_true(ok);
311 end);
312 it("should allow publishers to publish without a subscription", function ()
313 assert(service:set_affiliation("test", true, "mypublisher", "publisher"));
314 local ok, err = service:publish("test", "mypublisher", "item1", "foo");
315 assert.is_true(ok);
316 end);
317 it("should allow owners to publish without a subscription", function ()
318 assert(service:set_affiliation("test", true, "myowner", "owner"));
319 local ok = service:publish("test", "myowner", "item1", "foo");
320 assert.is_true(ok);
321 end);
322 end);
323 end);
325 describe("item API", function ()
326 local service;
327 before_each(function ()
328 service = pubsub.new();
329 service:create("test", true, { publish_model = "subscribers" });
330 end);
331 describe("get_last_item()", function ()
332 it("succeeds with nil on empty nodes", function ()
333 local ok, id, item = service:get_last_item("test", true);
334 assert.is_true(ok);
335 assert.is_nil(id);
336 assert.is_nil(item);
337 end);
338 it("succeeds and returns the last item", function ()
339 service:publish("test", true, "one", "hello world");
340 service:publish("test", true, "two", "hello again");
341 service:publish("test", true, "three", "hey");
342 service:publish("test", true, "one", "bye");
343 local ok, id, item = service:get_last_item("test", true);
344 assert.is_true(ok);
345 assert.equal("one", id);
346 assert.equal("bye", item);
347 end);
348 end);
349 describe("get_items()", function ()
350 it("fails on non-existent nodes", function ()
351 local ok, err = service:get_items("no-node", true);
352 assert.is_falsy(ok);
353 assert.equal("item-not-found", err);
354 end);
355 it("returns no items on an empty node", function ()
356 local ok, items = service:get_items("test", true);
357 assert.is_true(ok);
358 assert.equal(0, #items);
359 assert.is_nil(next(items));
360 end);
361 it("returns no items on an empty node", function ()
362 local ok, items = service:get_items("test", true);
363 assert.is_true(ok);
364 assert.equal(0, #items);
365 assert.is_nil((next(items)));
366 end);
367 it("returns all published items", function ()
368 service:publish("test", true, "one", "hello world");
369 service:publish("test", true, "two", "hello again");
370 service:publish("test", true, "three", "hey");
371 service:publish("test", true, "one", "bye");
372 local ok, items = service:get_items("test", true);
373 assert.is_true(ok);
374 assert.same({ "one", "three", "two", two = "hello again", three = "hey", one = "bye" }, items);
375 end);
376 end);
377 end);
379 describe("restoring data from nodestore", function ()
380 local nodestore = {
381 data = {
382 test = {
383 name = "test";
384 config = {};
385 affiliations = {};
386 subscribers = {
387 ["someone"] = true;
392 function nodestore:users()
393 return pairs(self.data)
395 function nodestore:get(key)
396 return self.data[key];
398 local service = pubsub.new({
399 nodestore = nodestore;
401 it("subscriptions", function ()
402 local ok, ret = service:get_subscriptions(nil, true, nil)
403 assert.is_true(ok);
404 assert.same({ { node = "test", jid = "someone", subscription = true, } }, ret);
405 end);
406 end);
408 end);