mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	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:
		
				
					committed by
					
						
						showell
					
				
			
			
				
	
			
			
			
						parent
						
							438a545477
						
					
				
				
					commit
					0def4a97ae
				
			@@ -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();
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 = {
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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');
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user