mirror of
https://github.com/nextcloud/server.git
synced 2026-06-10 17:23:59 -04:00
test(core): migrate session heartbeat tests
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
688ca81a6e
commit
c3e66e22c7
2 changed files with 123 additions and 87 deletions
|
|
@ -119,93 +119,6 @@ describe('Core base tests', function() {
|
|||
})).toEqual('number=123');
|
||||
});
|
||||
});
|
||||
describe('Session heartbeat', function() {
|
||||
var clock,
|
||||
oldConfig,
|
||||
counter;
|
||||
|
||||
beforeEach(function() {
|
||||
clock = sinon.useFakeTimers();
|
||||
oldConfig = OC.config;
|
||||
counter = 0;
|
||||
|
||||
fakeServer.autoRespond = true;
|
||||
fakeServer.autoRespondAfter = 0;
|
||||
fakeServer.respondWith(/\/csrftoken/, function(xhr) {
|
||||
counter++;
|
||||
xhr.respond(200, {'Content-Type': 'application/json'}, '{"token": "pgBEsb3MzTb1ZPd2mfDZbQ6/0j3OrXHMEZrghHcOkg8=:3khw5PSa+wKQVo4f26exFD3nplud9ECjJ8/Y5zk5/k4="}');
|
||||
});
|
||||
$(document).off('ajaxComplete'); // ignore previously registered heartbeats
|
||||
});
|
||||
afterEach(function() {
|
||||
clock.restore();
|
||||
/* jshint camelcase: false */
|
||||
OC.config = oldConfig;
|
||||
$(document).off('ajaxError');
|
||||
$(document).off('ajaxComplete');
|
||||
});
|
||||
it('sends heartbeat half the session lifetime when heartbeat enabled', function() {
|
||||
/* jshint camelcase: false */
|
||||
OC.config = {
|
||||
session_keepalive: true,
|
||||
session_lifetime: 300
|
||||
};
|
||||
window.initCore();
|
||||
|
||||
expect(counter).toEqual(0);
|
||||
|
||||
// less than half, still nothing
|
||||
clock.tick(100 * 1000);
|
||||
expect(counter).toEqual(0);
|
||||
|
||||
// reach past half (160), one call
|
||||
clock.tick(55 * 1000);
|
||||
expect(counter).toEqual(1);
|
||||
|
||||
// almost there to the next, still one
|
||||
clock.tick(140 * 1000);
|
||||
expect(counter).toEqual(1);
|
||||
|
||||
// past it, second call
|
||||
clock.tick(20 * 1000);
|
||||
expect(counter).toEqual(2);
|
||||
});
|
||||
it('does not send heartbeat when heartbeat disabled', function() {
|
||||
/* jshint camelcase: false */
|
||||
OC.config = {
|
||||
session_keepalive: false,
|
||||
session_lifetime: 300
|
||||
};
|
||||
window.initCore();
|
||||
|
||||
expect(counter).toEqual(0);
|
||||
|
||||
clock.tick(1000000);
|
||||
|
||||
// still nothing
|
||||
expect(counter).toEqual(0);
|
||||
});
|
||||
it('limits the heartbeat between one minute and one day', function() {
|
||||
/* jshint camelcase: false */
|
||||
var setIntervalStub = sinon.stub(window, 'setInterval');
|
||||
OC.config = {
|
||||
session_keepalive: true,
|
||||
session_lifetime: 5
|
||||
};
|
||||
window.initCore();
|
||||
expect(setIntervalStub.getCall(0).args[1]).toEqual(60 * 1000);
|
||||
setIntervalStub.reset();
|
||||
|
||||
OC.config = {
|
||||
session_keepalive: true,
|
||||
session_lifetime: 48 * 3600
|
||||
};
|
||||
window.initCore();
|
||||
expect(setIntervalStub.getCall(0).args[1]).toEqual(24 * 3600 * 1000);
|
||||
|
||||
setIntervalStub.restore();
|
||||
});
|
||||
});
|
||||
describe('Parse query string', function() {
|
||||
it('Parses query string from full URL', function() {
|
||||
var query = OC.parseQueryString('http://localhost/stuff.php?q=a&b=x');
|
||||
|
|
|
|||
123
core/src/tests/OC/session-heartbeat.spec.ts
Normal file
123
core/src/tests/OC/session-heartbeat.spec.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const requestToken = vi.hoisted(() => ({
|
||||
fetchRequestToken: vi.fn<() => Promise<string>>(),
|
||||
setRequestToken: vi.fn<(token: string) => void>(),
|
||||
}))
|
||||
vi.mock('../../OC/requesttoken.ts', () => requestToken)
|
||||
|
||||
const initialState = vi.hoisted(() => ({ loadState: vi.fn() }))
|
||||
vi.mock('@nextcloud/initial-state', () => initialState)
|
||||
|
||||
describe('Session heartbeat', () => {
|
||||
beforeAll(() => {
|
||||
vi.useFakeTimers()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllTimers()
|
||||
vi.resetModules()
|
||||
vi.resetAllMocks()
|
||||
})
|
||||
|
||||
it('sends heartbeat half the session lifetime when heartbeat enabled', async () => {
|
||||
initialState.loadState.mockImplementationOnce(() => ({
|
||||
session_keepalive: true,
|
||||
session_lifetime: 300,
|
||||
}))
|
||||
|
||||
const { initSessionHeartBeat } = await import('../../session-heartbeat.ts')
|
||||
initSessionHeartBeat()
|
||||
|
||||
// initial state loaded
|
||||
expect(initialState.loadState).toBeCalledWith('core', 'config')
|
||||
|
||||
// less than half, still nothing
|
||||
await vi.advanceTimersByTimeAsync(100 * 1000)
|
||||
expect(requestToken.fetchRequestToken).not.toBeCalled()
|
||||
|
||||
// reach past half, one call
|
||||
await vi.advanceTimersByTimeAsync(60 * 1000)
|
||||
expect(requestToken.fetchRequestToken).toBeCalledTimes(1)
|
||||
|
||||
// almost there to the next, still one
|
||||
await vi.advanceTimersByTimeAsync(135 * 1000)
|
||||
expect(requestToken.fetchRequestToken).toBeCalledTimes(1)
|
||||
|
||||
// past it, second call
|
||||
await vi.advanceTimersByTimeAsync(5 * 1000)
|
||||
expect(requestToken.fetchRequestToken).toBeCalledTimes(2)
|
||||
})
|
||||
|
||||
it('does not send heartbeat when heartbeat disabled', async () => {
|
||||
initialState.loadState.mockImplementationOnce(() => ({
|
||||
session_keepalive: false,
|
||||
session_lifetime: 300,
|
||||
}))
|
||||
|
||||
const { initSessionHeartBeat } = await import('../../session-heartbeat.ts')
|
||||
initSessionHeartBeat()
|
||||
|
||||
// initial state loaded
|
||||
expect(initialState.loadState).toBeCalledWith('core', 'config')
|
||||
|
||||
// less than half, still nothing
|
||||
await vi.advanceTimersByTimeAsync(100 * 1000)
|
||||
expect(requestToken.fetchRequestToken).not.toBeCalled()
|
||||
|
||||
// more than one, still nothing
|
||||
await vi.advanceTimersByTimeAsync(300 * 1000)
|
||||
expect(requestToken.fetchRequestToken).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('limit heartbeat to at least one minute', async () => {
|
||||
initialState.loadState.mockImplementationOnce(() => ({
|
||||
session_keepalive: true,
|
||||
session_lifetime: 55,
|
||||
}))
|
||||
|
||||
const { initSessionHeartBeat } = await import('../../session-heartbeat.ts')
|
||||
initSessionHeartBeat()
|
||||
|
||||
// initial state loaded
|
||||
expect(initialState.loadState).toBeCalledWith('core', 'config')
|
||||
|
||||
// 30 / 55 seconds
|
||||
await vi.advanceTimersByTimeAsync(30 * 1000)
|
||||
expect(requestToken.fetchRequestToken).not.toBeCalled()
|
||||
|
||||
// 59 / 55 seconds should not be called except it does not limit
|
||||
await vi.advanceTimersByTimeAsync(29 * 1000)
|
||||
expect(requestToken.fetchRequestToken).not.toBeCalled()
|
||||
|
||||
// now one minute has passed
|
||||
await vi.advanceTimersByTimeAsync(1000)
|
||||
expect(requestToken.fetchRequestToken).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('limit heartbeat to at least one minute', async () => {
|
||||
initialState.loadState.mockImplementationOnce(() => ({
|
||||
session_keepalive: true,
|
||||
session_lifetime: 50 * 60 * 60,
|
||||
}))
|
||||
|
||||
const { initSessionHeartBeat } = await import('../../session-heartbeat.ts')
|
||||
initSessionHeartBeat()
|
||||
|
||||
// initial state loaded
|
||||
expect(initialState.loadState).toBeCalledWith('core', 'config')
|
||||
|
||||
// 23 hours
|
||||
await vi.advanceTimersByTimeAsync(23 * 60 * 60 * 1000)
|
||||
expect(requestToken.fetchRequestToken).not.toBeCalled()
|
||||
|
||||
// one day - it should be called now
|
||||
await vi.advanceTimersByTimeAsync(60 * 60 * 1000)
|
||||
expect(requestToken.fetchRequestToken).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue