Skip to content

Commit

Permalink
Fix server update message not handling mutli-digit version numbers (m…
Browse files Browse the repository at this point in the history
  • Loading branch information
jwilander authored Dec 3, 2024
1 parent 7b72a65 commit 3ed209a
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {fetchAndCompareVersion} from './updates';

import {ItemStatus} from '../dashboard.type';

jest.mock('mattermost-redux/client', () => ({
Client4: {
getBaseRoute: jest.fn(() => 'http://localhost/api/v4'),
},
}));

describe('fetchAndCompareVersion', () => {
beforeEach(() => {
global.fetch = jest.fn();
});

afterEach(() => {
jest.resetAllMocks();
});

it('should return major update available', async () => {
(global.fetch as jest.Mock).mockResolvedValue({
json: jest.fn().mockResolvedValue({tag_name: 'v9.1.2', body: 'New major version available'}),
});

const formatMessage = jest.fn(({defaultMessage}) => defaultMessage);
const result = await fetchAndCompareVersion('5.6.0', formatMessage);

expect(result.type).toBe('Major');
expect(result.description).toBe('New major version available');
expect(result.status).toBe(ItemStatus.ERROR);
});

it('should return major update available - single to double digit', async () => {
(global.fetch as jest.Mock).mockResolvedValue({
json: jest.fn().mockResolvedValue({tag_name: 'v10.0.0', body: 'New major version available'}),
});

const formatMessage = jest.fn(({defaultMessage}) => defaultMessage);
const result = await fetchAndCompareVersion('9.1.0', formatMessage);

expect(result.type).toBe('Major');
expect(result.description).toBe('New major version available');
expect(result.status).toBe(ItemStatus.ERROR);
});

it('should return minor update available', async () => {
(global.fetch as jest.Mock).mockResolvedValue({
json: jest.fn().mockResolvedValue({tag_name: 'v9.2.0', body: 'New minor version available'}),
});

const formatMessage = jest.fn(({defaultMessage}) => defaultMessage);
const result = await fetchAndCompareVersion('9.1.0', formatMessage);

expect(result.type).toBe('Minor');
expect(result.description).toBe('New minor version available');
expect(result.status).toBe(ItemStatus.WARNING);
});

it('should return minor update available - single to double digit', async () => {
(global.fetch as jest.Mock).mockResolvedValue({
json: jest.fn().mockResolvedValue({tag_name: 'v9.11.0', body: 'New minor version available'}),
});

const formatMessage = jest.fn(({defaultMessage}) => defaultMessage);
const result = await fetchAndCompareVersion('9.5.0', formatMessage);

expect(result.type).toBe('Minor');
expect(result.description).toBe('New minor version available');
expect(result.status).toBe(ItemStatus.WARNING);
});

it('should return patch update available', async () => {
(global.fetch as jest.Mock).mockResolvedValue({
json: jest.fn().mockResolvedValue({tag_name: 'v9.1.1', body: 'New patch version available'}),
});

const formatMessage = jest.fn(({defaultMessage}) => defaultMessage);
const result = await fetchAndCompareVersion('9.1.0', formatMessage);

expect(result.type).toBe('Patch');
expect(result.description).toBe('New patch version available');
expect(result.status).toBe(ItemStatus.INFO);
});

it('should return patch update available - single to double digit', async () => {
(global.fetch as jest.Mock).mockResolvedValue({
json: jest.fn().mockResolvedValue({tag_name: 'v9.1.11', body: 'New patch version available'}),
});

const formatMessage = jest.fn(({defaultMessage}) => defaultMessage);
const result = await fetchAndCompareVersion('9.1.4', formatMessage);

expect(result.type).toBe('Patch');
expect(result.description).toBe('New patch version available');
expect(result.status).toBe(ItemStatus.INFO);
});

it('should return no update available', async () => {
(global.fetch as jest.Mock).mockResolvedValue({
json: jest.fn().mockResolvedValue({tag_name: 'v9.1.0', body: 'No new version available'}),
});

const formatMessage = jest.fn(({defaultMessage}) => defaultMessage);
const result = await fetchAndCompareVersion('9.1.0', formatMessage);

expect(result.type).toBe('');
expect(result.description).toBe('No new version available');
expect(result.status).toBe(ItemStatus.OK);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,55 +18,7 @@ const testServerVersion = async (
formatMessage: ReturnType<typeof useIntl>['formatMessage'],
options: Options,
) => {
const fetchVersion = async (
installedVersion: string,
formatMessage: ReturnType<typeof useIntl>['formatMessage'],
) => {
const result = await fetch(`${Client4.getBaseRoute()}/latest_version`).then((result) => result.json());

if (result.tag_name) {
const sanitizedVersion = result.tag_name.startsWith('v') ? result.tag_name.slice(1) : result.tag_name;
const newVersionParts = sanitizedVersion.split('.');
const installedVersionParts = installedVersion.split('.').slice(0, 3);

// quick general check if a newer version is available
let type = '';
let status: ItemStatus = ItemStatus.OK;

if (newVersionParts.join('') > installedVersionParts.join('')) {
// get correct values to be inserted into the accordion item
switch (true) {
case newVersionParts[0] > installedVersionParts[0]:
type = formatMessage({
id: 'admin.reporting.workspace_optimization.updates.server_version.update_type.major',
defaultMessage: 'Major',
});
status = ItemStatus.ERROR;
break;
case newVersionParts[1] > installedVersionParts[1]:
type = formatMessage({
id: 'admin.reporting.workspace_optimization.updates.server_version.update_type.minor',
defaultMessage: 'Minor',
});
status = ItemStatus.WARNING;
break;
case newVersionParts[2] > installedVersionParts[2]:
type = formatMessage({
id: 'admin.reporting.workspace_optimization.updates.server_version.update_type.patch',
defaultMessage: 'Patch',
});
status = ItemStatus.INFO;
break;
}
}

return {type, description: result.body, status};
}

return {type: '', description: '', status: ItemStatus.OK};
};

const serverVersion = await fetchVersion(options.installedVersion, formatMessage);
const serverVersion = await fetchAndCompareVersion(options.installedVersion, formatMessage);
return {
id: 'server_version',
title: formatMessage({
Expand All @@ -85,6 +37,54 @@ const testServerVersion = async (
};
};

export const fetchAndCompareVersion = async (
installedVersion: string,
formatMessage: ReturnType<typeof useIntl>['formatMessage'],
) => {
const result = await fetch(`${Client4.getBaseRoute()}/latest_version`).then((result) => result.json());

if (result.tag_name) {
const sanitizedVersion = result.tag_name.startsWith('v') ? result.tag_name.slice(1) : result.tag_name;
const newVersionParts = sanitizedVersion.split('.');
const installedVersionParts = installedVersion.split('.').slice(0, 3);

// quick general check if a newer version is available
let type = '';
let status: ItemStatus = ItemStatus.OK;

if (sanitizedVersion.localeCompare(installedVersion, undefined, {numeric: true, sensitivity: 'base'}) > 0) {
// get correct values to be inserted into the accordion item
switch (true) {
case Number(newVersionParts[0]) > Number(installedVersionParts[0]):
type = formatMessage({
id: 'admin.reporting.workspace_optimization.updates.server_version.update_type.major',
defaultMessage: 'Major',
});
status = ItemStatus.ERROR;
break;
case Number(newVersionParts[1]) > Number(installedVersionParts[1]):
type = formatMessage({
id: 'admin.reporting.workspace_optimization.updates.server_version.update_type.minor',
defaultMessage: 'Minor',
});
status = ItemStatus.WARNING;
break;
case Number(newVersionParts[2]) > Number(installedVersionParts[2]):
type = formatMessage({
id: 'admin.reporting.workspace_optimization.updates.server_version.update_type.patch',
defaultMessage: 'Patch',
});
status = ItemStatus.INFO;
break;
}
}

return {type, description: result.body, status};
}

return {type: '', description: '', status: ItemStatus.OK};
};

export const runUpdateChecks = async (
config: Partial<AdminConfig>,
formatMessage: ReturnType<typeof useIntl>['formatMessage'],
Expand Down

0 comments on commit 3ed209a

Please sign in to comment.