Skip to content
Merged
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
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pageLoadAssetSize:
canvas: 15210
cases: 153204
charts: 40269
cloud: 9300
cloud: 9676
cloudDataMigration: 5687
cloudExperiments: 103984
cloudFullStory: 4752
Expand Down
21 changes: 19 additions & 2 deletions src/platform/plugins/shared/navigation/public/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,28 @@ describe('Navigation Plugin', () => {
}
});

it('should set the feedback button visibility to "false" for deployment in trial', async () => {
it('should set the feedback button visibility to "false" for deployment in trial via endDate', async () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should set the feedback button visibility to "false" for deployment in trial via endDate', async () => {
it('should set the feedback button visibility to "false" for deployment in trial', async () => {

Seems like we're removing knowledge of "endDate"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, other plugins should just use the function and let the cloud plugin handle all the logic around endDate.

const { plugin, coreStart, unifiedSearch, cloud: cloudStart, spaces } = setup();
const coreSetup = coreMock.createSetup();
const cloudSetup = cloudMock.createSetup();
cloudSetup.trialEndDate = new Date(Date.now() + 1000 * 60 * 60 * 24 * 30); // 30 days from now
cloudSetup.isInTrial.mockReturnValue(true);
plugin.setup(coreSetup, { cloud: cloudSetup });

for (const solution of ['es', 'oblt', 'security']) {
spaces.getActiveSpace$ = jest
.fn()
.mockReturnValue(of({ solution } as Pick<Space, 'solution'>));
plugin.start(coreStart, { unifiedSearch, cloud: cloudStart, spaces });
await new Promise((resolve) => setTimeout(resolve));
expect(coreStart.chrome.sideNav.setIsFeedbackBtnVisible).toHaveBeenCalledWith(false);
coreStart.chrome.sideNav.setIsFeedbackBtnVisible.mockReset();
}
});
it('should set the feedback button visibility to "false" for deployment in trial in serverless', async () => {
const { plugin, coreStart, unifiedSearch, cloud: cloudStart, spaces } = setup();
const coreSetup = coreMock.createSetup();
const cloudSetup = cloudMock.createSetup();
cloudSetup.isInTrial.mockReturnValue(true);
plugin.setup(coreSetup, { cloud: cloudSetup });

for (const solution of ['es', 'oblt', 'security']) {
Expand Down
5 changes: 1 addition & 4 deletions src/platform/plugins/shared/navigation/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ export class NavigationPublicPlugin
public setup(core: CoreSetup, deps: NavigationPublicSetupDependencies): NavigationPublicSetup {
registerNavigationEventTypes(core);

const cloudTrialEndDate = deps.cloud?.trialEndDate;
if (cloudTrialEndDate) {
this.isCloudTrialUser = cloudTrialEndDate.getTime() > Date.now();
}
this.isCloudTrialUser = deps.cloud?.isInTrial() ?? false;

return {
registerMenuItem: this.topNavMenuExtensionsRegistry.register.bind(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
type Logger,
} from '@kbn/core/server';
import type { InterceptSetup, InterceptStart } from '@kbn/intercepts-plugin/server';
import type { CloudSetup } from '@kbn/cloud-plugin/server';
import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server';
import {
TRIGGER_DEF_ID,
UPGRADE_TRIGGER_DEF_PREFIX_ID,
Expand All @@ -22,11 +22,12 @@ import {
import type { ServerConfigSchema } from '../common/config';

interface ProductInterceptServerPluginSetup {
cloud: CloudSetup;
cloud?: CloudSetup;
intercepts: InterceptSetup;
}

interface ProductInterceptServerPluginStart {
cloud?: CloudStart;
intercepts: InterceptStart;
}

Expand All @@ -39,7 +40,6 @@ export class ProductInterceptServerPlugin
private readonly logger: Logger;
private readonly config: ServerConfigSchema;
private readonly buildVersion: string;
private trialEndDate?: Date;

constructor(initContext: PluginInitializerContext<unknown>) {
this.logger = initContext.logger.get();
Expand All @@ -48,12 +48,10 @@ export class ProductInterceptServerPlugin
}

setup(core: CoreSetup, { cloud }: ProductInterceptServerPluginSetup) {
this.trialEndDate = cloud?.trialEndDate;

return {};
}

start(core: CoreStart, { intercepts }: ProductInterceptServerPluginStart) {
start(core: CoreStart, { cloud, intercepts }: ProductInterceptServerPluginStart) {
if (this.config.enabled) {
void intercepts.registerTriggerDefinition?.(TRIGGER_DEF_ID, () => {
this.logger.debug('Registering global product intercept trigger definition');
Expand All @@ -69,7 +67,7 @@ export class ProductInterceptServerPlugin
);

// Register trial intercept only if the trial end date is set and not passed
if (Date.now() <= (this.trialEndDate?.getTime() ?? 0)) {
if (cloud?.isInTrial()) {
void intercepts.registerTriggerDefinition?.(
`${TRIAL_TRIGGER_DEF_ID}:${this.buildVersion}`,
() => {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/platform/plugins/shared/cloud/public/mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function createSetupMock(): jest.Mocked<CloudSetup> {
},
getUrls: jest.fn().mockReturnValue({}),
getPrivilegedUrls: jest.fn().mockResolvedValue({}),
isInTrial: jest.fn().mockReturnValue(false),
...mockCloudUrls,
};
}
Expand All @@ -61,6 +62,7 @@ const createStartMock = (): jest.Mocked<CloudStart> => ({
fetchElasticsearchConfig: jest.fn().mockResolvedValue({ elasticsearchUrl: 'elasticsearch-url' }),
getUrls: jest.fn().mockReturnValue({}),
getPrivilegedUrls: jest.fn().mockResolvedValue({}),
isInTrial: jest.fn().mockReturnValue(false),
...mockCloudUrls,
});

Expand Down
163 changes: 119 additions & 44 deletions x-pack/platform/plugins/shared/cloud/public/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,42 +163,83 @@ describe('Cloud Plugin', () => {
});
expect(setup.isServerlessEnabled).toBe(false);
});
});

it('exposes `serverless.projectId`', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
},
it('exposes `serverless.projectId`', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
},
});
expect(setup.serverless.projectId).toBe('my-awesome-project');
});
expect(setup.serverless.projectId).toBe('my-awesome-project');
});

it('exposes `serverless.projectName`', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
project_name: 'My Awesome Project',
},
it('exposes `serverless.projectName`', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
project_name: 'My Awesome Project',
},
});
expect(setup.serverless.projectName).toBe('My Awesome Project');
});
expect(setup.serverless.projectName).toBe('My Awesome Project');
});

it('exposes `serverless.projectType`', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
project_name: 'My Awesome Project',
project_type: 'security',
},
it('exposes `serverless.projectType`', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
project_name: 'My Awesome Project',
project_type: 'security',
},
});
expect(setup.serverless.projectType).toBe('security');
});
describe('exposes isInTrial', () => {
it('is `true` when `serverless.in_trial` is set', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
in_trial: true,
},
});

expect(setup.isInTrial()).toBe(true);
});
it('is `false` when `serverless.in_trial` is set to false', () => {
const { setup } = setupPlugin({
serverless: {
project_id: 'my-awesome-project',
in_trial: false,
},
});
expect(setup.isInTrial()).toBe(false);
});
});
expect(setup.serverless.projectType).toBe('security');
});

it('exposes fetchElasticsearchConfig', async () => {
const { setup } = setupPlugin();
const result = await setup.fetchElasticsearchConfig();
expect(result).toEqual({ elasticsearchUrl: 'elasticsearch-url' });
});
describe('exposes isInTrial', () => {
it('is `true` when `trial_end_date` is set and is in the future', () => {
const { setup } = setupPlugin({
trial_end_date: new Date(Date.now() + 10000).toISOString(),
});

expect(setup.isInTrial()).toBe(true);
});
it('is `false` when `trial_end_date` is set and is in the past', () => {
const { setup } = setupPlugin({
trial_end_date: new Date(Date.now() - 10000).toISOString(),
});

expect(setup.isInTrial()).toBe(false);
});
it('is `false` when `serverless.in_trial` & `trial_end_date` are not set', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when both serverless.in_trial and trial_end_date are set? IMO we should throw and remove all serverless.in_trial test cases from this set of tests and scope those to the serverless:true config tests below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jloleysens serverless.in_trial will override any trial_end_date for the purpose of getInTrial.

I will remove all serverless.in_trial case from here.

I can add code to throw if both are set, but that makes me a little uneasy since both of these config values are set from other systems. I feel like it's more likely someone will break Kibana unwittingly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove all serverless.in_trial test cases from this set of tests and scope those to the serverless:true config tests below.

The tests below are testing the start interface. These tests are testing setup. Technically we're exposing the same function, but I'd prefer to have the function tests for both contracts.

I will move the serverless.in_trial test cases into the is serverless enabled section.

const { setup } = setupPlugin({});
expect(setup.isInTrial()).toBe(false);
});
});
});
});

Expand Down Expand Up @@ -300,30 +341,31 @@ describe('Cloud Plugin', () => {
const start = plugin.start(coreStart);
expect(start.isServerlessEnabled).toBe(false);
});
});

it('exposes `serverless.projectId`', () => {
const { plugin } = startPlugin({
serverless: {
project_id: 'my-awesome-project',
},
it('exposes `serverless.projectId`', () => {
const { plugin } = startPlugin({
serverless: {
project_id: 'my-awesome-project',
},
});
const coreStart = coreMock.createStart();
const start = plugin.start(coreStart);
expect(start.serverless.projectId).toBe('my-awesome-project');
});
const coreStart = coreMock.createStart();
const start = plugin.start(coreStart);
expect(start.serverless.projectId).toBe('my-awesome-project');
});

it('exposes `serverless.projectName`', () => {
const { plugin } = startPlugin({
serverless: {
project_id: 'my-awesome-project',
project_name: 'My Awesome Project',
},
it('exposes `serverless.projectName`', () => {
const { plugin } = startPlugin({
serverless: {
project_id: 'my-awesome-project',
project_name: 'My Awesome Project',
},
});
const coreStart = coreMock.createStart();
const start = plugin.start(coreStart);
expect(start.serverless.projectName).toBe('My Awesome Project');
});
const coreStart = coreMock.createStart();
const start = plugin.start(coreStart);
expect(start.serverless.projectName).toBe('My Awesome Project');
});

it('exposes fetchElasticsearchConfig', async () => {
const { plugin } = startPlugin();
const coreStart = coreMock.createStart();
Expand All @@ -332,5 +374,38 @@ describe('Cloud Plugin', () => {
const result = await start.fetchElasticsearchConfig();
expect(result).toEqual({ elasticsearchUrl: 'elasticsearch-url' });
});
describe('exposes isInTrial', () => {
const getStart = (configParts: Partial<CloudConfigType> = {}) => {
const { plugin } = startPlugin(configParts);
const coreStart = coreMock.createStart();
coreStart.http.get.mockResolvedValue({ elasticsearch_url: 'elasticsearch-url' });
return plugin.start(coreStart);
};
it('is `true` when `trial_end_date` is set and is in the future', () => {
const pluginStart = getStart({
trial_end_date: new Date(Date.now() + 10000).toISOString(),
});

expect(pluginStart.isInTrial()).toBe(true);
});
it('is `false` when `trial_end_date` is set and is in the past', () => {
const pluginStart = getStart({
trial_end_date: new Date(Date.now() - 10000).toISOString(),
});

expect(pluginStart.isInTrial()).toBe(false);
});
it('is `false` when `trial_end_date` is not a valid date', () => {
const pluginStart = getStart({
trial_end_date: 'invalid-date',
});

expect(pluginStart.isInTrial()).toBe(false);
});
it('is `false` when `serverless.in_trial` & `trial_end_date` are not set', () => {
const pluginStart = getStart();
expect(pluginStart.isInTrial()).toBe(false);
});
});
});
});
25 changes: 17 additions & 8 deletions x-pack/platform/plugins/shared/cloud/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,7 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
public setup(core: CoreSetup): CloudSetup {
registerCloudDeploymentMetadataAnalyticsContext(core.analytics, this.config);

const {
id,
cname,
trial_end_date: trialEndDate,
is_elastic_staff_owned: isElasticStaffOwned,
csp,
} = this.config;
const { id, cname, is_elastic_staff_owned: isElasticStaffOwned, csp } = this.config;

let decodedId: DecodedCloudId | undefined;
if (id) {
Expand All @@ -96,7 +90,7 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
csp,
cloudHost: decodedId?.host,
cloudDefaultPort: decodedId?.defaultPort,
trialEndDate: trialEndDate ? new Date(trialEndDate) : undefined,
trialEndDate: this.config.trial_end_date ? new Date(this.config.trial_end_date) : undefined,
isElasticStaffOwned,
isCloudEnabled: this.isCloudEnabled,
onboarding: {
Expand All @@ -121,6 +115,7 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
...this.cloudUrls.getUrls(), // TODO: Deprecate directly accessing URLs, use `getUrls` instead
getPrivilegedUrls: this.cloudUrls.getPrivilegedUrls.bind(this.cloudUrls),
getUrls: this.cloudUrls.getUrls.bind(this.cloudUrls),
isInTrial: this.isInTrial.bind(this),
};
}

Expand Down Expand Up @@ -170,6 +165,7 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
...this.cloudUrls.getUrls(), // TODO: Deprecate directly accessing URLs, use `getUrls` instead
getPrivilegedUrls: this.cloudUrls.getPrivilegedUrls.bind(this.cloudUrls),
getUrls: this.cloudUrls.getUrls.bind(this.cloudUrls),
isInTrial: this.isInTrial.bind(this),
};
}

Expand All @@ -196,4 +192,17 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
};
}
}

private isInTrial(): boolean {
if (this.config.serverless?.in_trial) return true;
if (this.config.trial_end_date) {
const endDateMs = new Date(this.config.trial_end_date).getTime();
if (!Number.isNaN(endDateMs)) {
return Date.now() <= endDateMs;
} else {
this.logger.error('cloud.trial_end_date config value could not be parsed.');
}
}
return false;
}
}
Loading
Loading