Skip to content

Commit 81a0b57

Browse files
authored
Add sagemaker unit tests (#101)
1 parent 774098c commit 81a0b57

27 files changed

+1386
-1
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/.github/ @aws/aws-code-editor
33
/patches/sagemaker.series @aws/aws-code-editor @aws/sagemaker-code-editor
44
/patches/sagemaker/ @aws/aws-code-editor @aws/sagemaker-code-editor
5+
/sagemaker-tests/ @aws/aws-code-editor @aws/sagemaker-code-editor

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ build-artifacts
66
build-private
77
code-editor-src
88
vscode-reh-web-*
9-
code-editor-src-*
9+
code-editor-src-*
10+
node_modules
11+
package-lock.json
12+
package.json

sagemaker-tests/README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# SageMaker Code Editor Unit Tests
2+
3+
This directory contains TypeScript unit tests that validate all patches applied to the VSCode codebase.
4+
5+
## Test Structure
6+
7+
Each patch file in `patches/series` has a corresponding test file:
8+
9+
- `sagemaker-extension.test.ts` - Validates sagemaker-extension.diff patch
10+
- `disable-online-services.test.ts` - Validates disable-online-services.diff patch
11+
- `disable-telemetry.test.ts` - Validates disable-telemetry.diff patch
12+
- `update-csp.test.ts` - Validates update-csp.diff patch
13+
- `webview.test.ts` - Validates webview.diff patch
14+
- `local-storage.test.ts` - Validates local-storage.diff patch
15+
- `sagemaker-integration.test.ts` - Validates sagemaker-integration.diff patch
16+
- `license.test.ts` - Validates license.diff patch
17+
- `base-path-compatibility.test.ts` - Validates base-path-compatibility.diff patch
18+
- `sagemaker-idle-extension.test.ts` - Validates sagemaker-idle-extension.patch
19+
- `terminal-crash-mitigation.test.ts` - Validates terminal-crash-mitigation.patch
20+
- `sagemaker-open-notebook-extension.test.ts` - Validates sagemaker-open-notebook-extension.patch
21+
- `sagemaker-ui-dark-theme.test.ts` - Validates sagemaker-ui-dark-theme.patch
22+
- `sagemaker-ui-post-startup.test.ts` - Validates sagemaker-ui-post-startup.patch
23+
- `sagemaker-extension-smus-support.test.ts` - Validates sagemaker-extension-smus-support.patch
24+
- `post-startup-notifications.test.ts` - Validates post-startup-notifications.patch
25+
- `sagemaker-extensions-sync.test.ts` - Validates sagemaker-extensions-sync.patch
26+
- `custom-extensions-marketplace.test.ts` - Validates custom-extensions-marketplace.diff patch
27+
- `signature-verification.test.ts` - Validates signature-verification.diff patch
28+
- `display-language.test.ts` - Validates display-language.patch
29+
30+
**Total: 20 test files covering all patches in the series**
31+
32+
## Running Tests
33+
34+
### Locally
35+
```bash
36+
./scripts/run-unit-tests.sh
37+
```
38+
39+
### In CI
40+
Tests run automatically on every push via GitHub Actions in `.github/workflows/ci.yml`
41+
42+
## Test Framework
43+
44+
Tests use a simple Node.js-based framework defined in `test-framework.ts` with:
45+
- `describe()` - Test suite grouping
46+
- `test()` - Individual test cases
47+
48+
## What Tests Validate
49+
50+
Tests check that:
51+
1. Patches are properly applied to `patched-vscode/` directory
52+
2. Expected code modifications exist in target files
53+
3. New files/directories are created where needed
54+
4. Configuration changes are present
55+
56+
## Requirements
57+
58+
- Node.js 20+
59+
- TypeScript compiler (npx tsc)
60+
- Patches must be applied (script handles this automatically)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { readFileSync, existsSync } from 'fs';
2+
import { join } from 'path';
3+
import './test-framework';
4+
5+
const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src');
6+
7+
describe('base-path-compatibility.diff validation', () => {
8+
test('serverEnvironmentService.ts should have base-path option added', () => {
9+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/serverEnvironmentService.ts');
10+
11+
if (!existsSync(filePath)) {
12+
throw new Error(`File not found: ${filePath}`);
13+
}
14+
15+
const content = readFileSync(filePath, 'utf8');
16+
17+
// Check for base-path option in serverOptions
18+
const basePathOption = "'base-path': { type: 'string' },";
19+
if (!content.includes(basePathOption)) {
20+
throw new Error(`Expected base-path option not found in ${filePath}`);
21+
}
22+
23+
// Check for base-path in ServerParsedArgs interface
24+
const basePathArg = "'base-path'?: string,";
25+
if (!content.includes(basePathArg)) {
26+
throw new Error(`Expected base-path argument type not found in ${filePath}`);
27+
}
28+
29+
// Check for constructor modification
30+
const constructorLogic = "if (args['base-path']) {\n\t\t\targs['server-base-path'] = args['base-path'];\n\t\t}";
31+
if (!content.includes(constructorLogic)) {
32+
throw new Error(`Expected constructor base-path mapping not found in ${filePath}`);
33+
}
34+
35+
console.log('PASS: Base path compatibility modifications found in serverEnvironmentService.ts');
36+
});
37+
});
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { readFileSync, existsSync } from 'fs';
2+
import { join } from 'path';
3+
import './test-framework';
4+
5+
const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src');
6+
7+
describe('custom-extensions-marketplace.diff validation', () => {
8+
test('product.ts should have custom extensions gallery logic', () => {
9+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/product/common/product.ts');
10+
const productPath = join(PATCHED_VSCODE_DIR, 'product.json');
11+
if (!existsSync(filePath)) {
12+
throw new Error(`File not found: ${filePath}`);
13+
}
14+
15+
const content = readFileSync(filePath, 'utf8');
16+
const productContent = readFileSync(productPath, 'utf8');
17+
// Check for custom extensions gallery environment variable check
18+
const customGalleryCheck = "if (env['EXTENSIONS_GALLERY']) {";
19+
if (!content.includes(customGalleryCheck)) {
20+
throw new Error(`Expected custom extensions gallery check not found in ${filePath}`);
21+
}
22+
23+
// Check for custom gallery parsing log
24+
const customGalleryLog = "console.log(`Custom extensions gallery detected. Parsing...`);";
25+
if (!content.includes(customGalleryLog)) {
26+
throw new Error(`Expected custom gallery log not found in ${filePath}`);
27+
}
28+
29+
// Check for default gallery log - not needed for Code Editor, reference patches/web-server/marketplace.diff and patches/common/integration.diff
30+
// const defaultGalleryLog = "console.log(`Using default extensions gallery.`);";
31+
// if (!content.includes(defaultGalleryLog)) {
32+
// throw new Error(`Expected default gallery log not found in ${filePath}`);
33+
// }
34+
35+
// Check for open-vsx gallery configuration
36+
const openVsxGallery = '"serviceUrl": "https://open-vsx.org/vscode/gallery",';
37+
if (!productContent.includes(openVsxGallery)) {
38+
throw new Error(`Expected open-vsx gallery URL not found in ${productPath}`);
39+
}
40+
41+
// Check for item URL
42+
const itemUrl = '"itemUrl": "https://open-vsx.org/vscode/item",';
43+
if (!productContent.includes(itemUrl)) {
44+
throw new Error(`Expected open-vsx item URL not found in ${productPath}`);
45+
}
46+
47+
// Check for resource URL template
48+
const resourceUrl = '"resourceUrlTemplate": "https://open-vsx.org/vscode/unpkg/{publisher}/{name}/{version}/{path}",';
49+
if (!productContent.includes(resourceUrl)) {
50+
throw new Error(`Expected open-vsx resource URL template not found in ${productPath}`);
51+
}
52+
53+
// Check for gallery logging
54+
const galleryLogging = "console.log(JSON.stringify(product.extensionsGallery, null, 2));";
55+
if (!content.includes(galleryLogging)) {
56+
throw new Error(`Expected gallery logging not found in ${filePath}`);
57+
}
58+
59+
console.log('PASS: Custom extensions marketplace logic found in product.ts');
60+
});
61+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { readFileSync, existsSync } from 'fs';
2+
import { join } from 'path';
3+
import './test-framework';
4+
5+
const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src');
6+
7+
describe('disable-online-services.diff validation', () => {
8+
test('update.config.contribution.ts should disable automatic updates', () => {
9+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/update/common/update.config.contribution.ts');
10+
11+
if (!existsSync(filePath)) {
12+
throw new Error(`File not found: ${filePath}`);
13+
}
14+
15+
const content = readFileSync(filePath, 'utf8');
16+
17+
// Check update mode is set to none
18+
const updateModeDefault = "default: 'none',";
19+
if (!content.includes(updateModeDefault)) {
20+
throw new Error(`Expected update mode 'none' not found in ${filePath}`);
21+
}
22+
23+
// Check release notes are disabled
24+
const releaseNotesDefault = "default: false,";
25+
if (!content.includes(releaseNotesDefault)) {
26+
throw new Error(`Expected release notes disabled not found in ${filePath}`);
27+
}
28+
29+
console.log('PASS: Online services disabled in update configuration');
30+
});
31+
});
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { readFileSync, existsSync } from 'fs';
2+
import { join } from 'path';
3+
import './test-framework';
4+
5+
const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src');
6+
7+
describe('disable-telemetry.diff validation', () => {
8+
test('telemetryService.ts should have telemetry disabled by default', () => {
9+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/telemetry/common/telemetryService.ts');
10+
11+
if (!existsSync(filePath)) {
12+
throw new Error(`File not found: ${filePath}`);
13+
}
14+
15+
const content = readFileSync(filePath, 'utf8');
16+
17+
// Check that enum only contains OFF
18+
const enumLine = "'enum': [TelemetryConfiguration.OFF],";
19+
if (!content.includes(enumLine)) {
20+
throw new Error(`Expected telemetry enum restriction not found in ${filePath}`);
21+
}
22+
23+
// Check that default is OFF
24+
const defaultLine = "'default': TelemetryConfiguration.OFF,";
25+
if (!content.includes(defaultLine)) {
26+
throw new Error(`Expected telemetry default OFF not found in ${filePath}`);
27+
}
28+
29+
console.log('PASS: Telemetry disabled by default in telemetryService.ts');
30+
});
31+
32+
test('desktop.contribution.ts should have crash reporter disabled', () => {
33+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/electron-sandbox/desktop.contribution.ts');
34+
35+
if (!existsSync(filePath)) {
36+
throw new Error(`File not found: ${filePath}`);
37+
}
38+
39+
const content = readFileSync(filePath, 'utf8');
40+
41+
// Check crash reporter is disabled
42+
const crashReporterDisabled = "'default': false,";
43+
if (!content.includes(crashReporterDisabled)) {
44+
throw new Error(`Expected crash reporter disabled not found in ${filePath}`);
45+
}
46+
47+
console.log('PASS: Crash reporter disabled in desktop.contribution.ts');
48+
});
49+
50+
test('1dsAppender.ts should have Microsoft endpoints blocked', () => {
51+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/telemetry/common/1dsAppender.ts');
52+
53+
if (!existsSync(filePath)) {
54+
throw new Error(`File not found: ${filePath}`);
55+
}
56+
57+
const content = readFileSync(filePath, 'utf8');
58+
59+
// Check endpoints are redirected to 0.0.0.0
60+
const blockedEndpoint = "const endpointUrl = 'https://0.0.0.0/OneCollector/1.0';";
61+
const blockedHealthEndpoint = "const endpointHealthUrl = 'https://0.0.0.0/ping';";
62+
63+
if (!content.includes(blockedEndpoint)) {
64+
throw new Error(`Expected blocked endpoint not found in ${filePath}`);
65+
}
66+
67+
if (!content.includes(blockedHealthEndpoint)) {
68+
throw new Error(`Expected blocked health endpoint not found in ${filePath}`);
69+
}
70+
71+
console.log('PASS: Microsoft telemetry endpoints blocked in 1dsAppender.ts');
72+
});
73+
});
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { readFileSync, existsSync } from 'fs';
2+
import { join } from 'path';
3+
import './test-framework';
4+
5+
const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src');
6+
7+
describe('display-language.diff validation', () => {
8+
test('remoteLanguagePacks.ts should have locale functions', () => {
9+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/remoteLanguagePacks.ts');
10+
11+
if (!existsSync(filePath)) {
12+
throw new Error(`File not found: ${filePath}`);
13+
}
14+
15+
const content = readFileSync(filePath, 'utf8');
16+
17+
if (!content.includes('export const getLocaleFromConfig') ||
18+
!content.includes('export async function getBrowserNLSConfiguration')) {
19+
throw new Error(`Failed to find locale functions in ${filePath}`);
20+
}
21+
22+
console.log('PASS: Locale functions found in remoteLanguagePacks.ts');
23+
});
24+
25+
test('webClientServer.ts should use locale from args', () => {
26+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/webClientServer.ts');
27+
28+
if (!existsSync(filePath)) {
29+
throw new Error(`File not found: ${filePath}`);
30+
}
31+
32+
const content = readFileSync(filePath, 'utf8');
33+
34+
if (!content.includes('this._environmentService.args.locale')) {
35+
throw new Error(`Failed to find locale from args in ${filePath}`);
36+
}
37+
38+
console.log('PASS: Locale from args found in webClientServer.ts');
39+
});
40+
41+
test('serverEnvironmentService.ts should have locale option', () => {
42+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/serverEnvironmentService.ts');
43+
44+
if (!existsSync(filePath)) {
45+
throw new Error(`File not found: ${filePath}`);
46+
}
47+
48+
const content = readFileSync(filePath, 'utf8');
49+
50+
if (!content.includes("'locale': { type: 'string' }")) {
51+
throw new Error(`Failed to find locale option in ${filePath}`);
52+
}
53+
54+
console.log('PASS: Locale option found in serverEnvironmentService.ts');
55+
});
56+
57+
test('languagePacks.ts should use remote service', () => {
58+
const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/languagePacks/browser/languagePacks.ts');
59+
60+
if (!existsSync(filePath)) {
61+
throw new Error(`File not found: ${filePath}`);
62+
}
63+
64+
const content = readFileSync(filePath, 'utf8');
65+
66+
if (!content.includes('ProxyChannel.toService<ILanguagePackService>')) {
67+
throw new Error(`Failed to find ProxyChannel usage in ${filePath}`);
68+
}
69+
70+
console.log('PASS: Remote language pack service found in languagePacks.ts');
71+
});
72+
});

sagemaker-tests/globals.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare global {
2+
function describe(name: string, fn: () => void): void;
3+
function test(name: string, fn: () => void): void;
4+
}
5+
6+
export {};

0 commit comments

Comments
 (0)