Skip to content

Commit

Permalink
Chore: Adding preview end and download attempt metrics (#781)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Press authored Apr 27, 2018
1 parent 740181c commit 8166c25
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 8 deletions.
42 changes: 41 additions & 1 deletion src/lib/Preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,16 @@ import {
X_REP_HINT_VIDEO_MP4,
FILE_OPTION_FILE_VERSION_ID
} from './constants';
import { VIEWER_EVENT, ERROR_CODE, PREVIEW_ERROR, PREVIEW_METRIC, LOAD_METRIC } from './events';
import {
VIEWER_EVENT,
ERROR_CODE,
PREVIEW_ERROR,
PREVIEW_METRIC,
LOAD_METRIC,
DURATION_METRIC,
PREVIEW_END_EVENT,
PREVIEW_DOWNLOAD_ATTEMPT_EVENT
} from './events';
import { getClientLogDetails, getISOTime } from './logUtils';
import './Preview.scss';

Expand Down Expand Up @@ -186,6 +195,25 @@ class Preview extends EventEmitter {

// Destroy viewer
if (this.viewer && typeof this.viewer.destroy === 'function') {
// Log a preview end event
if (this.file && this.file.id) {
const previewDurationTag = Timer.createTag(this.file.id, DURATION_METRIC);
const previewDurationTimer = Timer.get(previewDurationTag);
Timer.stop(previewDurationTag);

const event = {
event_name: PREVIEW_END_EVENT,
value: {
duration: previewDurationTimer ? previewDurationTimer.elapsed : null,
viewer_status: this.viewer.getLoadStatus()
},
...this.createLogEvent()
};

Timer.reset(previewDurationTag);
this.emit(PREVIEW_METRIC, event);
}

this.viewer.destroy();
}

Expand Down Expand Up @@ -522,6 +550,14 @@ class Preview extends EventEmitter {
DownloadReachability.downloadWithReachabilityCheck(downloadUrl);
});
}

const downloadAttemptEvent = {
event_name: PREVIEW_DOWNLOAD_ATTEMPT_EVENT,
value: this.viewer ? this.viewer.getLoadStatus() : null,
...this.createLogEvent()
};

this.emit(PREVIEW_METRIC, downloadAttemptEvent);
}

/**
Expand Down Expand Up @@ -793,6 +829,10 @@ class Preview extends EventEmitter {
// Setup loading UI and progress bar
this.ui.showLoadingIndicator();
this.ui.startProgressBar();

// Start the preview duration timer when the user starts to perceive preview's load
const previewDurationTag = Timer.createTag(this.file.id, DURATION_METRIC);
Timer.start(previewDurationTag);
}

/**
Expand Down
66 changes: 59 additions & 7 deletions src/lib/__tests__/Preview-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,21 @@ describe('lib/Preview', () => {
};

stubs.viewer = {
destroy: sandbox.stub()
destroy: sandbox.stub(),
getLoadStatus: sandbox.stub()
};
});

it('should invoke emitLoadMetrics()', () => {
stubs.emitLoadMetrics = sandbox.stub(preview, 'emitLoadMetrics');
preview.destroy();
expect(stubs.emitLoadMetrics).to.be.called;
});

it('should destroy the viewer if it exists', () => {
preview.viewer = {
destroy: undefined
destroy: undefined,
getLoadStatus: sandbox.stub()
};

preview.destroy();
Expand All @@ -93,15 +101,41 @@ describe('lib/Preview', () => {
expect(stubs.viewer.destroy).to.be.called;
});

it('should clear the viewer', () => {
it('should stop the duration timer, reset it, and log a preview end event', () => {
preview.file = {
id: 1
};
stubs.viewer.getLoadStatus.returns('loaded');
sandbox.stub(preview, 'createLogEvent');
const durationTimer = {
elapsed: 7
};

const mockEventObject = {
event_name: 'preview_end',
value: {
duration: durationTimer.elapsed,
viewer_status: 'loaded'
}
};

sandbox.stub(Timer, 'createTag').returns('duration_tag');
sandbox.stub(Timer, 'get').returns(durationTimer);
sandbox.stub(Timer, 'stop');
sandbox.stub(Timer, 'reset');
sandbox.stub(preview, 'emit');
preview.viewer = stubs.viewer;

preview.destroy();
expect(preview.viewer).to.equal(undefined);
expect(Timer.createTag).to.be.called;
expect(Timer.stop).to.be.calledWith('duration_tag');
expect(stubs.viewer.getLoadStatus).to.be.called;
expect(preview.emit).to.be.calledWith(PREVIEW_METRIC, mockEventObject);
});

it('should invoke emitLoadMetrics()', () => {
stubs.emitLoadMetrics = sandbox.stub(preview, 'emitLoadMetrics');
it('should clear the viewer', () => {
preview.destroy();
expect(stubs.emitLoadMetrics).to.be.called;
expect(preview.viewer).to.equal(undefined);
});
});

Expand Down Expand Up @@ -767,13 +801,15 @@ describe('lib/Preview', () => {
preview.viewer = {
getRepresentation: sandbox.stub(),
getAssetPath: sandbox.stub(),
getLoadStatus: sandbox.stub(),
createContentUrlWithAuthParams: sandbox.stub(),
options: {
viewer: {
ASSET: ''
}
}
};
sandbox.stub(preview, 'emit');
sandbox.stub(file, 'canDownload');
sandbox.stub(file, 'shouldDownloadWM');
sandbox.stub(util, 'openUrlInsideIframe');
Expand Down Expand Up @@ -845,6 +881,22 @@ describe('lib/Preview', () => {
expect(DownloadReachability.downloadWithReachabilityCheck).to.be.calledWith(url);
});
});

it('should emit the download attempted metric', () => {
file.canDownload.returns(true);
file.shouldDownloadWM.returns(false);

const url = 'someurl';
util.appendQueryParams.returns(url);

const promise = Promise.resolve({
download_url: url
});

util.get.returns(promise);
preview.download();
expect(preview.emit).to.be.calledWith('preview_metric');
});
});

describe('updateToken()', () => {
Expand Down
5 changes: 5 additions & 0 deletions src/lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ export const LOAD_METRIC = {
fullDocumentLoadTime: 'full_document_load_time' // How long it took to load the document so it could be previewed.
};

export const DURATION_METRIC = 'preview_duration_metric';
// Event fired from preview with preview duration metrics
export const PREVIEW_END_EVENT = 'preview_end';
// Event fired when the user attempts to download the file
export const PREVIEW_DOWNLOAD_ATTEMPT_EVENT = 'preview_download_attempt';
// Events around download reachability
export const DOWNLOAD_REACHABILITY_METRICS = {
NOTIFICATION_SHOWN: 'dl_reachability_notification_shown',
Expand Down
20 changes: 20 additions & 0 deletions src/lib/viewers/BaseViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ import { VIEWER_EVENT, ERROR_CODE, LOAD_METRIC, DOWNLOAD_REACHABILITY_METRICS }
import PreviewError from '../PreviewError';
import Timer from '../Timer';

const VIEWER_STATUSES = {
error: 'error',
loaded: 'loaded',
loading: 'loading'
};

const ANNOTATIONS_JS = 'annotations.js';
const ANNOTATIONS_CSS = 'annotations.css';

Expand Down Expand Up @@ -750,6 +756,20 @@ class BaseViewer extends EventEmitter {
return repStatus;
}

/**
* Returns a string representing the viewer's loading status. Either loading, loaded, or error
*
* @public
* @return {string} A string representing the viewer's load status
*/
getLoadStatus() {
if (this.loaded) {
return this.options.viewer.NAME === 'Error' ? VIEWER_STATUSES.error : VIEWER_STATUSES.loaded;
}

return VIEWER_STATUSES.loading;
}

/**
* Returns if representation status is considered success
*
Expand Down
17 changes: 17 additions & 0 deletions src/lib/viewers/__tests__/BaseViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,23 @@ describe('lib/viewers/BaseViewer', () => {
});
});

describe('getLoadStatus()', () => {
it('should return the correct string based on load status and viewer type', () => {
base.loaded = false;
expect(base.getLoadStatus()).to.equal('loading');

base.loaded = true;
base.options.viewer = {
NAME: 'Error'
};

expect(base.getLoadStatus()).to.equal('error');

base.options.viewer.NAME = 'Dash';
expect(base.getLoadStatus()).to.equal('loaded');
});
});

describe('isRepresentationReady()', () => {
it('should return whether the representation has a successful status', () => {
const representation = {
Expand Down

0 comments on commit 8166c25

Please sign in to comment.