summaryrefslogtreecommitdiff
path: root/jstests/libs/ingress_handshake_metrics_helpers.js
blob: 6d4f39e1478d26db23c5f64ce70bfb8d4f41a0f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"use strict";

load("jstests/libs/fail_point_util.js");
load('jstests/libs/log.js');
load("jstests/libs/parallel_shell_helpers.js");

function ingressHandshakeMetricsTest(conn, options) {
    // Unpack test options

    const {
        rootCredentials = {user: 'root', pwd: 'root'},
        guestCredentials = {user: 'guest', pwd: 'guest'},
        dbName = 'test',
        collectionName = 'test_coll',
        connectionHealthLoggingOn,
        preAuthDelayMillis,
        postAuthDelayMillis,
        helloProcessingDelayMillis,
        helloResponseDelayMillis,
    } = options;

    const totalDelayMillis = preAuthDelayMillis + postAuthDelayMillis;

    // Define helper functions

    function setupTest() {
        let admin = conn.getDB('admin');
        let db = conn.getDB(dbName);

        admin.createUser(Object.assign(rootCredentials, {roles: jsTest.adminUserRoles}));
        admin.auth(rootCredentials.user, rootCredentials.pwd);

        db.createUser(Object.assign(guestCredentials, {roles: jsTest.readOnlyUserRoles}));
        db[collectionName].insert({foo: 42});

        if (!connectionHealthLoggingOn) {
            assert.commandWorked(conn.adminCommand(
                {setParameter: 1, enableDetailedConnectionHealthMetricLogLines: false}));
        }
    }

    function performAuthTestConnection() {
        let testConn = new Mongo(conn.host);
        let db = testConn.getDB(dbName);
        sleep(preAuthDelayMillis);
        db.auth(guestCredentials.user, guestCredentials.pwd);
        sleep(postAuthDelayMillis);
        db[collectionName].findOne();
    }

    function performHelloTestConnection() {
        let waitInHelloFailPoint =
            configureFailPoint(conn, 'waitInHello', {delayMillis: helloProcessingDelayMillis});
        let delaySendMessageFailPoint = configureFailPoint(
            conn, 'sessionWorkflowDelaySendMessage', {millis: helloResponseDelayMillis});
        let testConn = new Mongo(conn.host);
        delaySendMessageFailPoint.off();
        waitInHelloFailPoint.off();
    }

    function getTotalTimeToFirstNonAuthCommandMillis() {
        let status = assert.commandWorked(conn.adminCommand({serverStatus: 1}));
        printjson(status);
        return status.metrics.network.totalTimeToFirstNonAuthCommandMillis;
    }

    function logLineExists(id, predicate) {
        let serverLog = assert.commandWorked(conn.adminCommand({getLog: "global"})).log;
        for (const line of findMatchingLogLines(serverLog, {id: id})) {
            if (predicate(JSON.parse(line))) {
                return true;
            }
        }
        return false;
    }

    function timingLogLineExists() {
        return logLineExists(6788700, entry => entry.attr.elapsedMillis >= postAuthDelayMillis);
    }

    function helloCompletedLogLineExists() {
        return logLineExists(
            6724100,
            entry => (entry.attr.processingDurationMillis >= helloProcessingDelayMillis) &&
                (entry.attr.sendingDurationMillis >= helloResponseDelayMillis) &&
                (entry.attr.okCode == 1));
    }

    function performAuthMetricsTest() {
        let metricBeforeTest = getTotalTimeToFirstNonAuthCommandMillis();

        performAuthTestConnection();

        if (connectionHealthLoggingOn) {
            assert(timingLogLineExists, "No matching 'first non-auth command' log line");
        } else {
            assert.eq(
                timingLogLineExists(),
                false,
                "Found 'first non-auth command log line' despite disabling connection health logging");
        }

        let metricAfterTest = getTotalTimeToFirstNonAuthCommandMillis();
        assert.gte(metricAfterTest - metricBeforeTest, totalDelayMillis);
    }

    function performHelloMetricsTest() {
        performHelloTestConnection();

        if (connectionHealthLoggingOn) {
            assert(helloCompletedLogLineExists, "No matching 'hello completed' log line");
        } else {
            assert.eq(
                helloCompletedLogLineExists(),
                false,
                "Found 'hello completed' log line despite disabling conection health logging");
        }
    }

    // Setup the test and return the function that will perform the test when called

    setupTest();

    return function() {
        assert.commandWorked(conn.adminCommand({clearLog: 'global'}));
        performAuthMetricsTest();
        performHelloMetricsTest();
    };
}