Skip to content

Commit a2aa28b

Browse files
committed
Add test for the download validation failed case
1 parent 59a87fc commit a2aa28b

File tree

6 files changed

+79
-28
lines changed

6 files changed

+79
-28
lines changed

src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { AbsolutePathPackage } from './packageManager/AbsolutePathPackage';
4242
import { downloadAndInstallPackages } from './packageManager/downloadAndInstallPackages';
4343
import IInstallDependencies from './packageManager/IInstallDependencies';
4444
import { installRuntimeDependencies } from './InstallRuntimeDependencies';
45+
import { isValidDownload } from './packageManager/isValidDownload';
4546

4647
export async function activate(context: vscode.ExtensionContext): Promise<CSharpExtensionExports> {
4748

@@ -119,7 +120,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<CSharp
119120
eventStream.subscribe(telemetryObserver.post);
120121

121122
let networkSettingsProvider = vscodeNetworkSettingsProvider(vscode);
122-
let installDependencies: IInstallDependencies = (dependencies: AbsolutePathPackage[]) => downloadAndInstallPackages(dependencies, networkSettingsProvider, eventStream);
123+
let installDependencies: IInstallDependencies = (dependencies: AbsolutePathPackage[]) => downloadAndInstallPackages(dependencies, networkSettingsProvider, eventStream, isValidDownload);
123124
let runtimeDependenciesExist = await ensureRuntimeDependencies(extension, eventStream, platformInfo, installDependencies);
124125

125126
// activate language services

src/omnisharp/OmnisharpDownloader.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { downloadAndInstallPackages } from '../packageManager/downloadAndInstall
1212
import { DownloadFile } from '../packageManager/FileDownloader';
1313
import { getRuntimeDependenciesPackages } from '../tools/RuntimeDependencyPackageUtils';
1414
import { getAbsolutePathPackagesToInstall } from '../packageManager/getAbsolutePathPackagesToInstall';
15+
import { isValidDownload } from '../packageManager/isValidDownload';
1516

1617
export class OmnisharpDownloader {
1718

@@ -30,7 +31,7 @@ export class OmnisharpDownloader {
3031
if (packagesToInstall && packagesToInstall.length > 0) {
3132
this.eventStream.post(new PackageInstallation(`OmniSharp Version = ${version}`));
3233
this.eventStream.post(new LogPlatformInfo(this.platformInfo));
33-
await downloadAndInstallPackages(packagesToInstall, this.networkSettingsProvider, this.eventStream);
34+
await downloadAndInstallPackages(packagesToInstall, this.networkSettingsProvider, this.eventStream, isValidDownload);
3435
this.eventStream.post(new InstallationSuccess());
3536
}
3637
}

src/packageManager/downloadAndInstallPackages.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,29 @@ import { touchInstallFile, InstallFileType, deleteInstallFile, installFileExists
1414
import { InstallationFailure, IntegrityCheckFailure } from "../omnisharp/loggingEvents";
1515
import { mkdirpSync } from "fs-extra";
1616
import { PackageInstallStart } from "../omnisharp/loggingEvents";
17-
import { isValidDownload } from './isValidDownload';
17+
import { DownloadValidator } from './isValidDownload';
1818

19-
export async function downloadAndInstallPackages(packages: AbsolutePathPackage[], provider: NetworkSettingsProvider, eventStream: EventStream) {
19+
export async function downloadAndInstallPackages(packages: AbsolutePathPackage[], provider: NetworkSettingsProvider, eventStream: EventStream, downloadValidator: DownloadValidator) {
2020
if (packages) {
2121
eventStream.post(new PackageInstallStart());
2222
for (let pkg of packages) {
2323
let installationStage = "touchBeginFile";
2424
try {
2525
mkdirpSync(pkg.installPath.value);
2626
await touchInstallFile(pkg.installPath, InstallFileType.Begin);
27-
let count = 0;
28-
while (count < 2) {
29-
count++;
27+
let count = 1;
28+
let willTryInstallingPackage = () => count <= 2; // try 2 times
29+
while (willTryInstallingPackage()) {
30+
count = count + 1;
3031
let buffer = await DownloadFile(pkg.description, eventStream, provider, pkg.url, pkg.fallbackUrl);
31-
if (isValidDownload(buffer, pkg.integrity, eventStream)) {
32+
if (downloadValidator(buffer, pkg.integrity, eventStream)) {
3233
await InstallZip(buffer, pkg.description, pkg.installPath, pkg.binaries, eventStream);
3334
installationStage = 'touchLockFile';
3435
await touchInstallFile(pkg.installPath, InstallFileType.Lock);
3536
break;
3637
}
3738
else {
38-
let shouldRetry = count == 1;
39-
eventStream.post(new IntegrityCheckFailure(pkg.description, pkg.url, shouldRetry));
40-
break;
39+
eventStream.post(new IntegrityCheckFailure(pkg.description, pkg.url, willTryInstallingPackage()));
4140
}
4241
}
4342
}

src/packageManager/isValidDownload.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ import * as crypto from "crypto";
77
import { EventStream } from "../EventStream";
88
import { IntegrityCheckSuccess, DownloadValidation } from "../omnisharp/loggingEvents";
99

10+
export interface DownloadValidator {
11+
(buffer: Buffer, integrity: string, eventStream: EventStream): boolean;
12+
}
13+
1014
export function isValidDownload(buffer: Buffer, integrity: string, eventStream: EventStream): boolean {
1115
let hash = crypto.createHash('sha256');
1216
if (integrity && integrity.length > 0) {
1317
eventStream.post(new DownloadValidation());
1418
hash.update(buffer);
15-
let value = hash.digest('hex');
16-
if (value.toUpperCase() == integrity.toUpperCase()) {
19+
let value = hash.digest('hex');
20+
if (value.toUpperCase() == integrity.toUpperCase()) {
1721
eventStream.post(new IntegrityCheckSuccess());
1822
return true;
1923
}

tasks/offlinePackagingTasks.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import NetworkSettings from '../src/NetworkSettings';
2323
import { commandLineOptions } from '../tasks/commandLineArguments';
2424
import { getRuntimeDependenciesPackages } from '../src/tools/RuntimeDependencyPackageUtils';
2525
import { getAbsolutePathPackagesToInstall } from '../src/packageManager/getAbsolutePathPackagesToInstall';
26+
import { isValidDownload } from '../src/packageManager/isValidDownload';
2627

2728
gulp.task('vsix:offline:package', async () => {
2829
del.sync(vscodeignorePath);
@@ -93,7 +94,7 @@ async function install(platformInfo: PlatformInformation, packageJSON: any) {
9394
let runTimeDependencies = getRuntimeDependenciesPackages(packageJSON);
9495
let packagesToInstall = await getAbsolutePathPackagesToInstall(runTimeDependencies, platformInfo, codeExtensionPath);
9596
let provider = () => new NetworkSettings(undefined, undefined);
96-
await downloadAndInstallPackages(packagesToInstall, provider, eventStream);
97+
await downloadAndInstallPackages(packagesToInstall, provider, eventStream, isValidDownload);
9798
await debugUtil.CoreClrDebugUtil.writeEmptyFile(debuggerUtil.installCompleteFilePath());
9899
}
99100

test/unitTests/Packages/downloadAndInstallPackages.test.ts

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import TestZip from '../testAssets/TestZip';
1212
import { downloadAndInstallPackages } from '../../../src/packageManager/downloadAndInstallPackages';
1313
import NetworkSettings from '../../../src/NetworkSettings';
1414
import { EventStream } from '../../../src/EventStream';
15-
import { DownloadStart, DownloadSizeObtained, DownloadProgress, DownloadSuccess, InstallationStart, PackageInstallStart } from '../../../src/omnisharp/loggingEvents';
15+
import { DownloadStart, DownloadSizeObtained, DownloadProgress, DownloadSuccess, InstallationStart, PackageInstallStart, IntegrityCheckFailure } from '../../../src/omnisharp/loggingEvents';
1616
import MockHttpsServer from '../testAssets/MockHttpsServer';
1717
import { createTestFile } from '../testAssets/TestFile';
1818
import TestEventBus from '../testAssets/TestEventBus';
1919
import { AbsolutePathPackage } from '../../../src/packageManager/AbsolutePathPackage';
2020
import { AbsolutePath } from '../../../src/packageManager/AbsolutePath';
21+
import { DownloadValidator } from '../../../src/packageManager/isValidDownload';
2122

2223
chai.use(chaiAsPromised);
2324
let expect = chai.expect;
@@ -31,6 +32,7 @@ suite(`${downloadAndInstallPackages.name}`, () => {
3132
let eventBus: TestEventBus;
3233
let downloadablePackage: AbsolutePathPackage[];
3334
let notDownloadablePackage: AbsolutePathPackage[];
35+
let downloadValidator: DownloadValidator = () => true;
3436

3537
const packageDescription = "Test Package";
3638
const networkSettingsProvider = () => new NetworkSettings(undefined, false);
@@ -45,7 +47,7 @@ suite(`${downloadAndInstallPackages.name}`, () => {
4547
{
4648
url: `${server.baseUrl}/downloadablePackage`,
4749
description: packageDescription,
48-
installPath: new AbsolutePath(tmpDirPath)
50+
installPath: new AbsolutePath(tmpDirPath),
4951
}];
5052

5153
notDownloadablePackage = <AbsolutePathPackage[]>[
@@ -66,21 +68,16 @@ suite(`${downloadAndInstallPackages.name}`, () => {
6668
});
6769

6870
suite("If the download and install succeeds", () => {
69-
test("The expected files are installs at the specified path", async () => {
70-
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream);
71+
test("The expected files are installed at the specified path", async () => {
72+
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream, downloadValidator);
7173
for (let elem of testZip.files) {
7274
let filePath = path.join(tmpDirPath, elem.path);
7375
expect(await util.fileExists(filePath)).to.be.true;
7476
}
7577
});
7678

7779
test("install.Lock is present", async () => {
78-
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream);
79-
for (let elem of testZip.files) {
80-
let filePath = path.join(tmpDirPath, elem.path);
81-
expect(await util.fileExists(filePath)).to.be.true;
82-
}
83-
80+
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream, downloadValidator);
8481
expect(await util.fileExists(path.join(tmpDirPath, "install.Lock"))).to.be.true;
8582
});
8683

@@ -94,20 +91,68 @@ suite(`${downloadAndInstallPackages.name}`, () => {
9491
new InstallationStart(packageDescription)
9592
];
9693

97-
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream);
98-
console.log(eventBus.getEvents());
94+
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream, downloadValidator);
95+
expect(eventBus.getEvents()).to.be.deep.equal(eventsSequence);
96+
});
97+
98+
test("If the download validation fails for the first time and passed second time, the correct events are logged", async() => {
99+
let count = 1;
100+
let downloadValidator = () => {
101+
if (count > 1) {
102+
return true; // fail the first time and then pass the subsequent times
103+
}
104+
105+
count++;
106+
return false;
107+
};
108+
109+
let eventsSequence = [
110+
new PackageInstallStart(),
111+
new DownloadStart(packageDescription),
112+
new DownloadSizeObtained(testZip.size),
113+
new DownloadProgress(100, packageDescription),
114+
new DownloadSuccess(' Done!'),
115+
new IntegrityCheckFailure(packageDescription, downloadablePackage[0].url, true),
116+
new DownloadStart(packageDescription),
117+
new DownloadSizeObtained(testZip.size),
118+
new DownloadProgress(100, packageDescription),
119+
new DownloadSuccess(' Done!'),
120+
new InstallationStart(packageDescription)
121+
];
122+
123+
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream, downloadValidator);
99124
expect(eventBus.getEvents()).to.be.deep.equal(eventsSequence);
100125
});
101126
});
102127

103128
suite("If the download and install fails", () => {
129+
test("If the download succeeds but the validation fails, events are logged", async() => {
130+
let downloadValidator = () => false;
131+
let eventsSequence = [
132+
new PackageInstallStart(),
133+
new DownloadStart(packageDescription),
134+
new DownloadSizeObtained(testZip.size),
135+
new DownloadProgress(100, packageDescription),
136+
new DownloadSuccess(' Done!'),
137+
new IntegrityCheckFailure(packageDescription, downloadablePackage[0].url, true),
138+
new DownloadStart(packageDescription),
139+
new DownloadSizeObtained(testZip.size),
140+
new DownloadProgress(100, packageDescription),
141+
new DownloadSuccess(' Done!'),
142+
new IntegrityCheckFailure(packageDescription, downloadablePackage[0].url, false),
143+
];
144+
145+
await downloadAndInstallPackages(downloadablePackage, networkSettingsProvider, eventStream, downloadValidator);
146+
expect(eventBus.getEvents()).to.be.deep.equal(eventsSequence);
147+
});
148+
104149
test("Throws an exception when the download fails", async () => {
105-
await downloadAndInstallPackages(notDownloadablePackage, networkSettingsProvider, eventStream).should.be.rejected;
150+
await downloadAndInstallPackages(notDownloadablePackage, networkSettingsProvider, eventStream, downloadValidator).should.be.rejected;
106151
});
107152

108153
test("install.Lock is not present when the download fails", async () => {
109154
try {
110-
await downloadAndInstallPackages(notDownloadablePackage, networkSettingsProvider, eventStream);
155+
await downloadAndInstallPackages(notDownloadablePackage, networkSettingsProvider, eventStream, downloadValidator);
111156
}
112157
catch (error) {
113158
expect(await util.fileExists(path.join(tmpDirPath, "install.Lock"))).to.be.false;

0 commit comments

Comments
 (0)