Skip to content

Commit

Permalink
fix(MongoBinaryDownload): use coerced versions for semver
Browse files Browse the repository at this point in the history
fixes #734
  • Loading branch information
hasezoey committed Jan 17, 2023
1 parent 5676931 commit 10d1749
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
KnownVersionIncompatibilityError,
UnknownArchitectureError,
UnknownPlatformError,
UnknownVersionError,
} from './errors';
import { deprecate } from 'util';

Expand Down Expand Up @@ -101,11 +102,12 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {
*/
getArchiveNameWin(): string {
let name = `mongodb-${this.platform}-${this.arch}`;
const coercedVersion = semver.coerce(this.version);

if (!isNullOrUndefined(semver.coerce(this.version))) {
if (semver.satisfies(this.version, '4.2.x')) {
if (!isNullOrUndefined(coercedVersion)) {
if (semver.satisfies(coercedVersion, '4.2.x')) {
name += '-2012plus';
} else if (semver.lt(this.version, '4.1.0')) {
} else if (semver.lt(coercedVersion, '4.1.0')) {
name += '-2008plus-ssl';
}
}
Expand All @@ -121,19 +123,19 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {
*/
getArchiveNameOsx(): string {
let name = `mongodb-osx`;
const version = semver.coerce(this.version);
const coercedVersion = semver.coerce(this.version);

if (!isNullOrUndefined(version) && semver.gte(version, '3.2.0')) {
if (!isNullOrUndefined(coercedVersion) && semver.gte(coercedVersion, '3.2.0')) {
name += '-ssl';
}
if (isNullOrUndefined(version) || semver.gte(version, '4.2.0')) {
if (isNullOrUndefined(coercedVersion) || semver.gte(coercedVersion, '4.2.0')) {
name = `mongodb-macos`; // somehow these files are not listed in https://www.mongodb.org/dl/osx
}

// mongodb has native arm64
if (this.arch === 'aarch64') {
// force usage of "x86_64" binary for all versions below than 6.0.0
if (!isNullOrUndefined(version) && semver.lt(version, '6.0.0')) {
if (!isNullOrUndefined(coercedVersion) && semver.lt(coercedVersion, '6.0.0')) {
log('getArchiveNameOsx: Arch is "aarch64" and version is below 6.0.0, using x64 binary');
this.arch = 'x86_64';
} else {
Expand Down Expand Up @@ -243,11 +245,16 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {
getDebianVersionString(os: LinuxOS): string {
let name = 'debian';
const release: number = parseFloat(os.release);
const coercedVersion = semver.coerce(this.version);

if (isNullOrUndefined(coercedVersion)) {
throw new UnknownVersionError(this.version);
}

if (release >= 11 || ['unstable', 'testing'].includes(os.release)) {
// Debian 11 is compatible with the binaries for debian 10
// but does not have binaries for before 5.0.8
if (semver.lt(this.version, '5.0.8')) {
if (semver.lt(coercedVersion, '5.0.8')) {
log('debian11 detected, but version below 5.0.8 requested, using debian10');
name += '10';
} else {
Expand All @@ -264,7 +271,7 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {
}

if (release >= 10) {
if (semver.lt(this.version, '4.2.1')) {
if (semver.lt(coercedVersion, '4.2.1')) {
throw new KnownVersionIncompatibilityError(
`Debian ${release}`,
this.version,
Expand Down Expand Up @@ -311,6 +318,11 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {
let name = 'rhel';
const { release } = os;
const releaseAsSemver = semver.coerce(release); // coerce "8" to "8.0.0" and "8.2" to "8.2.0", makes comparing easier than "parseInt" or "parseFloat"
const coercedVersion = semver.coerce(this.version);

if (isNullOrUndefined(coercedVersion)) {
throw new UnknownVersionError(this.version);
}

if (releaseAsSemver) {
if (this.arch === 'aarch64') {
Expand All @@ -325,7 +337,7 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {
}
// there are no versions for aarch64 before mongodb 4.4.2
// Note: version 4.4.2 and 4.4.3 are NOT listed at the list, but are existing; list: https://www.mongodb.com/download-center/community/releases/archive
if (semver.lt(this.version, '4.4.2')) {
if (semver.lt(coercedVersion, '4.4.2')) {
throw new KnownVersionIncompatibilityError(`Rhel ${release}`, this.version, '>=4.4.2');
}

Expand Down Expand Up @@ -399,6 +411,11 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {
*/
getUbuntuVersionString(os: LinuxOS): string {
let ubuntuOS: LinuxOS | undefined = undefined;
const coercedVersion = semver.coerce(this.version);

if (isNullOrUndefined(coercedVersion)) {
throw new UnknownVersionError(this.version);
}

// "id_like" processing (version conversion) [this is an block to be collapsible]
{
Expand Down Expand Up @@ -460,13 +477,13 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {

if (this.arch === 'aarch64') {
// this is because, before version 4.1.10, everything for "arm64" / "aarch64" were just "arm64" and for "ubuntu1604"
if (semver.satisfies(this.version, '<4.1.10')) {
if (semver.satisfies(coercedVersion, '<4.1.10')) {
this.arch = 'arm64';

return 'ubuntu1604';
}
// this is because versions below "4.4.0" did not provide an binary for anything above 1804
if (semver.satisfies(this.version, '>=4.1.10 <4.4.0')) {
if (semver.satisfies(coercedVersion, '>=4.1.10 <4.4.0')) {
return 'ubuntu1804';
}
}
Expand All @@ -477,7 +494,7 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {

// there are no MongoDB 3.x binary distributions for ubuntu >= 18
// https://www.mongodb.org/dl/linux/x86_64-ubuntu1604
if (ubuntuYear >= 18 && semver.satisfies(this.version, '3.x.x')) {
if (ubuntuYear >= 18 && semver.satisfies(coercedVersion, '3.x.x')) {
log(
`getUbuntuVersionString: ubuntuYear is "${ubuntuYear}", which dosnt have an 3.x.x version, defaulting to "1604"`
);
Expand All @@ -487,7 +504,7 @@ export class MongoBinaryDownloadUrl implements MongoBinaryDownloadUrlOpts {

// there are no MongoDB <=4.3.x binary distributions for ubuntu > 18
// https://www.mongodb.org/dl/linux/x86_64-ubuntu1804
if (ubuntuYear > 18 && semver.satisfies(this.version, '<=4.3.x')) {
if (ubuntuYear > 18 && semver.satisfies(coercedVersion, '<=4.3.x')) {
log(
`getUbuntuVersionString: ubuntuYear is "${ubuntuYear}", which dosnt have an "<=4.3.x" version, defaulting to "1804"`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,42 @@ import {
UnknownPlatformError,
UnknownArchitectureError,
KnownVersionIncompatibilityError,
UnknownVersionError,
} from '../errors';
import { LinuxOS } from '../getos';
import MongoBinaryDownloadUrl from '../MongoBinaryDownloadUrl';
import { envName, ResolveConfigVariables } from '../resolveConfig';
import * as semver from 'semver';
import { assertion } from '../utils';

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

describe('MongoBinaryDownloadUrl', () => {
// the following is to make sure that semver works in expected ways and as examples of how we use it
describe('semver correctly coerces mongodb versions', () => {
it('should convert a normal semver version', () => {
const normal5 = semver.coerce('5.0.0');
assertion(normal5);
expect(normal5.version).toStrictEqual('5.0.0');

const normalAll = semver.coerce('4.4.2');
assertion(normalAll);
expect(normalAll.version).toStrictEqual('4.4.2');
});

it('should convert "-latest" version correctly', () => {
const latest5 = semver.coerce('v5.0-latest');
assertion(latest5);
expect(latest5.version).toStrictEqual('5.0.0');

const latest44 = semver.coerce('v4.4-latest');
assertion(latest44);
expect(latest44.version).toStrictEqual('4.4.0');
});
});

describe('getDownloadUrl()', () => {
describe('for mac', () => {
it('latest', async () => {
Expand Down Expand Up @@ -92,6 +118,28 @@ describe('MongoBinaryDownloadUrl', () => {
'https://fastdl.mongodb.org/osx/mongodb-macos-arm64-6.0.0.tgz'
);
});

it('should allow v5.0-latest x64', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'darwin',
arch: 'x64',
version: 'v5.0-latest',
});
expect(await du.getDownloadUrl()).toBe(
'https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-v5.0-latest.tgz'
);
});

it('should allow v5.0-latest arm64', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'darwin',
arch: 'arm64',
version: 'v5.0-latest',
});
expect(await du.getDownloadUrl()).toBe(
'https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-v5.0-latest.tgz'
);
});
});

describe('for linux', () => {
Expand Down Expand Up @@ -224,6 +272,44 @@ describe('MongoBinaryDownloadUrl', () => {
);
});

it('should allow v5.0-latest', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
arch: 'x64',
version: 'v5.0-latest',
os: {
os: 'linux',
dist: 'ubuntu',
release: '20.04',
},
});
expect(await du.getDownloadUrl()).toBe(
'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-v5.0-latest.tgz'
);
});

it('should throw a Error when the provided version could not be coerced [UnknownVersionError]', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
arch: 'x64',
version: 'vvv',
os: {
os: 'linux',
dist: 'ubuntu',
release: '20.04',
},
});

try {
await du.getDownloadUrl();
fail('Expected to throw a UnknownVersionError');
} catch (err) {
assertIsError(err);
expect(err).toBeInstanceOf(UnknownVersionError);
expect(err.message).toMatchSnapshot();
}
});

describe('arm64', () => {
it('for ubuntu arm64 4.0.25 (below 4.1.10)', async () => {
const du = new MongoBinaryDownloadUrl({
Expand Down Expand Up @@ -420,6 +506,44 @@ describe('MongoBinaryDownloadUrl', () => {
);
});

it('should allow v5.0-latest', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
arch: 'x64',
version: 'v5.0-latest',
os: {
os: 'linux',
dist: 'debian',
release: '10',
},
});
expect(await du.getDownloadUrl()).toBe(
'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-v5.0-latest.tgz'
);
});

it('should throw a Error when the provided version could not be coerced [UnknownVersionError]', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
arch: 'x64',
version: 'vvv',
os: {
os: 'linux',
dist: 'debian',
release: '10',
},
});

try {
await du.getDownloadUrl();
fail('Expected to throw a UnknownVersionError');
} catch (err) {
assertIsError(err);
expect(err).toBeInstanceOf(UnknownVersionError);
expect(err.message).toMatchSnapshot();
}
});

it('should throw a Error when requesting a version below 4.2.1 for debian 10+ [#554] [KnownVersionIncompatibilityError]', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
Expand Down Expand Up @@ -903,6 +1027,22 @@ describe('MongoBinaryDownloadUrl', () => {
);
});

it('should allow v5.0-latest', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
arch: 'x64',
version: 'v5.0-latest',
os: {
os: 'linux',
dist: 'rhel',
release: '9',
},
});
expect(await du.getDownloadUrl()).toBe(
'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-v5.0-latest.tgz'
);
});

it('should Error when ARM64 and rhel below 8 [KnownVersionIncompatibilityError]', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
Expand Down Expand Up @@ -988,6 +1128,28 @@ describe('MongoBinaryDownloadUrl', () => {
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
expect(consoleWarnSpy).toHaveBeenCalledWith('Couldnt coerce RHEL version "a"');
});

it('should throw a Error when the provided version could not be coerced [UnknownVersionError]', async () => {
const du = new MongoBinaryDownloadUrl({
platform: 'linux',
arch: 'x64',
version: 'vvv',
os: {
os: 'linux',
dist: 'rhel',
release: '9',
},
});

try {
await du.getDownloadUrl();
fail('Expected to throw a UnknownVersionError');
} catch (err) {
assertIsError(err);
expect(err).toBeInstanceOf(UnknownVersionError);
expect(err.message).toMatchSnapshot();
}
});
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ exports[`MongoBinaryDownloadUrl getDownloadUrl() for linux for debian should thr
Mongodb does not provide binaries for versions before 4.2.1 for Debian 10+ and also cannot be mapped to a previous Debian release"
`;

exports[`MongoBinaryDownloadUrl getDownloadUrl() for linux for debian should throw a Error when the provided version could not be coerced [UnknownVersionError] 1`] = `"Could not corece VERSION to a semver version (version: \\"vvv\\")"`;

exports[`MongoBinaryDownloadUrl getDownloadUrl() for linux for rhel should Error when ARM64 and rhel below 8 [KnownVersionIncompatibilityError] 1`] = `
"Requested Version \\"4.4.2\\" is not available for \\"Rhel 7\\"! Available Versions: \\">=4.4.2\\"
ARM64(aarch64) support for rhel is only for rhel82 or higher"
Expand All @@ -20,6 +22,10 @@ exports[`MongoBinaryDownloadUrl getDownloadUrl() for linux for rhel should Error
ARM64(aarch64) support for rhel is only for rhel82 or higher"
`;

exports[`MongoBinaryDownloadUrl getDownloadUrl() for linux for rhel should throw a Error when the provided version could not be coerced [UnknownVersionError] 1`] = `"Could not corece VERSION to a semver version (version: \\"vvv\\")"`;

exports[`MongoBinaryDownloadUrl getDownloadUrl() for linux for ubuntu should throw a Error when the provided version could not be coerced [UnknownVersionError] 1`] = `"Could not corece VERSION to a semver version (version: \\"vvv\\")"`;

exports[`MongoBinaryDownloadUrl getDownloadUrl() should throw an error if platform is unknown (getArchiveName) 1`] = `"Unknown Platform: \\"unknown\\""`;

exports[`MongoBinaryDownloadUrl getDownloadUrl() should throw an error if platform is unknown (translatePlatform) 1`] = `"Unknown Platform: \\"unknown\\""`;
Expand Down

0 comments on commit 10d1749

Please sign in to comment.