Files
xget/test/platforms.test.js
T
xixu-me 0a5ef94d81 Add Jenkins plugin mirror support
Introduces Jenkins plugin and update center mirror support in README and platform config. Updates transformPath logic for Jenkins endpoints and adds comprehensive tests for Jenkins path handling and URL construction.
2025-09-03 01:47:23 +08:00

470 lines
15 KiB
JavaScript

import { describe, expect, it } from 'vitest';
import { PLATFORMS, transformPath } from '../src/config/platforms.js';
describe('Platform Configuration', () => {
describe('Platform Definitions', () => {
it('should have all required platforms defined', () => {
const requiredPlatforms = [
'gh',
'gl',
'sf',
'gitea',
'codeberg',
'hf',
'civitai',
'npm',
'pypi',
'conda',
'homebrew'
];
requiredPlatforms.forEach(platform => {
expect(PLATFORMS).toHaveProperty(platform);
expect(PLATFORMS[platform]).toBeDefined();
});
});
it('should have valid base URLs for all platforms', () => {
Object.values(PLATFORMS).forEach(baseUrl => {
expect(baseUrl).toBeDefined();
expect(baseUrl).toMatch(/^https?:\/\/.+/);
});
});
it('should have unified transform function', () => {
expect(transformPath).toBeDefined();
expect(typeof transformPath).toBe('function');
});
});
describe('Unified Transform Function', () => {
it('should transform GitHub paths correctly', () => {
expect(transformPath('/gh/microsoft/vscode/archive/main.zip', 'gh')).toBe(
'/microsoft/vscode/archive/main.zip'
);
expect(transformPath('/gh/user/repo.git', 'gh')).toBe('/user/repo.git');
});
it('should transform GitLab paths correctly', () => {
expect(transformPath('/gl/gitlab-org/gitlab/-/archive/master/gitlab-master.zip', 'gl')).toBe(
'/gitlab-org/gitlab/-/archive/master/gitlab-master.zip'
);
});
it('should transform SourceForge paths correctly', () => {
expect(
transformPath('/sf/projects/sevenzip/files/7-Zip/23.01/7z2301-x64.exe/download', 'sf')
).toBe('/projects/sevenzip/files/7-Zip/23.01/7z2301-x64.exe/download');
});
it('should transform Gitea paths correctly', () => {
expect(transformPath('/gitea/gitea/gitea/archive/master.zip', 'gitea')).toBe(
'/gitea/gitea/archive/master.zip'
);
});
it('should transform Codeberg paths correctly', () => {
expect(transformPath('/codeberg/forgejo/forgejo/archive/forgejo.zip', 'codeberg')).toBe(
'/forgejo/forgejo/archive/forgejo.zip'
);
});
it('should transform Hugging Face paths correctly', () => {
expect(transformPath('/hf/microsoft/DialoGPT-medium/resolve/main/config.json', 'hf')).toBe(
'/microsoft/DialoGPT-medium/resolve/main/config.json'
);
expect(transformPath('/hf/datasets/squad/resolve/main/train.json', 'hf')).toBe(
'/datasets/squad/resolve/main/train.json'
);
});
it('should transform Civitai paths correctly', () => {
expect(transformPath('/civitai/api/v1/models', 'civitai')).toBe('/api/v1/models');
expect(transformPath('/civitai/api/v1/model-versions/1318', 'civitai')).toBe(
'/api/v1/model-versions/1318'
);
expect(transformPath('/civitai/api/download/models/1105', 'civitai')).toBe(
'/api/download/models/1105'
);
});
it('should transform npm paths correctly', () => {
expect(transformPath('/npm/react/-/react-18.2.0.tgz', 'npm')).toBe(
'/react/-/react-18.2.0.tgz'
);
expect(transformPath('/npm/lodash', 'npm')).toBe('/lodash');
});
it('should transform PyPI paths correctly', () => {
expect(transformPath('/pypi/packages/source/r/requests/requests-2.31.0.tar.gz', 'pypi')).toBe(
'/packages/source/r/requests/requests-2.31.0.tar.gz'
);
expect(transformPath('/pypi/simple/requests/', 'pypi')).toBe('/simple/requests/');
});
it('should transform PyPI files paths correctly', () => {
expect(
transformPath('/pypi/files/packages/source/r/requests/requests-2.31.0.tar.gz', 'pypi-files')
).toBe('/packages/source/r/requests/requests-2.31.0.tar.gz');
});
it('should transform conda default channel paths correctly', () => {
expect(transformPath('/conda/pkgs/main/linux-64/numpy-1.24.3.conda', 'conda')).toBe(
'/pkgs/main/linux-64/numpy-1.24.3.conda'
);
});
it('should transform conda community channel paths correctly', () => {
expect(
transformPath('/conda/community/conda-forge/linux-64/repodata.json', 'conda-community')
).toBe('/conda-forge/linux-64/repodata.json');
});
it('should transform container registry paths correctly', () => {
expect(
transformPath('/cr/ghcr/v2/nginxinc/nginx-unprivileged/manifests/latest', 'cr-ghcr')
).toBe('/v2/nginxinc/nginx-unprivileged/manifests/latest');
expect(transformPath('/cr/gcr/v2/distroless/base/manifests/latest', 'cr-gcr')).toBe(
'/v2/distroless/base/manifests/latest'
);
});
});
describe('Platform Base URLs', () => {
it('should have correct GitHub base URL', () => {
expect(PLATFORMS.gh).toBe('https://github.com');
});
it('should have correct GitLab base URL', () => {
expect(PLATFORMS.gl).toBe('https://gitlab.com');
});
it('should have correct SourceForge base URL', () => {
expect(PLATFORMS.sf).toBe('https://sourceforge.net');
});
it('should have correct Gitea base URL', () => {
expect(PLATFORMS.gitea).toBe('https://gitea.com');
});
it('should have correct Codeberg base URL', () => {
expect(PLATFORMS.codeberg).toBe('https://codeberg.org');
});
it('should have correct Hugging Face base URL', () => {
expect(PLATFORMS.hf).toBe('https://huggingface.co');
});
it('should have correct npm base URL', () => {
expect(PLATFORMS.npm).toBe('https://registry.npmjs.org');
});
it('should have correct PyPI base URL', () => {
expect(PLATFORMS.pypi).toBe('https://pypi.org');
});
it('should have correct PyPI files base URL', () => {
expect(PLATFORMS['pypi-files']).toBe('https://files.pythonhosted.org');
});
it('should have correct conda base URLs', () => {
expect(PLATFORMS.conda).toBe('https://repo.anaconda.com');
expect(PLATFORMS['conda-community']).toBe('https://conda.anaconda.org');
});
it('should have correct container registry base URLs', () => {
expect(PLATFORMS['cr-ghcr']).toBe('https://ghcr.io');
expect(PLATFORMS['cr-gcr']).toBe('https://gcr.io');
expect(PLATFORMS['cr-mcr']).toBe('https://mcr.microsoft.com');
});
});
describe('Path Transformation Edge Cases', () => {
it('should handle empty paths gracefully', () => {
Object.keys(PLATFORMS).forEach(key => {
expect(() => transformPath('', key)).not.toThrow();
});
});
it('should handle paths without platform prefix', () => {
Object.keys(PLATFORMS).forEach(key => {
const testPath = '/some/random/path';
expect(() => transformPath(testPath, key)).not.toThrow();
});
});
it('should handle unknown platform keys', () => {
const testPath = '/unknown/test/path';
expect(transformPath(testPath, 'unknown')).toBe(testPath);
});
it('should handle paths with query parameters', () => {
expect(transformPath('/gh/user/repo/file.txt?ref=main', 'gh')).toBe(
'/user/repo/file.txt?ref=main'
);
});
it('should handle paths with fragments', () => {
expect(transformPath('/gh/user/repo/README.md#section', 'gh')).toBe(
'/user/repo/README.md#section'
);
});
});
describe('URL Construction', () => {
it('should construct valid URLs for all platforms', () => {
Object.entries(PLATFORMS).forEach(([key, baseUrl]) => {
const testPath = `/${key.replace('-', '/')}/test/path`;
const transformedPath = transformPath(testPath, key);
const fullUrl = baseUrl + transformedPath;
expect(() => new URL(fullUrl)).not.toThrow();
});
});
it('should handle container registry URL construction', () => {
const testPath = '/cr/ghcr/v2/nginxinc/nginx-unprivileged/manifests/latest';
const transformedPath = transformPath(testPath, 'cr-ghcr');
const fullUrl = PLATFORMS['cr-ghcr'] + transformedPath;
expect(() => new URL(fullUrl)).not.toThrow();
expect(fullUrl).toBe('https://ghcr.io/v2/nginxinc/nginx-unprivileged/manifests/latest');
});
});
describe('Jenkins Plugin Support', () => {
it('should have Jenkins platform defined', () => {
expect(PLATFORMS).toHaveProperty('jenkins');
expect(PLATFORMS.jenkins).toBe('https://updates.jenkins.io');
});
it('should transform Jenkins paths correctly', () => {
// Update center JSON - should be redirected to current
expect(transformPath('/jenkins/update-center.json', 'jenkins')).toBe(
'/current/update-center.json'
);
expect(transformPath('/jenkins/update-center.actual.json', 'jenkins')).toBe(
'/current/update-center.actual.json'
);
// Plugin downloads - should preserve download paths
expect(
transformPath('/jenkins/download/plugins/maven-plugin/3.27/maven-plugin.hpi', 'jenkins')
).toBe('/download/plugins/maven-plugin/3.27/maven-plugin.hpi');
// Experimental update center - should preserve experimental paths
expect(transformPath('/jenkins/experimental/update-center.json', 'jenkins')).toBe(
'/experimental/update-center.json'
);
// Current paths - should preserve current paths
expect(transformPath('/jenkins/current/update-center.json', 'jenkins')).toBe(
'/current/update-center.json'
);
// Other paths - should be prefixed with current
expect(transformPath('/jenkins/test-path', 'jenkins')).toBe('/current/test-path');
});
it('should construct valid URLs for Jenkins services', () => {
const jenkinsUrls = [
'/jenkins/update-center.json',
'/jenkins/download/plugins/git/5.2.1/git.hpi',
'/jenkins/experimental/update-center.json',
'/jenkins/current/update-center.actual.json'
];
jenkinsUrls.forEach(path => {
const transformedPath = transformPath(path, 'jenkins');
const fullUrl = PLATFORMS.jenkins + transformedPath;
expect(() => new URL(fullUrl)).not.toThrow();
});
});
});
describe('Container Registry Support', () => {
it('should have all major container registries defined', () => {
const containerRegistries = [
'cr-quay',
'cr-gcr',
'cr-mcr',
'cr-ecr',
'cr-ghcr',
'cr-gitlab',
'cr-redhat',
'cr-oracle',
'cr-cloudsmith',
'cr-digitalocean',
'cr-vmware',
'cr-k8s',
'cr-heroku',
'cr-suse',
'cr-opensuse',
'cr-gitpod'
];
containerRegistries.forEach(registry => {
expect(PLATFORMS).toHaveProperty(registry);
expect(PLATFORMS[registry]).toBeDefined();
expect(typeof PLATFORMS[registry]).toBe('string');
});
});
it('should transform all container registry paths correctly', () => {
const containerRegistries = [
'cr-quay',
'cr-gcr',
'cr-mcr',
'cr-ecr',
'cr-ghcr',
'cr-gitlab',
'cr-redhat',
'cr-oracle',
'cr-cloudsmith',
'cr-digitalocean',
'cr-vmware',
'cr-k8s',
'cr-heroku',
'cr-suse',
'cr-opensuse',
'cr-gitpod'
];
containerRegistries.forEach(registry => {
const prefix = registry.replace('cr-', 'cr/');
const testPath = `/${prefix}/v2/test/image/manifests/latest`;
const transformedPath = transformPath(testPath, registry);
expect(transformedPath).toBe('/v2/test/image/manifests/latest');
});
});
});
describe('AI Inference Providers Support', () => {
it('should have all major AI inference providers defined', () => {
const aiProviders = [
'ip-openai',
'ip-anthropic',
'ip-gemini',
'ip-vertexai',
'ip-cohere',
'ip-mistralai',
'ip-xai',
'ip-githubmodels',
'ip-nvidiaapi',
'ip-perplexity',
'ip-braintrust',
'ip-groq',
'ip-cerebras',
'ip-sambanova',
'ip-huggingface',
'ip-together',
'ip-replicate',
'ip-fireworks',
'ip-nebius',
'ip-jina',
'ip-voyageai',
'ip-falai',
'ip-novita',
'ip-burncloud',
'ip-openrouter',
'ip-poe',
'ip-featherlessai',
'ip-hyperbolic'
];
aiProviders.forEach(provider => {
expect(PLATFORMS).toHaveProperty(provider);
expect(PLATFORMS[provider]).toBeDefined();
expect(typeof PLATFORMS[provider]).toBe('string');
expect(PLATFORMS[provider]).toMatch(/^https:\/\/.+/);
});
});
it('should transform AI inference provider paths correctly', () => {
const testCases = [
{
provider: 'ip-openai',
inputPath: '/ip/openai/v1/chat/completions',
expectedPath: '/v1/chat/completions'
},
{
provider: 'ip-anthropic',
inputPath: '/ip/anthropic/v1/messages',
expectedPath: '/v1/messages'
},
{
provider: 'ip-gemini',
inputPath: '/ip/gemini/v1beta/models/gemini-2.5-flash:generateContent',
expectedPath: '/v1beta/models/gemini-2.5-flash:generateContent'
},
{
provider: 'ip-cohere',
inputPath: '/ip/cohere/v1/generate',
expectedPath: '/v1/generate'
},
{
provider: 'ip-huggingface',
inputPath: '/ip/huggingface/models/meta-llama/Llama-2-7b-chat-hf',
expectedPath: '/models/meta-llama/Llama-2-7b-chat-hf'
},
{
provider: 'ip-together',
inputPath: '/ip/together/v1/chat/completions',
expectedPath: '/v1/chat/completions'
},
{
provider: 'ip-replicate',
inputPath: '/ip/replicate/v1/predictions',
expectedPath: '/v1/predictions'
},
{
provider: 'ip-groq',
inputPath: '/ip/groq/openai/v1/chat/completions',
expectedPath: '/openai/v1/chat/completions'
}
];
testCases.forEach(({ provider, inputPath, expectedPath }) => {
const transformedPath = transformPath(inputPath, provider);
expect(transformedPath).toBe(expectedPath);
});
});
it('should construct valid URLs for AI inference providers', () => {
const aiProviders = [
'ip-openrouter',
'ip-openai',
'ip-anthropic',
'ip-gemini',
'ip-cohere',
'ip-huggingface',
'ip-together',
'ip-replicate',
'ip-groq',
'ip-fireworks',
'ip-mistralai',
'ip-perplexity'
];
aiProviders.forEach(provider => {
const testPath = `/ip/${provider.replace('ip-', '')}/v1/test`;
const transformedPath = transformPath(testPath, provider);
const baseUrl = PLATFORMS[provider];
// Skip dynamic URLs with placeholders
if (!baseUrl.includes('{')) {
const fullUrl = baseUrl + transformedPath;
expect(() => new URL(fullUrl)).not.toThrow();
}
});
});
});
});