Skip to content

Commit

Permalink
Adds performance monitoring triggers to v2 alerts (#1223)
Browse files Browse the repository at this point in the history
* rebasing master

* add return to app distro

* merge changelog

* yank trace

* add alert type to index

* add link into tsdoc

* fix get opts

* linter

* lineup with master

* linter

* adding logic to convert a payload to api council spec

* fix wording of optional fields
  • Loading branch information
colerogers committed Sep 14, 2022
1 parent 7783ae6 commit c18e832
Show file tree
Hide file tree
Showing 13 changed files with 410 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
@@ -0,0 +1 @@
- Add performance monitoring triggers to v2 alerts (#1223).
4 changes: 4 additions & 0 deletions package.json
Expand Up @@ -64,6 +64,7 @@
"./v2/alerts/appDistribution": "./lib/v2/providers/alerts/appDistribution.js",
"./v2/alerts/billing": "./lib/v2/providers/alerts/billing.js",
"./v2/alerts/crashlytics": "./lib/v2/providers/alerts/crashlytics.js",
"./v2/alerts/performance": "./lib/v2/providers/alerts/performance.js",
"./v2/eventarc": "./lib/v2/providers/eventarc.js",
"./v2/identity": "./lib/v2/providers/identity.js",
"./v2/database": "./lib/v2/providers/database.js",
Expand Down Expand Up @@ -125,6 +126,9 @@
"v2/alerts/crashlytics": [
"lib/v2/providers/alerts/crashlytics"
],
"v2/alerts/performance": [
"lib/v2/providers/alerts/performance"
],
"v2/base": [
"lib/v2/base"
],
Expand Down
2 changes: 1 addition & 1 deletion spec/runtime/manifest.spec.ts
@@ -1,5 +1,5 @@
import { stackToWire, ManifestStack } from '../../src/runtime/manifest';
import { expect } from 'chai';
import { ManifestStack, stackToWire } from '../../src/runtime/manifest';
import * as params from '../../src/v2/params';

describe('stackToWire', () => {
Expand Down
168 changes: 168 additions & 0 deletions spec/v2/providers/alerts/performance.spec.ts
@@ -0,0 +1,168 @@
import { expect } from 'chai';
import * as alerts from '../../../../src/v2/providers/alerts';
import * as performance from '../../../../src/v2/providers/alerts/performance';
import { FULL_ENDPOINT, FULL_OPTIONS } from '../fixtures';

const APPID = '123456789';
const myHandler = () => 42;

const APP_EVENT_FILTER = {
appid: APPID,
};

describe('performance', () => {
describe('onThresholdAlertPublished', () => {
it('should create a function with alertType & appId', () => {
const func = performance.onThresholdAlertPublished(APPID, myHandler);

expect(func.__endpoint).to.deep.equal({
platform: 'gcfv2',
labels: {},
eventTrigger: {
eventType: alerts.eventType,
eventFilters: {
...APP_EVENT_FILTER,
alerttype: performance.thresholdAlert,
},
retry: false,
},
});
});

it('should create a function with opts', () => {
const func = performance.onThresholdAlertPublished(
{ ...FULL_OPTIONS },
myHandler
);

expect(func.__endpoint).to.deep.equal({
...FULL_ENDPOINT,
eventTrigger: {
eventType: alerts.eventType,
eventFilters: {
alerttype: performance.thresholdAlert,
},
retry: false,
},
});
});

it('should create a function with appid in opts', () => {
const func = performance.onThresholdAlertPublished(
{ ...FULL_OPTIONS, appId: APPID },
myHandler
);

expect(func.__endpoint).to.deep.equal({
...FULL_ENDPOINT,
eventTrigger: {
eventType: alerts.eventType,
eventFilters: {
...APP_EVENT_FILTER,
alerttype: performance.thresholdAlert,
},
retry: false,
},
});
});

it('should create a function without opts or appId', () => {
const func = performance.onThresholdAlertPublished(myHandler);

expect(func.__endpoint).to.deep.equal({
platform: 'gcfv2',
labels: {},
eventTrigger: {
eventType: alerts.eventType,
eventFilters: {
alerttype: performance.thresholdAlert,
},
retry: false,
},
});
});

it('should create a function with a run method', () => {
const func = performance.onThresholdAlertPublished(
APPID,
(event) => event
);

const res = func.run('input' as any);

expect(res).to.equal('input');
});
});

describe('getOptsAndApp', () => {
it('should parse a string', () => {
const [opts, appId] = performance.getOptsAndApp(APPID);

expect(opts).to.deep.equal({});
expect(appId).to.equal(APPID);
});

it('should parse an options object without appId', () => {
const myOpts: performance.PerformanceOptions = {
region: 'us-west1',
};

const [opts, appId] = performance.getOptsAndApp(myOpts);

expect(opts).to.deep.equal({ region: 'us-west1' });
expect(appId).to.be.undefined;
});

it('should parse an options object with appId', () => {
const myOpts: performance.PerformanceOptions = {
appId: APPID,
region: 'us-west1',
};

const [opts, appId] = performance.getOptsAndApp(myOpts);

expect(opts).to.deep.equal({ region: 'us-west1' });
expect(appId).to.equal(APPID);
});
});

describe('convertPayload', () => {
it('should return the same payload', () => {
const payload = {
a: 'b',
conditionPercentile: 23,
appVersion: '3',
};

const convertedPayload = performance.convertPayload(payload as any);

expect(convertedPayload).to.deep.eq(payload);
});

it('should return the same payload if the fields are undefined', () => {
const payload = {
a: 'b',
};

const convertedPayload = performance.convertPayload(payload as any);

expect(convertedPayload).to.deep.eq({
a: 'b',
});
});

it('should remove fields', () => {
const payload = {
a: 'b',
conditionPercentile: 0,
appVersion: '',
};

const convertedPayload = performance.convertPayload(payload as any);

expect(convertedPayload).to.deep.eq({
a: 'b',
});
});
});
});
4 changes: 2 additions & 2 deletions src/runtime/manifest.ts
Expand Up @@ -102,8 +102,8 @@ export interface ManifestStack {
* @internal
*/
export function stackToWire(stack: ManifestStack): Object {
let wireStack = stack as any;
let traverse = function traverse(obj: Object) {
const wireStack = stack as any;
const traverse = function traverse(obj: Object) {
for (const [key, val] of Object.entries(obj)) {
if (val instanceof Expression) {
obj[key] = val.toCEL();
Expand Down
4 changes: 2 additions & 2 deletions src/v2/params/index.ts
Expand Up @@ -27,14 +27,14 @@

import {
BooleanParam,
Expression,
FloatParam,
IntParam,
ListParam,
Param,
ParamOptions,
StringParam,
SecretParam,
Expression,
StringParam,
} from './types';

export { ParamOptions, Expression };
Expand Down
8 changes: 4 additions & 4 deletions src/v2/params/types.ts
Expand Up @@ -46,7 +46,7 @@ export abstract class Expression<
function quoteIfString<T extends string | number | boolean | string[]>(
literal: T
): T {
//TODO(vsfan@): CEL's string escape semantics are slightly different than Javascript's, what do we do here?
// TODO(vsfan@): CEL's string escape semantics are slightly different than Javascript's, what do we do here?
return typeof literal === 'string' ? (`"${literal}"` as T) : literal;
}

Expand Down Expand Up @@ -171,14 +171,14 @@ export interface SelectOptions<T = unknown> {
value: T;
}

export type ParamSpec<T = unknown> = {
export interface ParamSpec<T = unknown> {
name: string;
default?: T;
label?: string;
description?: string;
type: ParamValueType;
input?: ParamInput<T>;
};
}

export type ParamOptions<T = unknown> = Omit<ParamSpec<T>, 'name' | 'type'>;

Expand Down Expand Up @@ -219,8 +219,8 @@ export abstract class Param<
}

export class SecretParam {
name: string;
static type: ParamValueType = 'secret';
name: string;

constructor(name: string) {
this.name = name;
Expand Down
1 change: 1 addition & 0 deletions src/v2/providers/alerts/alerts.ts
Expand Up @@ -70,6 +70,7 @@ export type AlertType =
| 'billing.automatedPlanUpdate'
| 'appDistribution.newTesterIosDevice'
| 'appDistribution.inAppFeedback'
| 'performance.threshold'
| string;

/**
Expand Down
2 changes: 1 addition & 1 deletion src/v2/providers/alerts/appDistribution.ts
Expand Up @@ -27,8 +27,8 @@

import { CloudEvent, CloudFunction } from '../../core';
import * as options from '../../options';
import { FirebaseAlertData, getEndpointAnnotation } from './alerts';
import { Expression } from '../../params';
import { FirebaseAlertData, getEndpointAnnotation } from './alerts';

/**
* The internal payload object for adding a new tester device to app distribution.
Expand Down
3 changes: 2 additions & 1 deletion src/v2/providers/alerts/index.ts
Expand Up @@ -30,6 +30,7 @@
import * as appDistribution from './appDistribution';
import * as billing from './billing';
import * as crashlytics from './crashlytics';
import * as performance from './performance';

export { appDistribution, billing, crashlytics };
export { appDistribution, billing, crashlytics, performance };
export * from './alerts';

0 comments on commit c18e832

Please sign in to comment.