zblueslip: Implement tracking extra/lesser blueslip calls.

We change the user facing interface to allow specifying expected
number of error messages (default=1). Now an average test can look
like:

```
    // We expect 3 error messages;
    blueslip.expect('error', 'an error message', 3);
    throwError();
    throwError();
    throwError();
    blueslip.reset();
```
This commit is contained in:
Rohitt Vashishtha
2020-04-20 16:08:24 +05:30
committed by showell
parent 438a545477
commit 0def4a97ae
8 changed files with 64 additions and 20 deletions

View File

@@ -82,13 +82,12 @@ run_test('clear', () => {
});
run_test('undefined_keys', () => {
blueslip.expect('error', 'Tried to call a FoldDict method with an undefined key.');
blueslip.expect('error', 'Tried to call a FoldDict method with an undefined key.', 2);
const d = new FoldDict();
assert.equal(d.has(undefined), false);
assert.strictEqual(d.get(undefined), undefined);
assert.equal(blueslip.get_test_logs('error').length, 2);
blueslip.reset();
});

View File

@@ -15,8 +15,9 @@ run_test('map', () => {
});
run_test('conversions', () => {
blueslip.expect('error', 'not a number');
blueslip.expect('error', 'not a number', 2);
const ls = new LazySet([1, 2]);
ls.add('3');
assert(ls.has('3'));
blueslip.reset();
});

View File

@@ -186,18 +186,16 @@ run_test('errors', () => {
display_recipient: [{id: 92714}],
};
blueslip.expect('error', 'Unknown user_id in get_by_user_id: 92714');
blueslip.expect('error', 'Unknown user id 92714'); // From person.js
blueslip.expect('error', 'Unknown user_id in get_by_user_id: 92714', 2);
blueslip.expect('error', 'Unknown user id 92714', 2); // From person.js
// Expect each to throw two blueslip errors
// One from message_store.js, one from person.js
const emails = message_store.get_pm_emails(message);
assert.equal(emails, '?');
assert.equal(blueslip.get_test_logs('error').length, 2);
const names = message_store.get_pm_full_names(message);
assert.equal(names, '?');
assert.equal(blueslip.get_test_logs('error').length, 4);
blueslip.reset();

View File

@@ -81,12 +81,11 @@ run_test('blueslip', () => {
display_recipient: [],
sender_id: me.user_id,
};
blueslip.expect('error', 'Empty recipient list in message');
blueslip.expect('error', 'Empty recipient list in message', 4);
people.pm_with_user_ids(message);
people.group_pm_with_user_ids(message);
people.all_user_ids_in_pm(message);
assert.equal(people.pm_perma_link(message), undefined);
assert.equal(blueslip.get_test_logs('error').length, 4);
blueslip.reset();
const charles = {

View File

@@ -292,7 +292,7 @@ run_test('subscribers', () => {
blueslip.expect(
'warn',
'We got a is_user_subscribed call for a non-existent or inaccessible stream.');
'We got a is_user_subscribed call for a non-existent or inaccessible stream.', 2);
sub.invite_only = true;
stream_data.update_calculated_fields(sub);
assert.equal(stream_data.is_user_subscribed('Rome', brutus.user_id), undefined);

View File

@@ -72,7 +72,7 @@ run_test('server', () => {
});
run_test('defensive checks', () => {
blueslip.expect('error', 'need ints for user_id');
blueslip.expect('error', 'need ints for user_id', 2);
user_status.set_away('string');
user_status.revoke_away('string');
});

View File

@@ -34,7 +34,7 @@ run_test('basics', () => {
// zblueslip logs all the calls made to it, and they can be used in asserts like:
// Now, let's add our error to the list of expected errors.
blueslip.expect('error', 'world');
blueslip.expect('error', 'world', 2);
// This time, blueslip will just log the error, which is
// being verified by the assert call on the length of the log.
// We can also check for which specific error was logged, but since
@@ -42,13 +42,18 @@ run_test('basics', () => {
// only that error could have been logged, and others would raise
// an error, aborting the test.
throw_an_error();
// The following check is redundant; blueslip.reset() already asserts that
// we got the expected number of errors.
assert.equal(blueslip.get_test_logs('error').length, 2);
// Let's clear the array of valid errors as well as the log. Now, all errors
// should be thrown directly by blueslip.
blueslip.reset();
assert.throws(throw_an_error);
blueslip.reset();
// This call to blueslip.reset() would complain.
assert.throws(() => {
blueslip.reset();
});
// Let's repeat the above procedue with warnings. Unlike errors,
// warnings shouldn't stop the code execution, and thus, the
@@ -59,7 +64,14 @@ run_test('basics', () => {
}
assert.throws(throw_a_warning);
blueslip.reset();
// Again, we do not expect this particular warning so blueslip.reset should complain.
assert.throws(() => {
blueslip.reset();
});
// Let's reset blueslip regardless of errors. This is only for demonstration
// purposes here; do not reset blueslip like this in actual tests.
blueslip.reset(true);
// Now, let's add our warning to the list of expected warnings.
// This time, we shouldn't throw an error. However, to confirm that we
@@ -67,4 +79,12 @@ run_test('basics', () => {
blueslip.expect('warn', 'world');
throw_a_warning();
blueslip.reset();
// However, we detect when we have more or less of the expected errors/warnings.
blueslip.expect('warn', 'world');
assert.throws(() => {
blueslip.reset();
});
// Again, forcefully reset blueslip.
blueslip.reset(true);
});

View File

@@ -28,16 +28,40 @@ exports.make_zblueslip = function () {
lib.seen_messages[name] = new Set();
}
lib.expect = (name, message) => {
lib.expect = (name, message, count = 1) => {
if (opts[name] === undefined) {
throw Error('unexpected arg for expect: ' + name);
}
lib.test_data[name].push(message);
if (count <= 0 && Number.isInteger(count)) {
throw Error('expected count should be a positive integer');
}
const obj = {message, count, expected_count: count};
lib.test_data[name].push(obj);
};
lib.check_seen_messages = () => {
for (const name of names) {
for (const message of lib.test_data[name]) {
for (const obj of lib.test_logs[name]) {
const message = obj.message;
const i = lib.test_data[name].findIndex(x => x.message === message);
if (i === -1) {
// Only throw this for message types we want to explicitly track.
// For example, we do not want to throw here for debug messages.
if (opts[name]) {
throw Error (`Unexpected '${name}' message: ${message}`);
}
continue;
}
lib.test_data[name][i].count -= 1;
}
for (const obj of lib.test_data[name]) {
const message = obj.message;
if (obj.count > 0) {
throw Error(`We saw ${obj.count} (expected ${obj.expected_count}) of '${name}': ${message}`);
} else if (obj.count < 0) {
throw Error(`We saw ${obj.expected_count - obj.count} (expected ${obj.expected_count}) of '${name}': ${message}`);
}
if (!lib.seen_messages[name].has(message)) {
throw Error('Never saw: ' + message);
}
@@ -45,8 +69,10 @@ exports.make_zblueslip = function () {
}
};
lib.reset = () => {
lib.check_seen_messages();
lib.reset = (skip_checks = false) => {
if (!skip_checks) {
lib.check_seen_messages();
}
for (const name of names) {
lib.test_data[name] = [];
@@ -81,7 +107,8 @@ exports.make_zblueslip = function () {
}
lib.seen_messages[name].add(message);
lib.test_logs[name].push({message, more_info, stack});
const exact_match_fail = !lib.test_data[name].includes(message);
const matched_error_message = lib.test_data[name].find(x => x.message === message);
const exact_match_fail = !matched_error_message;
if (exact_match_fail) {
const error = Error(`Invalid ${name} message: "${message}".`);
error.blueslip = true;