mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-30 19:43:47 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			530 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			530 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| 
 | |
| /*
 | |
|     This mostly tests the peer_data module, but it
 | |
|     also tests some stream_data functions that are
 | |
|     glorified wrappers for peer_data functions.
 | |
| */
 | |
| 
 | |
| const assert = require("node:assert/strict");
 | |
| 
 | |
| const {make_user_group} = require("./lib/example_group.cjs");
 | |
| const {make_realm} = require("./lib/example_realm.cjs");
 | |
| const example_settings = require("./lib/example_settings.cjs");
 | |
| const {mock_esm, set_global, zrequire} = require("./lib/namespace.cjs");
 | |
| const {run_test} = require("./lib/test.cjs");
 | |
| const blueslip = require("./lib/zblueslip.cjs");
 | |
| const {page_params} = require("./lib/zpage_params.cjs");
 | |
| 
 | |
| const channel = mock_esm("../src/channel");
 | |
| 
 | |
| const peer_data = zrequire("peer_data");
 | |
| const people = zrequire("people");
 | |
| const {set_current_user, set_realm} = zrequire("state_data");
 | |
| const stream_data = zrequire("stream_data");
 | |
| const user_groups = zrequire("user_groups");
 | |
| 
 | |
| set_current_user({});
 | |
| const realm = make_realm();
 | |
| set_realm(realm);
 | |
| 
 | |
| page_params.realm_users = [];
 | |
| const me = {
 | |
|     email: "me@zulip.com",
 | |
|     full_name: "Current User",
 | |
|     user_id: 100,
 | |
| };
 | |
| // set up user data
 | |
| const fred = {
 | |
|     email: "fred@zulip.com",
 | |
|     full_name: "Fred",
 | |
|     user_id: 101,
 | |
| };
 | |
| const gail = {
 | |
|     email: "gail@zulip.com",
 | |
|     full_name: "Gail",
 | |
|     user_id: 102,
 | |
| };
 | |
| const george = {
 | |
|     email: "george@zulip.com",
 | |
|     full_name: "George",
 | |
|     user_id: 103,
 | |
| };
 | |
| const bot_botson = {
 | |
|     email: "botson-bot@example.com",
 | |
|     user_id: 35,
 | |
|     full_name: "Bot Botson",
 | |
|     is_bot: true,
 | |
|     role: 300,
 | |
| };
 | |
| 
 | |
| const nobody_group = make_user_group({
 | |
|     name: "Nobody",
 | |
|     id: 1,
 | |
|     members: new Set([]),
 | |
|     is_system_group: true,
 | |
|     direct_subgroup_ids: new Set([]),
 | |
| });
 | |
| 
 | |
| function contains_sub(subs, sub) {
 | |
|     return subs.some((s) => s.name === sub.name);
 | |
| }
 | |
| function test(label, f) {
 | |
|     run_test(label, ({override}) => {
 | |
|         peer_data.clear_for_testing();
 | |
|         stream_data.clear_subscriptions();
 | |
|         people.init();
 | |
|         people.add_active_user(me);
 | |
|         people.initialize_current_user(me.user_id);
 | |
| 
 | |
|         user_groups.initialize({
 | |
|             realm_user_groups: [nobody_group],
 | |
|         });
 | |
|         override(
 | |
|             realm,
 | |
|             "server_supported_permission_settings",
 | |
|             example_settings.server_supported_permission_settings,
 | |
|         );
 | |
|         override(realm, "realm_can_access_all_users_group", nobody_group.id);
 | |
| 
 | |
|         return f({override});
 | |
|     });
 | |
| }
 | |
| 
 | |
| test("unsubscribe", () => {
 | |
|     const devel = {name: "devel", subscribed: false, stream_id: 1};
 | |
|     stream_data.add_sub_for_tests(devel);
 | |
| 
 | |
|     // verify clean slate
 | |
|     assert.ok(!stream_data.is_subscribed(devel.stream_id));
 | |
| 
 | |
|     // set up our subscription
 | |
|     devel.subscribed = true;
 | |
|     peer_data.set_subscribers(devel.stream_id, [me.user_id]);
 | |
| 
 | |
|     // ensure our setup is accurate
 | |
|     assert.ok(stream_data.is_subscribed(devel.stream_id));
 | |
| 
 | |
|     // DO THE UNSUBSCRIBE HERE
 | |
|     stream_data.unsubscribe_myself(devel);
 | |
|     assert.ok(!devel.subscribed);
 | |
|     assert.ok(!stream_data.is_subscribed(devel.stream_id));
 | |
|     assert.ok(!contains_sub(stream_data.subscribed_subs(), devel));
 | |
|     assert.ok(contains_sub(stream_data.unsubscribed_subs(), devel));
 | |
| 
 | |
|     // make sure subsequent calls work
 | |
|     const sub = stream_data.get_sub("devel");
 | |
|     assert.ok(!sub.subscribed);
 | |
| });
 | |
| 
 | |
| test("subscribers", async () => {
 | |
|     const sub = {
 | |
|         name: "Rome",
 | |
|         subscribed: true,
 | |
|         stream_id: 1001,
 | |
|         can_add_subscribers_group: nobody_group.id,
 | |
|         can_administer_channel_group: nobody_group.id,
 | |
|         can_subscribe_group: nobody_group.id,
 | |
|     };
 | |
|     stream_data.add_sub_for_tests(sub);
 | |
| 
 | |
|     people.add_active_user(fred);
 | |
|     people.add_active_user(gail);
 | |
|     people.add_active_user(george);
 | |
| 
 | |
|     // verify setup
 | |
|     assert.ok(stream_data.is_subscribed(sub.stream_id));
 | |
| 
 | |
|     const stream_id = sub.stream_id;
 | |
| 
 | |
|     function potential_subscriber_ids() {
 | |
|         const users = peer_data.potential_subscribers(stream_id);
 | |
|         return users.map((u) => u.user_id).toSorted();
 | |
|     }
 | |
| 
 | |
|     blueslip.expect(
 | |
|         "error",
 | |
|         "Fetching potential subscribers for stream without full subscriber data",
 | |
|     );
 | |
|     potential_subscriber_ids();
 | |
|     blueslip.reset();
 | |
| 
 | |
|     const bogus_stream_id = 999;
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We called set_subscribers for an untracked stream: " + bogus_stream_id,
 | |
|     );
 | |
|     peer_data.set_subscribers(bogus_stream_id, []);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     peer_data.set_subscribers(stream_id, []);
 | |
|     assert.deepEqual(potential_subscriber_ids(), [
 | |
|         me.user_id,
 | |
|         fred.user_id,
 | |
|         gail.user_id,
 | |
|         george.user_id,
 | |
|     ]);
 | |
| 
 | |
|     peer_data.set_subscribers(stream_id, [me.user_id, fred.user_id, george.user_id]);
 | |
|     assert.ok(stream_data.is_user_loaded_and_subscribed(stream_id, me.user_id));
 | |
|     assert.ok(stream_data.is_user_loaded_and_subscribed(stream_id, fred.user_id));
 | |
|     assert.ok(stream_data.is_user_loaded_and_subscribed(stream_id, george.user_id));
 | |
|     assert.ok(!stream_data.is_user_loaded_and_subscribed(stream_id, gail.user_id));
 | |
| 
 | |
|     assert.deepEqual(potential_subscriber_ids(), [gail.user_id]);
 | |
| 
 | |
|     peer_data.set_subscribers(stream_id, []);
 | |
| 
 | |
|     const brutus = {
 | |
|         email: "brutus@zulip.com",
 | |
|         full_name: "Brutus",
 | |
|         user_id: 104,
 | |
|     };
 | |
|     people.add_active_user(brutus);
 | |
|     assert.ok(!stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
| 
 | |
|     // add
 | |
|     peer_data.add_subscriber(stream_id, brutus.user_id);
 | |
|     assert.ok(stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
|     assert.equal(peer_data.get_subscriber_count(stream_id), 1);
 | |
| 
 | |
|     // verify that adding an already-added subscriber is a noop
 | |
|     peer_data.add_subscriber(stream_id, brutus.user_id);
 | |
|     assert.ok(stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
|     assert.equal(peer_data.get_subscriber_count(stream_id), 1);
 | |
| 
 | |
|     // remove
 | |
|     peer_data.remove_subscriber(stream_id, brutus.user_id);
 | |
|     assert.ok(!stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
|     assert.equal(peer_data.get_subscriber_count(stream_id), 0);
 | |
| 
 | |
|     // Verify noop for bad stream when removing subscriber
 | |
|     const bad_stream_id = 999999;
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We called get_loaded_subscriber_subset for an untracked stream: " + bad_stream_id,
 | |
|     );
 | |
|     blueslip.expect(
 | |
|         "error",
 | |
|         "We called decrement_subscriber_count for an untracked stream: " + bad_stream_id,
 | |
|     );
 | |
|     peer_data.remove_subscriber(bad_stream_id, brutus.user_id);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     // verify that removing an already-removed subscriber is a noop
 | |
|     peer_data.remove_subscriber(stream_id, brutus.user_id);
 | |
|     assert.ok(!stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
|     assert.equal(peer_data.get_subscriber_count(stream_id), 0);
 | |
| 
 | |
|     // Verify defensive code in set_subscribers, where the second parameter
 | |
|     // can be undefined.
 | |
|     stream_data.add_sub_for_tests(sub);
 | |
|     peer_data.add_subscriber(stream_id, brutus.user_id);
 | |
|     sub.subscribed = true;
 | |
|     assert.ok(stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
| 
 | |
|     // Verify that we noop and don't crash when unsubscribed.
 | |
|     sub.subscribed = false;
 | |
|     peer_data.add_subscriber(stream_id, brutus.user_id);
 | |
|     assert.equal(stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id), true);
 | |
|     peer_data.remove_subscriber(stream_id, brutus.user_id);
 | |
|     assert.equal(stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id), false);
 | |
|     peer_data.add_subscriber(stream_id, brutus.user_id);
 | |
|     assert.equal(stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id), true);
 | |
| 
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We got a is_user_subscribed call for a non-existent or inaccessible stream.",
 | |
|         2,
 | |
|     );
 | |
|     sub.invite_only = true;
 | |
|     assert.ok(!stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
|     peer_data.remove_subscriber(stream_id, brutus.user_id);
 | |
|     assert.ok(!stream_data.is_user_loaded_and_subscribed(stream_id, brutus.user_id));
 | |
|     blueslip.reset();
 | |
| 
 | |
|     // Same test but for `maybe_fetch_is_user_subscribed`
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We got a maybe_fetch_is_user_subscribed call for a non-existent or inaccessible stream.",
 | |
|         2,
 | |
|     );
 | |
|     peer_data.add_subscriber(stream_id, brutus.user_id);
 | |
|     assert.ok(!(await stream_data.maybe_fetch_is_user_subscribed(stream_id, brutus.user_id)));
 | |
|     peer_data.remove_subscriber(stream_id, brutus.user_id);
 | |
|     assert.ok(!(await stream_data.maybe_fetch_is_user_subscribed(stream_id, brutus.user_id)));
 | |
|     blueslip.reset();
 | |
| 
 | |
|     // Verify that we don't crash for a bad stream.
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We called get_loaded_subscriber_subset for an untracked stream: 9999999",
 | |
|     );
 | |
|     blueslip.expect(
 | |
|         "error",
 | |
|         "We called increment_subscriber_count for an untracked stream: 9999999",
 | |
|     );
 | |
|     peer_data.add_subscriber(9999999, brutus.user_id);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     // Verify that we don't crash for a bad user id.
 | |
|     blueslip.expect("error", "Unknown user_id in maybe_get_user_by_id");
 | |
|     blueslip.expect("warn", "We tried to add invalid subscriber: 88888");
 | |
|     peer_data.add_subscriber(stream_id, 88888);
 | |
|     blueslip.reset();
 | |
| });
 | |
| 
 | |
| test("maybe_fetch_stream_subscribers", async () => {
 | |
|     const india = {
 | |
|         stream_id: 102,
 | |
|         name: "India",
 | |
|         subscribed: true,
 | |
|     };
 | |
|     stream_data.add_sub_for_tests(india);
 | |
|     let channel_get_calls = 0;
 | |
|     channel.get = (opts) => {
 | |
|         assert.equal(opts.url, `/json/streams/${india.stream_id}/members`);
 | |
|         channel_get_calls += 1;
 | |
|         return {
 | |
|             subscribers: [1, 2, 3, 4],
 | |
|         };
 | |
|     };
 | |
| 
 | |
|     // Only one of these will do the fetch, and the other will wait
 | |
|     // for the first fetch to complete.
 | |
|     const promise1 = peer_data.maybe_fetch_stream_subscribers(india.stream_id);
 | |
|     const promise2 = peer_data.maybe_fetch_stream_subscribers(india.stream_id);
 | |
|     await promise1;
 | |
|     await promise2;
 | |
|     assert.equal(channel_get_calls, 1);
 | |
| 
 | |
|     peer_data.clear_for_testing();
 | |
|     const pending_promise = peer_data.maybe_fetch_stream_subscribers(india.stream_id, false);
 | |
|     peer_data.bulk_add_subscribers({
 | |
|         stream_ids: [india.stream_id],
 | |
|         user_ids: [7, 9],
 | |
|     });
 | |
|     peer_data.bulk_remove_subscribers({
 | |
|         stream_ids: [india.stream_id],
 | |
|         user_ids: [3],
 | |
|     });
 | |
|     blueslip.expect("error", "Getting subscribers for stream without full subscriber data");
 | |
|     const subscribers_before_fetch_completes = peer_data.get_subscriber_ids_assert_loaded(
 | |
|         india.stream_id,
 | |
|     );
 | |
|     blueslip.reset();
 | |
|     assert.deepEqual(subscribers_before_fetch_completes, [7, 9]);
 | |
|     const subscribers_after_fetch = await pending_promise;
 | |
|     assert.deepEqual([...subscribers_after_fetch.keys()], [1, 2, 4, 7, 9]);
 | |
| 
 | |
|     peer_data.clear_for_testing();
 | |
|     assert.equal(await peer_data.maybe_fetch_is_user_subscribed(india.stream_id, 2, false), true);
 | |
|     assert.equal(peer_data.has_full_subscriber_data(india.stream_id), true);
 | |
| 
 | |
|     peer_data.clear_for_testing();
 | |
|     assert.equal(peer_data.has_full_subscriber_data(india.stream_id), false);
 | |
|     assert.equal(await peer_data.maybe_fetch_is_user_subscribed(india.stream_id, 2, false), true);
 | |
|     assert.equal(await peer_data.maybe_fetch_is_user_subscribed(india.stream_id, 5, false), false);
 | |
| 
 | |
|     peer_data.clear_for_testing();
 | |
|     blueslip.expect("error", "Getting subscribers for stream without full subscriber data");
 | |
|     assert.deepEqual(await peer_data.get_subscriber_ids_assert_loaded(india.stream_id), []);
 | |
|     blueslip.reset();
 | |
|     assert.deepEqual(
 | |
|         await peer_data.get_subscribers_with_possible_fetch(india.stream_id),
 | |
|         [1, 2, 3, 4],
 | |
|     );
 | |
| 
 | |
|     peer_data.clear_for_testing();
 | |
|     channel.get = () => {
 | |
|         throw new Error("error");
 | |
|     };
 | |
|     blueslip.expect("error", "Failure fetching channel subscribers");
 | |
|     // retry is false, so we get null because there was an error
 | |
|     assert.deepEqual(
 | |
|         await peer_data.get_subscribers_with_possible_fetch(india.stream_id, false),
 | |
|         null,
 | |
|     );
 | |
|     blueslip.reset();
 | |
| 
 | |
|     channel.get = () => {
 | |
|         throw new Error("error");
 | |
|     };
 | |
|     peer_data.clear_for_testing();
 | |
|     blueslip.expect("error", "Failure fetching channel subscribers");
 | |
|     assert.equal(await peer_data.maybe_fetch_is_user_subscribed(india.stream_id, 5, false), null);
 | |
|     // If we know they're subscribed, we return `true` even though we don't have complete
 | |
|     // data.
 | |
|     peer_data.bulk_add_subscribers({
 | |
|         stream_ids: [india.stream_id],
 | |
|         user_ids: [5],
 | |
|     });
 | |
|     assert.equal(await peer_data.maybe_fetch_is_user_subscribed(india.stream_id, 5, false), true);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     peer_data.clear_for_testing();
 | |
|     set_global("setTimeout", (f) => {
 | |
|         f();
 | |
|     });
 | |
|     let num_attempts = 0;
 | |
|     channel.get = async () => {
 | |
|         num_attempts += 1;
 | |
|         if (num_attempts === 2) {
 | |
|             return {
 | |
|                 subscribers: [1, 2, 3, 4],
 | |
|             };
 | |
|         }
 | |
|         throw new Error("error");
 | |
|     };
 | |
|     blueslip.expect("error", "Failure fetching channel subscribers");
 | |
|     const subscribers = await peer_data.maybe_fetch_stream_subscribers_with_retry(india.stream_id);
 | |
|     assert.equal(num_attempts, 2);
 | |
|     assert.deepEqual([...subscribers.keys()], [1, 2, 3, 4]);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     peer_data.clear_for_testing();
 | |
|     blueslip.expect("error", "Failure fetching channel subscribers");
 | |
|     num_attempts = 0;
 | |
|     assert.equal(await peer_data.maybe_fetch_is_user_subscribed(india.stream_id, 5, true), false);
 | |
|     assert.equal(num_attempts, 2);
 | |
| });
 | |
| 
 | |
| test("get_subscriber_count", async () => {
 | |
|     people.add_active_user(fred);
 | |
|     people.add_active_user(gail);
 | |
|     people.add_active_user(george);
 | |
|     const welcome_bot = {
 | |
|         email: "welcome-bot@example.com",
 | |
|         user_id: 40,
 | |
|         full_name: "Welcome Bot",
 | |
|         is_bot: true,
 | |
|     };
 | |
|     people.add_active_user(welcome_bot);
 | |
| 
 | |
|     const india = {
 | |
|         stream_id: 102,
 | |
|         name: "India",
 | |
|         subscribed: true,
 | |
|         subscriber_count: 0,
 | |
|     };
 | |
|     stream_data.clear_subscriptions();
 | |
| 
 | |
|     blueslip.expect("warn", "We called get_subscriber_count for an untracked stream: 102");
 | |
|     assert.equal(peer_data.get_subscriber_count(india.stream_id), 0);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     stream_data.add_sub_for_tests(india);
 | |
|     assert.equal(peer_data.get_subscriber_count(india.stream_id), 0);
 | |
| 
 | |
|     peer_data.add_subscriber(india.stream_id, fred.user_id);
 | |
|     assert.equal(peer_data.get_subscriber_count(india.stream_id), 1);
 | |
|     peer_data.add_subscriber(india.stream_id, george.user_id);
 | |
|     assert.equal(peer_data.get_subscriber_count(india.stream_id), 2);
 | |
| 
 | |
|     peer_data.remove_subscriber(india.stream_id, george.user_id);
 | |
|     assert.deepStrictEqual(peer_data.get_subscriber_count(india.stream_id), 1);
 | |
| 
 | |
|     peer_data.add_subscriber(india.stream_id, welcome_bot.user_id);
 | |
|     assert.deepStrictEqual(peer_data.get_subscriber_count(india.stream_id), 2);
 | |
|     // Get the count without bots
 | |
|     assert.deepStrictEqual(peer_data.get_subscriber_count(india.stream_id, false), 1);
 | |
| 
 | |
|     // We don't have full data, so we assume this is a decrement even though gail isn't
 | |
|     // in the subscriber list.
 | |
|     peer_data.set_subscriber_count(india.stream_id, 20);
 | |
|     assert.deepStrictEqual(peer_data.get_subscriber_count(india.stream_id), 20);
 | |
|     peer_data.remove_subscriber(india.stream_id, gail.user_id);
 | |
|     assert.deepStrictEqual(peer_data.get_subscriber_count(india.stream_id), 19);
 | |
| 
 | |
|     // Now fetch the actual subscribers
 | |
|     channel.get = () => ({
 | |
|         subscribers: [george.user_id, fred.user_id],
 | |
|     });
 | |
|     await peer_data.maybe_fetch_stream_subscribers(india.stream_id);
 | |
|     assert.deepStrictEqual(peer_data.get_subscriber_count(india.stream_id), 2);
 | |
|     // Now we know Gail isn't subscribed, so we don't decrement the count
 | |
|     peer_data.remove_subscriber(india.stream_id, gail.user_id);
 | |
|     assert.deepStrictEqual(peer_data.get_subscriber_count(india.stream_id), 2);
 | |
| });
 | |
| 
 | |
| test("is_subscriber_subset", async () => {
 | |
|     function make_sub(stream_id, user_ids) {
 | |
|         const sub = {
 | |
|             stream_id,
 | |
|             name: `stream ${stream_id}`,
 | |
|         };
 | |
|         stream_data.add_sub_for_tests(sub);
 | |
|         peer_data.set_subscribers(sub.stream_id, user_ids);
 | |
|         return sub;
 | |
|     }
 | |
| 
 | |
|     const sub_a = make_sub(301, [1, 2]);
 | |
|     const sub_b = make_sub(302, [2, 3]);
 | |
|     const sub_c = make_sub(303, [1, 2, 3]);
 | |
| 
 | |
|     const matrix = [
 | |
|         [sub_a, sub_a, true],
 | |
|         [sub_a, sub_b, false],
 | |
|         [sub_a, sub_c, true],
 | |
|         [sub_b, sub_a, false],
 | |
|         [sub_b, sub_b, true],
 | |
|         [sub_b, sub_c, true],
 | |
|         [sub_c, sub_a, false],
 | |
|         [sub_c, sub_b, false],
 | |
|         [sub_c, sub_c, true],
 | |
|     ];
 | |
| 
 | |
|     for (const row of matrix) {
 | |
|         assert.equal(
 | |
|             await peer_data.is_subscriber_subset(row[0].stream_id, row[1].stream_id),
 | |
|             row[2],
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     // Two untracked streams should never be passed into us.
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We called get_loaded_subscriber_subset for an untracked stream: 88888",
 | |
|     );
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We called get_loaded_subscriber_subset for an untracked stream: 99999",
 | |
|     );
 | |
|     await peer_data.is_subscriber_subset(99999, 88888);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     // Warn about hypothetical undefined stream_ids.
 | |
|     blueslip.expect(
 | |
|         "warn",
 | |
|         "We called get_loaded_subscriber_subset for an untracked stream: undefined",
 | |
|     );
 | |
|     await peer_data.is_subscriber_subset(undefined, sub_a.stream_id);
 | |
|     blueslip.reset();
 | |
| 
 | |
|     // Errors when fetching subscriber data return `null`
 | |
|     channel.get = () => {
 | |
|         throw new Error("error");
 | |
|     };
 | |
|     peer_data.clear_for_testing();
 | |
|     // Expect two calls, one for each channel
 | |
|     blueslip.expect("error", "Failure fetching channel subscribers", 2);
 | |
|     assert.equal(await peer_data.is_subscriber_subset(sub_a.stream_id, sub_b.stream_id), null);
 | |
| });
 | |
| 
 | |
| test("get_unique_subscriber_count_for_streams", async () => {
 | |
|     const sub = {name: "Rome", subscribed: true, stream_id: 1001};
 | |
|     stream_data.add_sub_for_tests(sub);
 | |
| 
 | |
|     people.add_active_user(fred);
 | |
|     people.add_active_user(gail);
 | |
|     people.add_active_user(george);
 | |
|     people.add_active_user(bot_botson);
 | |
| 
 | |
|     const stream_id = sub.stream_id;
 | |
|     peer_data.set_subscribers(stream_id, [me.user_id, fred.user_id, bot_botson.user_id]);
 | |
| 
 | |
|     const count = await peer_data.get_unique_subscriber_count_for_streams([stream_id]);
 | |
| 
 | |
|     assert.equal(count, 2);
 | |
| });
 |