Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions InfoLogger/public/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default class Model extends Observable {

this.frameworkInfoEnabled = false;
this.frameworkInfo = RemoteData.notAsked();
this.getFrameworkInfo();
this.frameworkInfoLoaded = this.getFrameworkInfo();

this.inspectorEnabled = false;
this.accountMenuEnabled = false;
Expand All @@ -67,7 +67,6 @@ export default class Model extends Observable {
this.router = new QueryRouter();
this.router.observe(this.handleLocationChange.bind(this));
this.router.bubbleTo(this);
this.handleLocationChange(); // Init first page

// Setup keyboard and wheel dispatchers
window.addEventListener('keydown', this.handleKeyboardDown.bind(this));
Expand All @@ -77,6 +76,10 @@ export default class Model extends Observable {
this.ws = new WebSocketClient();
this.ws.addListener('command', this.handleWSCommand.bind(this));
this.ws.addListener('authed', this.handleWSAuthed.bind(this));
this.wsSettled = new Promise((resolve) => {
this.ws.addListener('authed', resolve);
this.ws.addListener('close', resolve);
});
this.ws.addListener('close', this.handleWSClose.bind(this));

// update router on model change
Expand All @@ -86,6 +89,9 @@ export default class Model extends Observable {

this.zoom = new Zoom();
this.zoom.bubbleTo(this);

// Must run last as live=true awaits frameworkInfoLoaded and wsSettled, so both must exist before the URL is parsed
this.handleLocationChange(); // Init first page
}

/**
Expand Down Expand Up @@ -362,7 +368,7 @@ export default class Model extends Observable {
return;
} else if (params.profile) {
this.getProfile(params.profile);
return;
return; // live=true ignored if a profile is used
} else if (params.q) {
this.getUserProfile();
try {
Expand All @@ -371,10 +377,39 @@ export default class Model extends Observable {
this.log.filter.resetCriteria();
this.updateRouteOnModelChange();
this.notification.show(`Invalid URL filter format: ${error.message}`, 'danger');
return; // don't go live when q is invalid
}
} else {
this.getUserProfile();
}

if (params.live === 'true') {
this.startLiveModeFromURL();
}
}

/**
* Start live mode from URL once dependencies are ready
*/
async startLiveModeFromURL() {
await Promise.all([
this.frameworkInfoLoaded,
this.wsSettled,
]);

if (!this.ws.authed) {
return; // connection lost before auth, handleWSClose has already notified the user
}

if (!this.log.queryResult.isNotAsked()) {
return; // user started a query as framework has loaded but WS not yet
}
if (!this.log.isLiveModeAvailable()) {
this.notification.show('Live mode is currently unavailable, loaded in query mode', 'danger', 3000);
return;
}

this.log.liveStart();
}

/**
Expand Down
50 changes: 50 additions & 0 deletions InfoLogger/test/public/live-mode-mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,25 @@ const test = require('../mocha-index');

const isFieldEmpty = (value) => value === undefined || value === null || value === '';

const getLiveState = (page) => page.evaluate(() => ({
activeMode: window.model.log.activeMode,
className: document.querySelector('#live-button').className,
title: document.title,
autoScroll: window.model.log.autoScrollLive,
search: decodeURIComponent(window.location.search),
}));

describe('Live Mode test-suite', async () => {
let baseUrl = null;
let page = null;
before(async () => {
({ helpers: { baseUrl }, page } = test);
});

after(async () => {
await page.evaluate(() => window.model.log.liveStop());
});

it('should successfully go to homepage with predefined filters', async () => {
await page.goto(baseUrl, { waitUntil: 'networkidle0' });
const location = await page.evaluate(() => window.location);
Expand Down Expand Up @@ -118,6 +130,44 @@ describe('Live Mode test-suite', async () => {
assert.ok(isUserNameMatching);
});

it('should stay in QUERY mode when live=true is combined with an invalid url filter', async () => {
await page.goto(`${baseUrl}?q={"severity":{"in":"E F"}&live=true`, { waitUntil: 'networkidle0' });
const { activeMode, notification } = await page.evaluate(() => ({
activeMode: window.model.log.activeMode,
notification: window.model.notification,
}));

assert.strictEqual(activeMode, 'Query');
assert.strictEqual(notification.type, 'danger');
assert.ok(notification.message.startsWith('Invalid URL filter format'));
});

it('should successfully enable LIVE mode from url parameter with the defined filter', async () => {
await page.goto(`${baseUrl}?q={"severity":{"in":"E F"}}&live=true`, { waitUntil: 'networkidle0' });

const { activeMode, className, search, autoScroll } = await getLiveState(page);

assert.strictEqual(autoScroll, true);
assert.strictEqual(activeMode, 'Running');
assert.strictEqual(className, 'btn bold btn-success active');

// Check if filter is still applied
assert.strictEqual(search, '?q={"severity":{"in":"E F"}}');
});

it('should successfully enable LIVE mode from url parameter with no filter', async () => {
await page.goto(`${baseUrl}?live=true`, { waitUntil: 'networkidle0' });
const { activeMode, className, search, title, autoScroll } = await getLiveState(page);

assert.strictEqual(autoScroll, true);
assert.strictEqual(activeMode, 'Running');
assert.strictEqual(className, 'btn bold btn-success active');

assert.strictEqual(search, '?q={"severity":{"in":"I W E F"}}');

assert.ok(title.endsWith(' LIVE'), `unexpected title: ${title}`);
});

describe('Empty field filters in live mode', async () => {
it('should only receive logs with empty rolename when emptyFor is set to "match"', async () => {
await page.evaluate(() => window.model.log.liveStop('Paused'));
Expand Down
Loading