Skip to content

Commit 57ae68a

Browse files
committed
Improve error handling while fetching subscriptions
1 parent cdfeb82 commit 57ae68a

2 files changed

Lines changed: 78 additions & 5 deletions

File tree

packages/server/api/src/app/benchmark/providers/azure/azure-option-resolver.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,28 @@ async function getSubscriptionsList(
4949
});
5050

5151
const credentials = (connection.value as CustomAuthConnectionValue)?.props;
52-
const tokenResult = await authenticateUserWithAzure(credentials);
53-
const subscriptions = await getAzureSubscriptionsList(
54-
tokenResult.access_token,
55-
);
52+
53+
if (!credentials || typeof credentials !== 'object') {
54+
throwValidationError(
55+
'Selected connection is misconfigured or missing Azure credentials.',
56+
);
57+
}
58+
59+
let subscriptions: { subscriptionId: string; displayName: string }[];
60+
try {
61+
const tokenResult = await authenticateUserWithAzure(credentials);
62+
subscriptions = await getAzureSubscriptionsList(tokenResult.access_token);
63+
} catch {
64+
throwValidationError(
65+
'Unable to retrieve Azure subscriptions with the provided connection details.',
66+
);
67+
}
68+
69+
if (subscriptions.length === 0) {
70+
throwValidationError(
71+
'No Azure subscriptions were returned for this connection. Check access and tenant configuration.',
72+
);
73+
}
5674

5775
const imageLogoUrl = await getAuthProviderLogoUrl(
5876
connection.authProviderKey,

packages/server/api/test/unit/benchmark/providers/azure/azure-option-resolver.test.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { REGION_IMAGE_LOGO_URL } from '@openops/shared';
1+
import { ErrorCode, REGION_IMAGE_LOGO_URL } from '@openops/shared';
22

33
import { resolveOptions } from '../../../../../src/app/benchmark/providers/azure/azure-option-resolver';
44

@@ -178,6 +178,61 @@ describe('resolveOptions (Azure)', () => {
178178
expect(result).toEqual([{ id: 'sub-1', displayName: 'One' }]);
179179
});
180180

181+
it('throws validation error when subscriptions list is empty', async () => {
182+
mockGetOneOrThrow.mockResolvedValue({
183+
authProviderKey: 'Azure',
184+
value: {
185+
type: 'CUSTOM_AUTH',
186+
props: {
187+
clientId: 'client_id',
188+
clientSecret: 'client_secret',
189+
tenantId: 'tenant',
190+
},
191+
},
192+
});
193+
mockAuthenticateUserWithAzure.mockResolvedValue({ access_token: 't' });
194+
mockGetAzureSubscriptionsList.mockResolvedValue([]);
195+
196+
const rejection = resolveOptions('getSubscriptionsList', {
197+
projectId,
198+
provider,
199+
benchmarkConfiguration: { connection: ['c1'] },
200+
});
201+
await expect(rejection).rejects.toMatchObject({
202+
error: { code: ErrorCode.VALIDATION },
203+
});
204+
await expect(rejection).rejects.toThrow(
205+
/No Azure subscriptions were returned for this connection/,
206+
);
207+
});
208+
209+
it('throws validation error when subscription listing fails', async () => {
210+
mockGetOneOrThrow.mockResolvedValue({
211+
authProviderKey: 'Azure',
212+
value: {
213+
type: 'CUSTOM_AUTH',
214+
props: {
215+
clientId: 'client_id',
216+
clientSecret: 'client_secret',
217+
tenantId: 'tenant',
218+
},
219+
},
220+
});
221+
mockAuthenticateUserWithAzure.mockRejectedValue(new Error('token failed'));
222+
223+
const rejection = resolveOptions('getSubscriptionsList', {
224+
projectId,
225+
provider,
226+
benchmarkConfiguration: { connection: ['c1'] },
227+
});
228+
await expect(rejection).rejects.toMatchObject({
229+
error: { code: ErrorCode.VALIDATION },
230+
});
231+
await expect(rejection).rejects.toThrow(
232+
/Unable to retrieve Azure subscriptions with the provided connection details/,
233+
);
234+
});
235+
181236
it('delegates to getAzureRegionsList and returns options with imageLogoUrl for getRegionsList', async () => {
182237
const regionsList = [
183238
{ id: 'eastus', displayName: 'East US' },

0 commit comments

Comments
 (0)