Skip to content

Commit

Permalink
Updating the Fireperf SDK to support tree-shaking by removing side-ef…
Browse files Browse the repository at this point in the history
…fects
  • Loading branch information
jposuna committed Sep 17, 2020
1 parent d094b8c commit 3bba7f3
Show file tree
Hide file tree
Showing 23 changed files with 496 additions and 254 deletions.
166 changes: 89 additions & 77 deletions packages-exp/performance-exp/src/controllers/perf.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
import { expect } from 'chai';
import { stub } from 'sinon';
import { PerformanceController } from '../controllers/perf';
import { Trace } from '../resources/trace';
import { Api, setupApi } from '../services/api_service';
import { FirebaseApp } from '@firebase/app-types-exp';
import * as initializationService from '../services/initialization_service';
import * as FirebaseUtil from '@firebase/util';
import { SettingsService } from '../services/settings_service';
import { consoleLogger } from '../utils/console_logger';
import { FirebaseApp } from '@firebase/app-types-exp';
import { _FirebaseInstallationsInternal } from '@firebase/installations-types-exp';
import '../../test/setup';

describe('Firebase Performance Test', () => {
Expand All @@ -43,95 +43,107 @@ describe('Firebase Performance Test', () => {
options: fakeFirebaseConfig
} as unknown) as FirebaseApp;

const fakeInstallations = ({} as unknown) as _FirebaseInstallationsInternal;

describe('#constructor', () => {
it('does not initialize performance if the required apis are not available', () => {
stub(Api.prototype, 'requiredApisAvailable').returns(false);
stub(initializationService, 'getInitializationPromise');
new PerformanceController(fakeFirebaseApp);
expect(initializationService.getInitializationPromise).not.be.called;
});
it('does not initialize performance if validateIndexedDBOpenable return false', async () => {
stub(Api.prototype, 'requiredApisAvailable').returns(true);
const validateStub = stub(
FirebaseUtil,
'validateIndexedDBOpenable'
).resolves(false);
stub(initializationService, 'getInitializationPromise');
new PerformanceController(fakeFirebaseApp);
await validateStub;
expect(initializationService.getInitializationPromise).not.be.called;
});

it('does not initialize performance if validateIndexedDBOpenable throws an error', async () => {
stub(Api.prototype, 'requiredApisAvailable').returns(true);
const validateStub = stub(
FirebaseUtil,
'validateIndexedDBOpenable'
).rejects();

stub(initializationService, 'getInitializationPromise');
stub(consoleLogger, 'info');
new PerformanceController(fakeFirebaseApp);
try {
await validateStub;
expect(initializationService.getInitializationPromise).not.be.called;
expect(consoleLogger.info).be.called;
} catch (ignored) {}
});
});
const performanceController = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);
performanceController._init();

describe('#trace', () => {
it('creates a custom trace', () => {
const controller = new PerformanceController(fakeFirebaseApp);
const myTrace = controller.trace('myTrace');

expect(myTrace).to.be.instanceOf(Trace);
});

it('custom trace has the correct name', () => {
const controller = new PerformanceController(fakeFirebaseApp);
const myTrace = controller.trace('myTrace');

expect(myTrace.name).is.equal('myTrace');
});

it('custom trace is not auto', () => {
const controller = new PerformanceController(fakeFirebaseApp);
const myTrace = controller.trace('myTrace');

expect(myTrace.isAuto).is.equal(false);
expect(initializationService.getInitializationPromise).not.be.called;
expect(consoleLogger.info).be.called;
});
});

describe('#instrumentationEnabled', () => {
it('sets instrumentationEnabled to enabled', async () => {
const controller = new PerformanceController(fakeFirebaseApp);

controller.instrumentationEnabled = true;
expect(controller.instrumentationEnabled).is.equal(true);
describe('#settings', () => {
it('applies the settings if provided', async () => {
const settings = {
instrumentationEnabled: false,
dataCollectionEnabled: false
};

const performance = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);
performance._init(settings);

expect(performance.instrumentationEnabled).is.equal(false);
expect(performance.dataCollectionEnabled).is.equal(false);
});

it('sets instrumentationEnabled to disabled', async () => {
const controller = new PerformanceController(fakeFirebaseApp);

controller.instrumentationEnabled = false;
expect(controller.instrumentationEnabled).is.equal(false);
it('uses defaults when settings are not provided', async () => {
const expectedInstrumentationEnabled = SettingsService.getInstance()
.instrumentationEnabled;
const expectedDataCollectionEnabled = SettingsService.getInstance()
.dataCollectionEnabled;

const performance = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);
performance._init();

expect(performance.instrumentationEnabled).is.equal(
expectedInstrumentationEnabled
);
expect(performance.dataCollectionEnabled).is.equal(
expectedDataCollectionEnabled
);
});
});

describe('#dataCollectionEnabled', () => {
it('sets dataCollectionEnabled to enabled', async () => {
const controller = new PerformanceController(fakeFirebaseApp);

controller.dataCollectionEnabled = true;
expect(controller.dataCollectionEnabled).is.equal(true);
describe('#instrumentationEnabled', () => {
it('sets instrumentationEnabled to enabled', async () => {
const performance = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);
performance._init();

performance.instrumentationEnabled = true;
expect(performance.instrumentationEnabled).is.equal(true);
});

it('sets instrumentationEnabled to disabled', async () => {
const performance = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);
performance._init();

performance.instrumentationEnabled = false;
expect(performance.instrumentationEnabled).is.equal(false);
});
});

it('sets dataCollectionEnabled to disabled', () => {
const controller = new PerformanceController(fakeFirebaseApp);

controller.dataCollectionEnabled = false;
expect(controller.dataCollectionEnabled).is.equal(false);
describe('#dataCollectionEnabled', () => {
it('sets dataCollectionEnabled to enabled', async () => {
const performance = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);
performance._init();

performance.dataCollectionEnabled = true;
expect(performance.dataCollectionEnabled).is.equal(true);
});

it('sets dataCollectionEnabled to disabled', () => {
const performance = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);
performance._init();

performance.dataCollectionEnabled = false;
expect(performance.dataCollectionEnabled).is.equal(false);
});
});
});
});
48 changes: 37 additions & 11 deletions packages-exp/performance-exp/src/controllers/perf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,66 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Trace } from '../resources/trace';

import { setupOobResources } from '../services/oob_resources_service';
import { SettingsService } from '../services/settings_service';
import { getInitializationPromise } from '../services/initialization_service';
import { Api } from '../services/api_service';
import { FirebaseApp } from '@firebase/app-types-exp';
import { FirebasePerformance } from '@firebase/performance-types-exp';
import { setupTransportService } from '../services/transport_service';
import { _FirebaseInstallationsInternal } from '@firebase/installations-types-exp';
import {
PerformanceSettings,
FirebasePerformance
} from '@firebase/performance-types-exp';
import { validateIndexedDBOpenable } from '@firebase/util';
import { setupTransportService } from '../services/transport_service';
import { consoleLogger } from '../utils/console_logger';

export class PerformanceController implements FirebasePerformance {
constructor(readonly app: FirebaseApp) {
constructor(
readonly app: FirebaseApp,
readonly installations: _FirebaseInstallationsInternal
) {}

/**
* This method *must* be called internally as part of creating a
* PerformanceController instance.
*
* Currently it's not possible to pass the settings object through the
* constructor using Components, so this method exists to be called with the
* desired settings, to ensure nothing is collected without the user's
* consent.
*/
_init(settings?: PerformanceSettings): void {
if (settings?.dataCollectionEnabled !== undefined) {
this.dataCollectionEnabled = settings.dataCollectionEnabled;
}
if (settings?.instrumentationEnabled !== undefined) {
this.instrumentationEnabled = settings.instrumentationEnabled;
}

if (Api.getInstance().requiredApisAvailable()) {
validateIndexedDBOpenable()
.then(isAvailable => {
if (isAvailable) {
setupTransportService();
getInitializationPromise().then(
setupOobResources,
setupOobResources
getInitializationPromise(this).then(
() => setupOobResources(this),
() => setupOobResources(this)
);
}
})
.catch(error => {
consoleLogger.info(`Environment doesn't support IndexedDB: ${error}`);
});
} else {
consoleLogger.info(
'Firebase Performance cannot start if the browser does not support ' +
'"Fetch" and "Promise", or cookies are disabled.'
);
}
}

trace(name: string): Trace {
return new Trace(name);
}

set instrumentationEnabled(val: boolean) {
SettingsService.getInstance().instrumentationEnabled = val;
}
Expand Down
16 changes: 10 additions & 6 deletions packages-exp/performance-exp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
*/

import { FirebaseApp } from '@firebase/app-types-exp';
import { FirebasePerformance } from '@firebase/performance-types-exp';
import {
FirebasePerformance,
PerformanceSettings
} from '@firebase/performance-types-exp';
import { ERROR_FACTORY, ErrorCode } from './utils/errors';
import { setupApi } from './services/api_service';
import { PerformanceController } from './controllers/perf';
Expand All @@ -31,14 +34,17 @@ import {
Component,
ComponentType
} from '@firebase/component';
import { SettingsService } from './services/settings_service';
import { name, version } from '../package.json';

const DEFAULT_ENTRY_NAME = '[DEFAULT]';

export function getPerformance(app: FirebaseApp): FirebasePerformance {
export function getPerformance(
app: FirebaseApp,
settings?: PerformanceSettings
): FirebasePerformance {
const provider = _getProvider(app, 'performance-exp');
const perfInstance = provider.getImmediate() as PerformanceController;
perfInstance._init(settings);
return perfInstance;
}

Expand All @@ -58,9 +64,7 @@ const factory: InstanceFactory<'performance-exp'> = (
throw ERROR_FACTORY.create(ErrorCode.NO_WINDOW);
}
setupApi(window);
SettingsService.getInstance().firebaseAppInstance = app;
SettingsService.getInstance().installationsService = installations;
return new PerformanceController(app);
return new PerformanceController(app, installations);
};

export function registerPerformance(): void {
Expand Down
18 changes: 16 additions & 2 deletions packages-exp/performance-exp/src/resources/network_request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,24 @@ import { expect } from 'chai';
import { Api, setupApi } from '../services/api_service';
import * as perfLogger from '../services/perf_logger';

import { FirebaseApp } from '@firebase/app-types-exp';
import { PerformanceController } from '../controllers/perf';
import { FirebaseInstallations } from '@firebase/installations-types';
import '../../test/setup';

describe('Firebase Performance > network_request', () => {
setupApi(window);

const fakeFirebaseApp = ({
options: {}
} as unknown) as FirebaseApp;

const fakeInstallations = ({} as unknown) as FirebaseInstallations;
const performanceController = new PerformanceController(
fakeFirebaseApp,
fakeInstallations
);

beforeEach(() => {
stub(Api.prototype, 'getTimeOrigin').returns(1528521843799.5032);
stub(perfLogger, 'logNetworkRequest');
Expand All @@ -46,14 +59,15 @@ describe('Firebase Performance > network_request', () => {
} as unknown) as PerformanceResourceTiming;

const EXPECTED_NETWORK_REQUEST = {
performanceController,
url: 'http://some.test.website.com',
responsePayloadBytes: 500,
startTimeUs: 1528523489152135,
timeToResponseInitiatedUs: 7611,
timeToResponseCompletedUs: 8200
};

createNetworkRequestEntry(PERFORMANCE_ENTRY);
createNetworkRequestEntry(performanceController, PERFORMANCE_ENTRY);

expect(
(perfLogger.logNetworkRequest as any).calledWith(
Expand All @@ -70,7 +84,7 @@ describe('Firebase Performance > network_request', () => {
responseEnd: 1645360.832443
} as unknown) as PerformanceResourceTiming;

createNetworkRequestEntry(PERFORMANCE_ENTRY);
createNetworkRequestEntry(performanceController, PERFORMANCE_ENTRY);

expect(perfLogger.logNetworkRequest).to.not.have.been.called;
});
Expand Down
Loading

0 comments on commit 3bba7f3

Please sign in to comment.