2020-08-01 03:43:15 +02:00
|
|
|
"use strict";
|
|
|
|
|
2020-11-30 23:46:45 +01:00
|
|
|
const {strict: assert} = require("assert");
|
|
|
|
|
2023-02-22 23:04:10 +01:00
|
|
|
const {mock_esm, zrequire} = require("./lib/namespace");
|
|
|
|
const {run_test} = require("./lib/test");
|
|
|
|
const blueslip = require("./lib/zblueslip");
|
|
|
|
const {page_params, user_settings} = require("./lib/zpage_params");
|
2020-12-01 00:02:16 +01:00
|
|
|
|
2023-02-22 23:04:10 +01:00
|
|
|
const reload_state = mock_esm("../src/reload_state", {
|
2021-02-26 12:49:16 +01:00
|
|
|
is_in_progress: () => false,
|
2021-03-07 13:57:14 +01:00
|
|
|
});
|
2021-02-28 00:48:19 +01:00
|
|
|
|
2020-12-01 23:21:38 +01:00
|
|
|
const people = zrequire("people");
|
2021-03-23 14:24:49 +01:00
|
|
|
const watchdog = zrequire("watchdog");
|
2020-12-01 23:21:38 +01:00
|
|
|
const presence = zrequire("presence");
|
|
|
|
|
presence: Tweak and document presence tuning values.
We're changing the ping interval from 50s to 60s, because that's what
the mobile apps have hardcoded currently, and backwards-compatibility
is more important there than the web app's previously hardcoded 50s.
For PRESENCE_PING_INTERVAL_SECS, the previous value hardcoded in both
clients was 140s, selected as "plenty of network/other latency more
than 2 x ACTIVE_PING_INTERVAL_MS". This is a pretty aggressive value;
even a single request being missed or 500ing can result in a user
appearing offline incorrectly. (There's a lag of up to one full ping
interval between when the other client checks in and when you check
in, and so we'll be at almost 2 ping intervals when you issue your
next request that might get an updated connection time from that
user).
To increase failure tolerance, we want to change the offline
threshhold from 2 x ACTIVE_PING_INTERVAL + 20s to 3 x
ACTIVE_PING_INTERVAL + 20s, aka 140s => 200s, to be more robust to
temporary failures causing us to display other users as offline.
Since the mobile apps currently have 140s and 60s hardcoded, it should
be safe to make this particular change; the mobile apps will just
remain more aggressive than the web app in marking users offline until
it uses the new API parameters.
The end result in that Zulip will be slightly less aggressive at
marking other users as offline if they go off the Internet. We will
likely be able to tune ACTIVE_PING_INTERVAL downwards once #16381 and
its follow-ups are completed, because it'll likely make these requests
much cheaper.
2023-02-21 12:20:41 +01:00
|
|
|
const OFFLINE_THRESHOLD_SECS = 200;
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const me = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "me@zulip.com",
|
2020-04-03 15:31:17 +02:00
|
|
|
user_id: 101,
|
2020-07-15 01:29:15 +02:00
|
|
|
full_name: "Me Myself",
|
2017-05-24 17:55:31 +02:00
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const alice = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "alice@zulip.com",
|
2017-05-24 17:55:31 +02:00
|
|
|
user_id: 1,
|
2020-07-15 01:29:15 +02:00
|
|
|
full_name: "Alice Smith",
|
2017-05-24 17:55:31 +02:00
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const fred = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "fred@zulip.com",
|
2017-05-24 17:55:31 +02:00
|
|
|
user_id: 2,
|
|
|
|
full_name: "Fred Flintstone",
|
|
|
|
};
|
|
|
|
|
2020-02-07 14:50:30 +01:00
|
|
|
const sally = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "sally@example.com",
|
2020-02-07 14:50:30 +01:00
|
|
|
user_id: 3,
|
2020-07-15 01:29:15 +02:00
|
|
|
full_name: "Sally Jones",
|
2020-02-07 14:50:30 +01:00
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const zoe = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "zoe@example.com",
|
2017-05-24 17:55:31 +02:00
|
|
|
user_id: 6,
|
2020-07-15 01:29:15 +02:00
|
|
|
full_name: "Zoe Yang",
|
2017-05-24 17:55:31 +02:00
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const bot = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "bot@zulip.com",
|
2017-06-07 18:36:26 +02:00
|
|
|
user_id: 7,
|
2020-07-15 01:29:15 +02:00
|
|
|
full_name: "The Bot",
|
2017-06-07 18:36:26 +02:00
|
|
|
is_bot: true,
|
|
|
|
};
|
|
|
|
|
2020-05-29 18:38:52 +02:00
|
|
|
const john = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "john@zulip.com",
|
2020-05-29 18:38:52 +02:00
|
|
|
user_id: 8,
|
|
|
|
full_name: "John Doe",
|
|
|
|
};
|
|
|
|
|
|
|
|
const jane = {
|
2020-07-15 01:29:15 +02:00
|
|
|
email: "jane@zulip.com",
|
2020-05-29 18:38:52 +02:00
|
|
|
user_id: 9,
|
|
|
|
full_name: "Jane Doe",
|
|
|
|
};
|
|
|
|
|
2020-05-26 22:34:15 +02:00
|
|
|
people.add_active_user(me);
|
|
|
|
people.add_active_user(alice);
|
|
|
|
people.add_active_user(fred);
|
|
|
|
people.add_active_user(sally);
|
|
|
|
people.add_active_user(zoe);
|
|
|
|
people.add_active_user(bot);
|
2020-05-29 18:38:52 +02:00
|
|
|
people.add_active_user(john);
|
|
|
|
people.add_active_user(jane);
|
2017-05-24 17:55:31 +02:00
|
|
|
people.initialize_current_user(me.user_id);
|
|
|
|
|
2021-03-12 13:00:49 +01:00
|
|
|
function test(label, f) {
|
2023-08-04 23:40:48 +02:00
|
|
|
run_test(label, (helpers) => {
|
2023-02-21 11:52:30 +01:00
|
|
|
page_params.server_presence_offline_threshold_seconds = OFFLINE_THRESHOLD_SECS;
|
2021-12-04 01:20:20 +01:00
|
|
|
user_settings.presence_enabled = true;
|
2021-03-12 13:00:49 +01:00
|
|
|
presence.clear_internal_data();
|
2023-08-04 23:40:48 +02:00
|
|
|
f(helpers);
|
2021-03-12 13:00:49 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
test("my user", () => {
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(me.user_id), "active");
|
2019-01-03 16:44:06 +01:00
|
|
|
});
|
|
|
|
|
2021-06-16 14:38:37 +02:00
|
|
|
test("unknown user", ({override}) => {
|
2020-04-03 15:31:17 +02:00
|
|
|
const unknown_user_id = 999;
|
|
|
|
const now = 888888;
|
|
|
|
const presences = {};
|
2020-07-15 01:29:15 +02:00
|
|
|
presences[unknown_user_id.toString()] = "does-not-matter";
|
2020-04-03 15:31:17 +02:00
|
|
|
|
2023-04-24 15:57:45 +02:00
|
|
|
blueslip.expect("error", "Unknown user ID in presence data");
|
2020-04-03 15:31:17 +02:00
|
|
|
presence.set_info(presences, now);
|
|
|
|
|
|
|
|
// If the server is suspected to be offline or reloading,
|
|
|
|
// then we suppress errors. The use case here is that we
|
|
|
|
// haven't gotten info for a brand new user yet.
|
2022-07-10 01:06:33 +02:00
|
|
|
watchdog.set_suspect_offline(true);
|
|
|
|
presence.set_info(presences, now);
|
2020-04-03 15:31:17 +02:00
|
|
|
|
2022-07-10 01:06:33 +02:00
|
|
|
watchdog.set_suspect_offline(false);
|
2021-02-24 13:30:27 +01:00
|
|
|
override(reload_state, "is_in_progress", () => true);
|
2020-04-03 15:31:17 +02:00
|
|
|
presence.set_info(presences, now);
|
|
|
|
});
|
|
|
|
|
2021-03-12 13:00:49 +01:00
|
|
|
test("status_from_raw", () => {
|
2020-02-07 14:50:30 +01:00
|
|
|
const status_from_raw = presence.status_from_raw;
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2020-02-07 14:50:30 +01:00
|
|
|
const now = 5000;
|
|
|
|
let raw;
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2020-02-07 14:50:30 +01:00
|
|
|
raw = {
|
|
|
|
server_timestamp: now,
|
|
|
|
active_timestamp: now - OFFLINE_THRESHOLD_SECS / 2,
|
2017-05-24 17:55:31 +02:00
|
|
|
};
|
2020-02-07 14:50:30 +01:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(status_from_raw(raw), {
|
|
|
|
status: "active",
|
|
|
|
last_active: raw.active_timestamp,
|
|
|
|
});
|
2020-02-07 14:50:30 +01:00
|
|
|
|
|
|
|
raw = {
|
|
|
|
server_timestamp: now,
|
|
|
|
active_timestamp: now - OFFLINE_THRESHOLD_SECS * 2,
|
2017-06-17 00:04:27 +02:00
|
|
|
};
|
2020-02-07 14:50:30 +01:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(status_from_raw(raw), {
|
|
|
|
status: "offline",
|
|
|
|
last_active: raw.active_timestamp,
|
|
|
|
});
|
2020-02-07 14:50:30 +01:00
|
|
|
|
|
|
|
raw = {
|
|
|
|
server_timestamp: now,
|
|
|
|
idle_timestamp: now - OFFLINE_THRESHOLD_SECS / 2,
|
2017-06-17 00:04:27 +02:00
|
|
|
};
|
2020-04-03 17:23:56 +02:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(status_from_raw(raw), {
|
|
|
|
status: "idle",
|
|
|
|
last_active: raw.idle_timestamp,
|
|
|
|
});
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2021-03-12 13:00:49 +01:00
|
|
|
test("set_presence_info", () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const presences = {};
|
2020-02-07 14:50:30 +01:00
|
|
|
const now = 5000;
|
|
|
|
const recent = now + 1 - OFFLINE_THRESHOLD_SECS;
|
|
|
|
const a_while_ago = now - OFFLINE_THRESHOLD_SECS * 2;
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2020-02-02 17:29:05 +01:00
|
|
|
presences[alice.user_id.toString()] = {
|
2020-02-07 14:50:30 +01:00
|
|
|
active_timestamp: recent,
|
2017-05-24 17:55:31 +02:00
|
|
|
};
|
|
|
|
|
2020-02-02 17:29:05 +01:00
|
|
|
presences[fred.user_id.toString()] = {
|
2020-02-07 14:50:30 +01:00
|
|
|
active_timestamp: a_while_ago,
|
|
|
|
idle_timestamp: now,
|
2017-05-24 17:55:31 +02:00
|
|
|
};
|
|
|
|
|
2020-02-02 17:29:05 +01:00
|
|
|
presences[me.user_id.toString()] = {
|
2020-02-07 14:50:30 +01:00
|
|
|
active_timestamp: now,
|
|
|
|
};
|
|
|
|
|
|
|
|
presences[sally.user_id.toString()] = {
|
|
|
|
active_timestamp: a_while_ago,
|
2018-09-08 14:25:06 +02:00
|
|
|
};
|
|
|
|
|
2020-05-29 18:38:52 +02:00
|
|
|
presences[john.user_id.toString()] = {
|
|
|
|
idle_timestamp: a_while_ago,
|
|
|
|
};
|
|
|
|
|
|
|
|
presences[jane.user_id.toString()] = {
|
|
|
|
idle_timestamp: now,
|
|
|
|
};
|
|
|
|
|
2020-02-25 12:16:26 +01:00
|
|
|
const params = {};
|
|
|
|
params.presences = presences;
|
2021-05-20 20:01:51 +02:00
|
|
|
params.server_timestamp = now;
|
2020-02-25 12:16:26 +01:00
|
|
|
presence.initialize(params);
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(alice.user_id), {
|
|
|
|
status: "active",
|
|
|
|
last_active: recent,
|
|
|
|
});
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(alice.user_id), "active");
|
2021-02-05 21:20:14 +01:00
|
|
|
assert.deepEqual(presence.last_active_date(alice.user_id), new Date(recent * 1000));
|
2020-07-15 00:34:28 +02:00
|
|
|
|
|
|
|
assert.deepEqual(presence.presence_info.get(fred.user_id), {status: "idle", last_active: now});
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(fred.user_id), "idle");
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(me.user_id), {status: "active", last_active: now});
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(me.user_id), "active");
|
2020-02-07 14:50:30 +01:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(sally.user_id), {
|
|
|
|
status: "offline",
|
|
|
|
last_active: a_while_ago,
|
|
|
|
});
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(sally.user_id), "offline");
|
2018-09-08 14:41:41 +02:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(zoe.user_id), {
|
|
|
|
status: "offline",
|
|
|
|
last_active: undefined,
|
|
|
|
});
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(zoe.user_id), "offline");
|
2020-02-07 14:50:30 +01:00
|
|
|
assert.equal(presence.last_active_date(zoe.user_id), undefined);
|
2017-06-07 18:36:26 +02:00
|
|
|
|
2021-06-10 08:32:54 +02:00
|
|
|
assert.ok(!presence.presence_info.has(bot.user_id));
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(bot.user_id), "offline");
|
2020-05-29 18:38:52 +02:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(john.user_id), {
|
|
|
|
status: "offline",
|
|
|
|
last_active: a_while_ago,
|
|
|
|
});
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(john.user_id), "offline");
|
2020-05-29 18:38:52 +02:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(jane.user_id), {status: "idle", last_active: now});
|
2020-07-15 01:29:15 +02:00
|
|
|
assert.equal(presence.get_status(jane.user_id), "idle");
|
2020-02-07 14:50:30 +01:00
|
|
|
});
|
|
|
|
|
2021-03-12 13:00:49 +01:00
|
|
|
test("falsy values", () => {
|
2020-02-07 14:50:30 +01:00
|
|
|
/*
|
|
|
|
When a user does not have a relevant active timestamp,
|
|
|
|
the server just leaves off the `active_timestamp` field
|
|
|
|
to save bandwidth, which looks like `undefined` to us
|
|
|
|
if we try to dereference it.
|
|
|
|
|
|
|
|
Our code should just treat all falsy values the same way,
|
|
|
|
though, to defend against bugs where we say the person
|
|
|
|
was last online in 1970 or silly things like that.
|
|
|
|
*/
|
|
|
|
const now = 2000000;
|
|
|
|
const a_bit_ago = now - 5;
|
|
|
|
const presences = {};
|
|
|
|
|
|
|
|
for (const falsy_value of [undefined, 0, null]) {
|
|
|
|
presences[zoe.user_id.toString()] = {
|
|
|
|
active_timestamp: falsy_value,
|
|
|
|
idle_timestamp: a_bit_ago,
|
|
|
|
};
|
|
|
|
|
|
|
|
presence.set_info(presences, now);
|
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(zoe.user_id), {
|
|
|
|
status: "idle",
|
|
|
|
last_active: a_bit_ago,
|
|
|
|
});
|
2020-05-29 18:38:52 +02:00
|
|
|
|
|
|
|
presences[zoe.user_id.toString()] = {
|
|
|
|
active_timestamp: falsy_value,
|
|
|
|
idle_timestamp: falsy_value,
|
|
|
|
};
|
|
|
|
|
|
|
|
presence.set_info(presences, now);
|
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(zoe.user_id), {
|
|
|
|
status: "offline",
|
|
|
|
last_active: undefined,
|
|
|
|
});
|
2020-02-07 14:50:30 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-08-04 23:40:48 +02:00
|
|
|
test("big realms", ({override_rewire}) => {
|
2020-02-07 14:50:30 +01:00
|
|
|
const presences = {};
|
|
|
|
const now = 5000;
|
|
|
|
|
|
|
|
presences[sally.user_id.toString()] = {
|
|
|
|
active_timestamp: now,
|
|
|
|
};
|
2017-06-16 01:53:12 +02:00
|
|
|
|
2020-02-07 14:50:30 +01:00
|
|
|
// Make it seem like realm has a lot of people, in
|
|
|
|
// which case we will not provide default values for
|
|
|
|
// users that aren't in our presences payload.
|
2023-08-04 23:40:48 +02:00
|
|
|
override_rewire(people, "get_active_human_count", () => 1000);
|
2020-02-07 14:50:30 +01:00
|
|
|
presence.set_info(presences, now);
|
2021-06-10 08:32:54 +02:00
|
|
|
assert.ok(presence.presence_info.has(sally.user_id));
|
|
|
|
assert.ok(!presence.presence_info.has(zoe.user_id));
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|
2017-05-24 17:55:31 +02:00
|
|
|
|
2021-03-12 13:00:49 +01:00
|
|
|
test("last_active_date", () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const unknown_id = 42;
|
2020-02-06 04:21:07 +01:00
|
|
|
presence.presence_info.clear();
|
2020-07-16 22:40:18 +02:00
|
|
|
presence.presence_info.set(alice.user_id, {last_active: 500});
|
2020-02-06 04:21:07 +01:00
|
|
|
presence.presence_info.set(fred.user_id, {});
|
2017-06-16 01:54:49 +02:00
|
|
|
|
|
|
|
assert.equal(presence.last_active_date(unknown_id), undefined);
|
|
|
|
assert.equal(presence.last_active_date(fred.user_id), undefined);
|
2021-02-05 21:20:14 +01:00
|
|
|
assert.deepEqual(presence.last_active_date(alice.user_id), new Date(500 * 1000));
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|
2017-06-16 01:54:49 +02:00
|
|
|
|
2021-03-12 13:00:49 +01:00
|
|
|
test("update_info_from_event", () => {
|
2020-02-07 14:50:30 +01:00
|
|
|
let info;
|
|
|
|
|
|
|
|
info = {
|
2017-06-17 00:06:21 +02:00
|
|
|
website: {
|
|
|
|
status: "active",
|
2020-02-07 14:50:30 +01:00
|
|
|
timestamp: 500,
|
2017-06-17 00:06:21 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-02-06 04:21:07 +01:00
|
|
|
presence.presence_info.delete(alice.user_id);
|
2020-02-07 14:50:30 +01:00
|
|
|
presence.update_info_from_event(alice.user_id, info, 500);
|
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(alice.user_id), {
|
|
|
|
status: "active",
|
|
|
|
last_active: 500,
|
|
|
|
});
|
2020-02-07 14:50:30 +01:00
|
|
|
|
|
|
|
info = {
|
|
|
|
mobile: {
|
|
|
|
status: "idle",
|
|
|
|
timestamp: 510,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
presence.update_info_from_event(alice.user_id, info, 510);
|
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(alice.user_id), {
|
|
|
|
status: "active",
|
|
|
|
last_active: 510,
|
|
|
|
});
|
2017-06-17 00:06:21 +02:00
|
|
|
|
2020-02-07 14:50:30 +01:00
|
|
|
info = {
|
|
|
|
mobile: {
|
|
|
|
status: "idle",
|
|
|
|
timestamp: 1000,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
presence.update_info_from_event(alice.user_id, info, 1000);
|
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
assert.deepEqual(presence.presence_info.get(alice.user_id), {
|
|
|
|
status: "idle",
|
|
|
|
last_active: 1000,
|
|
|
|
});
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|