Skip to content

Commit

Permalink
merge master + add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Bamieh committed Nov 6, 2019
2 parents 4436f3f + 17383b8 commit 2715b43
Show file tree
Hide file tree
Showing 36 changed files with 740 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
EuiPagination,
EuiText,
EuiSpacer,
EuiIcon,
} from '@elastic/eui';

import { i18n } from '@kbn/i18n';
Expand Down Expand Up @@ -116,8 +117,6 @@ export const SavedQueryManagementComponent: FunctionComponent<Props> = ({

const savedQueryPopoverButton = (
<EuiButtonEmpty
iconType="arrowDown"
iconSide="right"
onClick={() => {
setIsOpen(!isOpen);
}}
Expand All @@ -129,7 +128,8 @@ export const SavedQueryManagementComponent: FunctionComponent<Props> = ({
})}
data-test-subj="saved-query-management-popover-button"
>
#
<EuiIcon type="save" className="euiQuickSelectPopover__buttonText" />
<EuiIcon type="arrowDown" />
</EuiButtonEmpty>
);

Expand Down
17 changes: 15 additions & 2 deletions src/legacy/core_plugins/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,13 @@ const telemetry = (kibana: any) => {
},
},
async replaceInjectedVars(originalInjectedVars: any, request: any) {
const currentKibanaVersion = getCurrentKibanaVersion(request.server);
const telemetryInjectedVars = await replaceTelemetryInjectedVars(
originalInjectedVars,
request
request,
currentKibanaVersion
);

return {
...originalInjectedVars,
...telemetryInjectedVars,
Expand All @@ -103,7 +106,13 @@ const telemetry = (kibana: any) => {
mappings,
},
init(server: Server, kibanaConfig: any) {
const initializerContext = {} as PluginInitializerContext;
const initializerContext = {
env: {
packageInfo: {
version: getCurrentKibanaVersion(server),
},
},
} as PluginInitializerContext;

const coreSetup = ({
http: { server },
Expand All @@ -125,3 +134,7 @@ const telemetry = (kibana: any) => {

// eslint-disable-next-line import/no-default-export
export default telemetry;

function getCurrentKibanaVersion(server: Server): string {
return server.config().get('pkg.version');
}
3 changes: 3 additions & 0 deletions src/legacy/core_plugins/telemetry/mappings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
},
"lastReported": {
"type": "date"
},
"lastVersionChecked": {
"type": "keyword"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/legacy/core_plugins/telemetry/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ export { replaceTelemetryInjectedVars } from './replace_injected_vars';
export { telemetryCollectionManager } from './collection_manager';

export const telemetryPlugin = (initializerContext: PluginInitializerContext) =>
new TelemetryPlugin();
new TelemetryPlugin(initializerContext);
export { constants };
11 changes: 9 additions & 2 deletions src/legacy/core_plugins/telemetry/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,21 @@
* under the License.
*/

import { CoreSetup } from 'src/core/server';
import { CoreSetup, PluginInitializerContext } from 'src/core/server';
import { registerRoutes } from './routes';
import { telemetryCollectionManager } from './collection_manager';
import { getStats } from './telemetry_collection';

export class TelemetryPlugin {
private readonly currentKibanaVersion: string;

constructor(initializerContext: PluginInitializerContext) {
this.currentKibanaVersion = initializerContext.env.packageInfo.version;
}

public setup(core: CoreSetup) {
const currentKibanaVersion = this.currentKibanaVersion;
telemetryCollectionManager.setStatsGetter(getStats, 'local');
registerRoutes(core);
registerRoutes({ core, currentKibanaVersion });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { getTelemetryOptIn } from './get_telemetry_opt_in';
import { TelemetrySavedObject } from './get_telemetry_saved_object';

describe('getTelemetryOptIn', () => {
it('returns false when request path is not /app*', () => {
const params = getCallGetTelemetryOptInParams({
requestPath: '/foo/bar',
});

const result = callGetTelemetryOptIn(params);

expect(result).toBe(false);
});

it('returns null when saved object not found', () => {
const params = getCallGetTelemetryOptInParams({
savedObjectNotFound: true,
});

const result = callGetTelemetryOptIn(params);

expect(result).toBe(null);
});

it('returns false when saved object forbidden', () => {
const params = getCallGetTelemetryOptInParams({
savedObjectForbidden: true,
});

const result = callGetTelemetryOptIn(params);

expect(result).toBe(false);
});

it('returns null if enabled is null or undefined', () => {
for (const enabled of [null, undefined]) {
const params = getCallGetTelemetryOptInParams({
enabled,
});

const result = callGetTelemetryOptIn(params);

expect(result).toBe(null);
}
});

it('returns true when enabled is true', () => {
const params = getCallGetTelemetryOptInParams({
enabled: true,
});

const result = callGetTelemetryOptIn(params);

expect(result).toBe(true);
});

// build a table of tests with version checks, with results for enabled false
type VersionCheckTable = Array<Partial<CallGetTelemetryOptInParams>>;

const EnabledFalseVersionChecks: VersionCheckTable = [
{ lastVersionChecked: '8.0.0', currentKibanaVersion: '8.0.0', result: false },
{ lastVersionChecked: '8.0.0', currentKibanaVersion: '8.0.1', result: false },
{ lastVersionChecked: '8.0.1', currentKibanaVersion: '8.0.0', result: false },
{ lastVersionChecked: '8.0.0', currentKibanaVersion: '8.1.0', result: null },
{ lastVersionChecked: '8.0.0', currentKibanaVersion: '9.0.0', result: null },
{ lastVersionChecked: '8.0.0', currentKibanaVersion: '7.0.0', result: false },
{ lastVersionChecked: '8.1.0', currentKibanaVersion: '8.0.0', result: false },
{ lastVersionChecked: '8.0.0-X', currentKibanaVersion: '8.0.0', result: false },
{ lastVersionChecked: '8.0.0', currentKibanaVersion: '8.0.0-X', result: false },
{ lastVersionChecked: null, currentKibanaVersion: '8.0.0', result: null },
{ lastVersionChecked: undefined, currentKibanaVersion: '8.0.0', result: null },
{ lastVersionChecked: 5, currentKibanaVersion: '8.0.0', result: null },
{ lastVersionChecked: '8.0.0', currentKibanaVersion: 'beta', result: null },
{ lastVersionChecked: 'beta', currentKibanaVersion: '8.0.0', result: null },
{ lastVersionChecked: 'beta', currentKibanaVersion: 'beta', result: false },
{ lastVersionChecked: 'BETA', currentKibanaVersion: 'beta', result: null },
].map(el => ({ ...el, enabled: false }));

// build a table of tests with version checks, with results for enabled true/null/undefined
const EnabledTrueVersionChecks: VersionCheckTable = EnabledFalseVersionChecks.map(el => ({
...el,
enabled: true,
result: true,
}));

const EnabledNullVersionChecks: VersionCheckTable = EnabledFalseVersionChecks.map(el => ({
...el,
enabled: null,
result: null,
}));

const EnabledUndefinedVersionChecks: VersionCheckTable = EnabledFalseVersionChecks.map(el => ({
...el,
enabled: undefined,
result: null,
}));

const AllVersionChecks = [
...EnabledFalseVersionChecks,
...EnabledTrueVersionChecks,
...EnabledNullVersionChecks,
...EnabledUndefinedVersionChecks,
];

test.each(AllVersionChecks)(
'returns expected result for version check with %j',
async (params: Partial<CallGetTelemetryOptInParams>) => {
const result = await callGetTelemetryOptIn({ ...DefaultParams, ...params });
expect(result).toBe(params.result);
}
);
});

interface CallGetTelemetryOptInParams {
requestPath: string;
savedObjectNotFound: boolean;
savedObjectForbidden: boolean;
enabled: boolean | null | undefined;
lastVersionChecked?: any; // should be a string, but test with non-strings
currentKibanaVersion: string;
result?: boolean | null;
}

const DefaultParams = {
requestPath: '/app/something',
savedObjectNotFound: false,
savedObjectForbidden: false,
enabled: true,
lastVersionChecked: '8.0.0',
currentKibanaVersion: '8.0.0',
};

function getCallGetTelemetryOptInParams(
overrides: Partial<CallGetTelemetryOptInParams>
): CallGetTelemetryOptInParams {
return { ...DefaultParams, ...overrides };
}

function callGetTelemetryOptIn(params: CallGetTelemetryOptInParams) {
const { currentKibanaVersion } = params;
const request = getMockRequest(params);
const telemetrySavedObject = getMockTelemetrySavedObject(params);
return getTelemetryOptIn({ request, currentKibanaVersion, telemetrySavedObject });
}

function getMockTelemetrySavedObject(params: CallGetTelemetryOptInParams): TelemetrySavedObject {
const { savedObjectNotFound, savedObjectForbidden } = params;
if (savedObjectForbidden) {
return false;
}
if (savedObjectNotFound) {
return null;
}

return {
enabled: params.enabled,
lastVersionChecked: params.lastVersionChecked,
};
}

function getMockRequest(params: CallGetTelemetryOptInParams): any {
return {
path: params.requestPath,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,75 @@
* under the License.
*/

export function getTelemetryOptIn(telemetrySavedObject: any, request: any) {
import semver from 'semver';
import { TelemetrySavedObject } from './get_telemetry_saved_object';

interface GetTelemetryOptInConfig {
request: any;
telemetrySavedObject: TelemetrySavedObject;
currentKibanaVersion: string;
}

type GetTelemetryOptIn = (config: GetTelemetryOptInConfig) => null | boolean;

export const getTelemetryOptIn: GetTelemetryOptIn = ({
request,
telemetrySavedObject,
currentKibanaVersion,
}) => {
const isRequestingApplication = request.path.startsWith('/app');

// Prevent interstitial screens (such as the space selector) from prompting for telemetry
if (!isRequestingApplication) {
return false;
}

if (telemetrySavedObject === false || telemetrySavedObject === null) {
return telemetrySavedObject;
if (telemetrySavedObject === false) {
return false;
}

if (telemetrySavedObject === null || telemetrySavedObject.enabled == null) {
return null;
}

return telemetrySavedObject.enabled;
const enabled = !!telemetrySavedObject.enabled;

// if enabled is true, return it
if (enabled === true) return enabled;

// Additional check if they've already opted out (enabled: false):
// - if the Kibana version has changed by at least a minor version,
// return null to re-prompt.

const lastKibanaVersion = telemetrySavedObject.lastVersionChecked;

// if the last kibana version isn't set, or is somehow not a string, return null
if (typeof lastKibanaVersion !== 'string') return null;

// if version hasn't changed, just return enabled value
if (lastKibanaVersion === currentKibanaVersion) return enabled;

const lastSemver = parseSemver(lastKibanaVersion);
const currentSemver = parseSemver(currentKibanaVersion);

// if either version is invalid, return null
if (lastSemver == null || currentSemver == null) return null;

// actual major/minor version comparison, for cases when to return null
if (currentSemver.major > lastSemver.major) return null;
if (currentSemver.major === lastSemver.major) {
if (currentSemver.minor > lastSemver.minor) return null;
}

// current version X.Y is not greater than last version X.Y, return enabled
return enabled;
};

function parseSemver(version: string): semver.SemVer | null {
// semver functions both return nulls AND throw exceptions: "it depends!"
try {
return semver.parse(version);
} catch (err) {
return null;
}
}
Loading

0 comments on commit 2715b43

Please sign in to comment.