mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-03 11:03:39 +00:00
05e1271376
Enables the vitest/prefer-expect-resolves oxlint rule and applies its autofix across the spec suite.
287 lines
8.9 KiB
TypeScript
287 lines
8.9 KiB
TypeScript
import type { WebApi } from 'azure-devops-node-api';
|
|
import type { DeploymentFlags } from 'azure-devops-node-api/interfaces/common/VSSInterfaces.js';
|
|
import { buildTestJwt } from '~test/jwt-util.ts';
|
|
import { logger } from '~test/util.ts';
|
|
import type * as _hostRules from '../../../util/host-rules.ts';
|
|
|
|
describe('modules/platform/azure/azure-got-wrapper', () => {
|
|
let azure: typeof import('./azure-got-wrapper.ts');
|
|
let hostRules: typeof _hostRules;
|
|
|
|
beforeEach(async () => {
|
|
// reset module
|
|
vi.resetModules();
|
|
hostRules = await vi.importActual('../../../util/host-rules.ts');
|
|
azure = await vi.importActual('./azure-got-wrapper.ts');
|
|
});
|
|
|
|
describe('gitApi', () => {
|
|
it('should throw an error if no config found', () => {
|
|
expect(azure.gitApi).toThrow('No config found for azure');
|
|
expect(azure.coreApi).toThrow('No config found for azure');
|
|
expect(azure.policyApi).toThrow('No config found for azure');
|
|
expect(azure.workItemTrackingApi).toThrow('No config found for azure');
|
|
});
|
|
|
|
it('should set personal access token and endpoint', () => {
|
|
hostRules.add({
|
|
hostType: 'azure',
|
|
token: '123test',
|
|
matchHost: 'https://dev.azure.com/renovate1',
|
|
});
|
|
azure.setEndpoint('https://dev.azure.com/renovate1');
|
|
|
|
const res = azure.azureObj();
|
|
|
|
delete res.rest.client.userAgent;
|
|
delete res.vsoClient.restClient.client.userAgent;
|
|
|
|
expect(res).toMatchObject({
|
|
serverUrl: 'https://dev.azure.com/renovate1',
|
|
authHandler: {
|
|
token: '123test',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should set bearer token and endpoint', () => {
|
|
const token = buildTestJwt(
|
|
{ typ: 'JWT', alg: 'RS256' },
|
|
{ aud: '499b84ac', sub: 'test', exp: 9999999999 },
|
|
'fake-sig',
|
|
);
|
|
hostRules.add({
|
|
hostType: 'azure',
|
|
token,
|
|
matchHost: 'https://dev.azure.com/renovate2',
|
|
});
|
|
azure.setEndpoint('https://dev.azure.com/renovate2');
|
|
|
|
const res = azure.azureObj();
|
|
|
|
delete res.rest.client.userAgent;
|
|
delete res.vsoClient.restClient.client.userAgent;
|
|
|
|
expect(res).toMatchObject({
|
|
serverUrl: 'https://dev.azure.com/renovate2',
|
|
authHandler: {
|
|
token,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should set password and endpoint', () => {
|
|
hostRules.add({
|
|
hostType: 'azure',
|
|
username: 'user',
|
|
password: 'pass',
|
|
matchHost: 'https://dev.azure.com/renovate3',
|
|
});
|
|
azure.setEndpoint('https://dev.azure.com/renovate3');
|
|
|
|
const res = azure.azureObj();
|
|
|
|
delete res.rest.client.userAgent;
|
|
delete res.vsoClient.restClient.client.userAgent;
|
|
|
|
expect(res).toMatchObject({
|
|
serverUrl: 'https://dev.azure.com/renovate3',
|
|
authHandler: {
|
|
username: 'user',
|
|
password: 'pass',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should use BearerCredentialHandler for JWT tokens', () => {
|
|
const jwt = buildTestJwt(
|
|
{ typ: 'JWT', alg: 'RS256' },
|
|
{ aud: '499b84ac', sub: 'test', exp: 9999999999 },
|
|
'fake-sig',
|
|
);
|
|
hostRules.add({
|
|
hostType: 'azure',
|
|
token: jwt,
|
|
matchHost: 'https://dev.azure.com/renovate4',
|
|
});
|
|
azure.setEndpoint('https://dev.azure.com/renovate4');
|
|
|
|
const res = azure.azureObj();
|
|
|
|
expect(res.authHandler).toHaveProperty('token', jwt);
|
|
expect(res.authHandler.constructor.name).toBe('BearerCredentialHandler');
|
|
});
|
|
|
|
it('should use PersonalAccessTokenHandler for PAT tokens', () => {
|
|
const pat = 'a'.repeat(52);
|
|
hostRules.add({
|
|
hostType: 'azure',
|
|
token: pat,
|
|
matchHost: 'https://dev.azure.com/renovate5',
|
|
});
|
|
azure.setEndpoint('https://dev.azure.com/renovate5');
|
|
|
|
const res = azure.azureObj();
|
|
|
|
expect(res.authHandler).toHaveProperty('token', pat);
|
|
expect(res.authHandler.constructor.name).toBe(
|
|
'PersonalAccessTokenCredentialHandler',
|
|
);
|
|
});
|
|
|
|
it('should use PersonalAccessTokenHandler for short opaque tokens', () => {
|
|
hostRules.add({
|
|
hostType: 'azure',
|
|
token: 'shorttoken',
|
|
matchHost: 'https://dev.azure.com/renovate6',
|
|
});
|
|
azure.setEndpoint('https://dev.azure.com/renovate6');
|
|
|
|
const res = azure.azureObj();
|
|
|
|
expect(res.authHandler).toHaveProperty('token', 'shorttoken');
|
|
expect(res.authHandler.constructor.name).toBe(
|
|
'PersonalAccessTokenCredentialHandler',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('isHosted', () => {
|
|
let sdk: typeof import('azure-devops-node-api');
|
|
|
|
beforeEach(async () => {
|
|
sdk = await vi.importActual('azure-devops-node-api');
|
|
hostRules.add({
|
|
hostType: 'azure',
|
|
token: '123test',
|
|
matchHost: 'https://dev.azure.com/renovate7',
|
|
});
|
|
azure.setEndpoint('https://dev.azure.com/renovate7');
|
|
});
|
|
|
|
it('returns true when deployment type is Hosted', async () => {
|
|
// DeploymentFlags.Hosted === 1
|
|
vi.spyOn(sdk.WebApi.prototype, 'connect').mockResolvedValue({
|
|
deploymentType: 1,
|
|
});
|
|
|
|
await expect(azure.isHosted()).resolves.toBe(true);
|
|
});
|
|
|
|
it('returns true when deployment type is the serialized enum name', async () => {
|
|
vi.spyOn(sdk.WebApi.prototype, 'connect').mockResolvedValue({
|
|
deploymentType: 'hosted' as unknown as DeploymentFlags,
|
|
});
|
|
|
|
await expect(azure.isHosted()).resolves.toBe(true);
|
|
});
|
|
|
|
it('returns false when deployment type is OnPremises', async () => {
|
|
// DeploymentFlags.OnPremises === 2
|
|
vi.spyOn(sdk.WebApi.prototype, 'connect').mockResolvedValue({
|
|
deploymentType: 2,
|
|
});
|
|
|
|
await expect(azure.isHosted()).resolves.toBe(false);
|
|
});
|
|
|
|
it('returns false when deployment type is the on-premises enum name', async () => {
|
|
vi.spyOn(sdk.WebApi.prototype, 'connect').mockResolvedValue({
|
|
deploymentType: 'onPremises' as unknown as DeploymentFlags,
|
|
});
|
|
|
|
await expect(azure.isHosted()).resolves.toBe(false);
|
|
});
|
|
|
|
it('returns false when connectionData cannot be read', async () => {
|
|
vi.spyOn(sdk.WebApi.prototype, 'connect').mockRejectedValue(
|
|
new Error('boom'),
|
|
);
|
|
|
|
await expect(azure.isHosted()).resolves.toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getAuthenticatedUserId', () => {
|
|
let sdk: typeof import('azure-devops-node-api');
|
|
|
|
beforeEach(async () => {
|
|
sdk = await vi.importActual('azure-devops-node-api');
|
|
azure.setEndpoint('https://dev.azure.com/renovate8');
|
|
});
|
|
|
|
it('returns the authenticated user ID using PAT credentials', async () => {
|
|
const connect = vi
|
|
.spyOn(sdk.WebApi.prototype, 'connect')
|
|
.mockResolvedValue({ authenticatedUser: { id: 'user-id' } });
|
|
|
|
await expect(
|
|
azure.getAuthenticatedUserId({ token: '123test' }),
|
|
).resolves.toBe('user-id');
|
|
const context = connect.mock.contexts[0] as WebApi;
|
|
expect(context.authHandler.constructor.name).toBe(
|
|
'PersonalAccessTokenCredentialHandler',
|
|
);
|
|
});
|
|
|
|
it('returns the authenticated user ID using JWT credentials', async () => {
|
|
const token = buildTestJwt(
|
|
{ typ: 'JWT', alg: 'RS256' },
|
|
{ aud: '499b84ac', sub: 'test', exp: 9999999999 },
|
|
'fake-sig',
|
|
);
|
|
const connect = vi
|
|
.spyOn(sdk.WebApi.prototype, 'connect')
|
|
.mockResolvedValue({ authenticatedUser: { id: 'user-id' } });
|
|
|
|
await expect(azure.getAuthenticatedUserId({ token })).resolves.toBe(
|
|
'user-id',
|
|
);
|
|
const context = connect.mock.contexts[0] as WebApi;
|
|
expect(context.authHandler.constructor.name).toBe(
|
|
'BearerCredentialHandler',
|
|
);
|
|
});
|
|
|
|
it('returns the authenticated user ID using username and password', async () => {
|
|
const connect = vi
|
|
.spyOn(sdk.WebApi.prototype, 'connect')
|
|
.mockResolvedValue({ authenticatedUser: { id: 'user-id' } });
|
|
|
|
await expect(
|
|
azure.getAuthenticatedUserId({
|
|
username: 'user',
|
|
password: 'pass',
|
|
}),
|
|
).resolves.toBe('user-id');
|
|
const context = connect.mock.contexts[0] as WebApi;
|
|
expect(context.authHandler).toMatchObject({
|
|
username: 'user',
|
|
password: 'pass',
|
|
});
|
|
});
|
|
|
|
it('returns undefined when the authenticated user ID is unavailable', async () => {
|
|
vi.spyOn(sdk.WebApi.prototype, 'connect').mockResolvedValue({});
|
|
|
|
await expect(
|
|
azure.getAuthenticatedUserId({ token: '123test' }),
|
|
).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('returns undefined when connection data cannot be read', async () => {
|
|
vi.spyOn(sdk.WebApi.prototype, 'connect').mockRejectedValue(
|
|
new Error('boom'),
|
|
);
|
|
|
|
await expect(
|
|
azure.getAuthenticatedUserId({ token: '123test' }),
|
|
).resolves.toBeUndefined();
|
|
expect(logger.logger.debug).toHaveBeenCalledWith(
|
|
{ err: new Error('boom') },
|
|
'Azure: could not determine authenticated user ID',
|
|
);
|
|
});
|
|
});
|
|
});
|