Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 12 additions & 2 deletions packages/compass-smoke-tests/src/build-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { type PackageKind } from './packages';
import { type SmokeTestsContext } from './context';
import { pick } from 'lodash';

const SUPPORTED_CHANNELS = ['dev', 'beta', 'stable'] as const;

function assertObjectHasKeys(
obj: unknown,
name: string,
Expand All @@ -25,13 +27,21 @@ function assertObjectHasKeys(

// subsets of the hadron-build info result

export const commonKeys = ['productName'] as const;
export type CommonBuildInfo = Record<typeof commonKeys[number], string>;
export const commonKeys = ['productName', 'channel'] as const;
export type CommonBuildInfo = Record<typeof commonKeys[number], string> & {
channel: 'dev' | 'beta' | 'stable';
};

export function assertCommonBuildInfo(
buildInfo: unknown
): asserts buildInfo is CommonBuildInfo {
assertObjectHasKeys(buildInfo, 'buildInfo', commonKeys);
assert(
SUPPORTED_CHANNELS.includes((buildInfo as any).channel),
Copy link
Contributor

@kraenhansen kraenhansen Jan 21, 2025

Choose a reason for hiding this comment

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

This is probably the easiest. It's a bit annoying that Array#includes doesn't simply take an unknown, but .. there are reasons.

Suggested change
SUPPORTED_CHANNELS.includes((buildInfo as any).channel),
SUPPORTED_CHANNELS.includes((buildInfo as unknown as Channel).channel),

Copy link
Contributor Author

Choose a reason for hiding this comment

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

buildInfo isn't a channel, though. it has a channel. And it is already unknown.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Something like:

export function assertCommonBuildInfo(
  buildInfo: unknown
): asserts buildInfo is CommonBuildInfo {
  assertObjectHasKeys(buildInfo, 'buildInfo', commonKeys);
  assert(
    SUPPORTED_CHANNELS.includes((buildInfo as { channel: Channel }).channel),
    `Expected ${
      (buildInfo as { channel: Channel }).channel
    } to be in ${SUPPORTED_CHANNELS.join(',')}`
  );
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you use assertObjectHasKeys to make sure buildInfo has the channel property? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Already did. I added channel to commonKeys.

Copy link
Contributor

@kraenhansen kraenhansen Jan 25, 2025

Choose a reason for hiding this comment

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

Then why the (buildInfo as { channel: Channel }).channel? 🤔
Could that be buildInfo.channel as Channel instead?

`Expected ${(buildInfo as any).channel} to be in ${SUPPORTED_CHANNELS.join(
','
)}`
);
}

export const windowsFilenameKeys = [
Expand Down
83 changes: 83 additions & 0 deletions packages/compass-smoke-tests/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,60 @@ async function getTestSubject(
}
}

type Arch = 'arm64' | 'x64';

type PlatformShortName =
| 'darwin-arm64'
| 'darwin-x64'
| 'windows'
| 'linux_deb'
| 'linux_rpm';

function getPlatformShortName(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The URL for downloading the latest release ends in things like osx, darwin-arm64, darwin-x64, windows, linux_dev or linux_rpm. This just calculates that bit. I'm calling it a "platform short name" until we think of something better.

arch: Arch,
kind: PackageKind
): PlatformShortName {
if (arch === 'arm64') {
if (kind === 'osx_dmg' || kind === 'osx_zip') {
return 'darwin-arm64';
}
}
if (arch === 'x64') {
if (kind === 'osx_dmg' || kind === 'osx_zip') {
return 'darwin-x64';
}
if (
kind === 'windows_setup' ||
kind === 'windows_msi' ||
kind === 'windows_zip'
) {
return 'windows';
}
if (kind === 'linux_deb' || kind === 'linux_tar') {
return 'linux_deb';
}
if (kind === 'linux_rpm' || kind === 'rhel_tar') {
return 'linux_rpm';
}
}

throw new Error(`Unsupported arch/kind combo: ${arch}/${kind}`);
}

async function getLatestRelease(
channel: 'dev' | 'beta' | 'stable',
arch: Arch,
kind: PackageKind,
forceDownload?: boolean
): Promise<string> {
const shortName = getPlatformShortName(arch, kind);

return await downloadFile({
url: `http://compass.mongodb.com/api/v2/download/latest/compass/${channel}/${shortName}`,
clearCache: forceDownload,
});
}

function getInstaller(kind: PackageKind) {
if (kind === 'osx_dmg') {
return installMacDMG;
Expand Down Expand Up @@ -179,6 +233,8 @@ async function run() {
const install = getInstaller(kind);

try {
console.log('downgrade from this package to latest release');

const appName = buildInfo.productName;

const { appPath, uninstall } = install({
Expand All @@ -196,6 +252,33 @@ async function run() {
console.log('Cleaning up sandbox');
fs.rmSync(context.sandboxPath, { recursive: true });
}

console.log('update from latest release to this package');
const releasepath = await getLatestRelease(
buildInfo.channel,
context.arch,
kind,
context.forceDownload
);

try {
const appName = buildInfo.productName;

const { appPath, uninstall } = install({
appName,
filepath: releasepath,
destinationPath: context.sandboxPath,
});

try {
runTest({ appName, appPath });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again: This should actually see if you can update from this version. I'm just including it as a kind of sanity check that releasepath works.

} finally {
await uninstall();
}
} finally {
console.log('Cleaning up sandbox');
fs.rmSync(context.sandboxPath, { recursive: true });
}
}

type RunTestOptions = {
Expand Down
12 changes: 11 additions & 1 deletion packages/compass-smoke-tests/src/downloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ensureDownloadsDirectory } from './directories';

type DownloadFileOptions = {
url: string;
targetFilename: string;
targetFilename?: string;
clearCache?: boolean;
};

Expand All @@ -18,6 +18,14 @@ export async function downloadFile({
}: DownloadFileOptions): Promise<string> {
const response = await fetch(url);

if (!targetFilename) {
// if no filename was specified, work out the filename based on the final
// URL the way a browser would
targetFilename = path.basename(new URL(response.url).pathname);
}

assert(targetFilename, 'Expected a filename');

const etag = response.headers.get('etag');
assert(etag, 'Expected an ETag header');
const cleanEtag = etag.match(/[0-9a-fA-F]/g)?.join('');
Expand Down Expand Up @@ -50,5 +58,7 @@ export async function downloadFile({
fs.createWriteStream(outputPath)
);

console.log(outputPath);

return outputPath;
}
Loading