forked from aws/agentcore-cli
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patherrors.test.ts
More file actions
207 lines (179 loc) · 7.98 KB
/
Copy patherrors.test.ts
File metadata and controls
207 lines (179 loc) · 7.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import {
AgentAlreadyExistsError,
getErrorMessage,
isChangesetInProgressError,
isExpiredTokenError,
isNoCredentialsError,
isStackInProgressError,
} from '../errors.js';
import { describe, expect, it } from 'vitest';
describe('errors', () => {
describe('AgentAlreadyExistsError', () => {
it('has correct message with agent name', () => {
const err = new AgentAlreadyExistsError('my-agent');
expect(err.message).toBe('An agent named "my-agent" already exists in the schema.');
});
it('has correct name', () => {
const err = new AgentAlreadyExistsError('test');
expect(err.name).toBe('AgentAlreadyExistsError');
});
it('is instance of Error', () => {
expect(new AgentAlreadyExistsError('test')).toBeInstanceOf(Error);
});
});
describe('getErrorMessage', () => {
it('returns message from Error instance', () => {
const err = new Error('test error');
expect(getErrorMessage(err)).toBe('test error');
});
it('returns string for non-Error values', () => {
expect(getErrorMessage('raw error')).toBe('raw error');
expect(getErrorMessage(123)).toBe('123');
expect(getErrorMessage(null)).toBe('null');
expect(getErrorMessage(undefined)).toBe('undefined');
});
});
describe('isExpiredTokenError', () => {
// Test ALL error codes in EXPIRED_TOKEN_ERROR_CODES via error.name
const allErrorCodes = [
'ExpiredToken',
'ExpiredTokenException',
'TokenRefreshRequired',
'CredentialsExpired',
'InvalidIdentityToken',
'UnauthorizedAccess',
'InvalidClientTokenId',
'SignatureDoesNotMatch',
'RequestExpired',
];
it('returns true for all SDK v3 error names', () => {
for (const code of allErrorCodes) {
expect(isExpiredTokenError({ name: code }), `Should detect error.name: ${code}`).toBe(true);
}
});
it('returns true for all error Code properties', () => {
for (const code of allErrorCodes) {
expect(isExpiredTokenError({ Code: code }), `Should detect error.Code: ${code}`).toBe(true);
}
});
it('returns true for nested cause with error name', () => {
expect(isExpiredTokenError({ cause: { name: 'ExpiredToken' } })).toBe(true);
});
it('returns true for double-nested cause', () => {
expect(isExpiredTokenError({ cause: { cause: { name: 'ExpiredToken' } } })).toBe(true);
});
it('returns true for nested cause with Code', () => {
expect(isExpiredTokenError({ cause: { Code: 'ExpiredToken' } })).toBe(true);
});
it('returns true for message patterns', () => {
const patterns = [
'expired token',
'token has expired',
'credentials have expired',
'security token included in the request is expired',
'the security token included in the request is invalid',
];
for (const pattern of patterns) {
expect(isExpiredTokenError(new Error(pattern)), `Should detect message: ${pattern}`).toBe(true);
}
});
it('returns false for non-expired errors', () => {
expect(isExpiredTokenError({ name: 'ValidationError' })).toBe(false);
expect(isExpiredTokenError({ Code: 'ResourceNotFound' })).toBe(false);
expect(isExpiredTokenError(new Error('some other error'))).toBe(false);
});
it('returns false for AccessDenied errors (authorization, not authentication)', () => {
// AccessDenied errors indicate authorization failures (wrong account, missing IAM permissions),
// NOT token expiration. Users should see the actual AccessDenied error, not "credentials expired".
expect(isExpiredTokenError({ name: 'AccessDenied' })).toBe(false);
expect(isExpiredTokenError({ name: 'AccessDeniedException' })).toBe(false);
expect(isExpiredTokenError({ Code: 'AccessDenied' })).toBe(false);
expect(isExpiredTokenError({ Code: 'AccessDeniedException' })).toBe(false);
expect(isExpiredTokenError({ cause: { name: 'AccessDenied' } })).toBe(false);
expect(isExpiredTokenError(new Error('AccessDenied: User is not authorized'))).toBe(false);
});
it('returns false for edge cases', () => {
expect(isExpiredTokenError(null)).toBe(false);
expect(isExpiredTokenError(undefined)).toBe(false);
expect(isExpiredTokenError('string')).toBe(false);
expect(isExpiredTokenError(123)).toBe(false);
expect(isExpiredTokenError({})).toBe(false);
expect(isExpiredTokenError({ name: 123 })).toBe(false); // non-string name
expect(isExpiredTokenError({ Code: 123 })).toBe(false); // non-string Code
});
});
describe('isNoCredentialsError', () => {
it('returns true for AwsCredentialsError', () => {
expect(isNoCredentialsError({ name: 'AwsCredentialsError' })).toBe(true);
});
it('returns true for message patterns', () => {
const patterns = ['no aws credentials found', 'could not load credentials', 'credentials not found'];
for (const pattern of patterns) {
expect(isNoCredentialsError(new Error(pattern)), `Should detect message: ${pattern}`).toBe(true);
}
});
it('returns false for other errors', () => {
expect(isNoCredentialsError({ name: 'ExpiredTokenException' })).toBe(false);
expect(isNoCredentialsError(new Error('some other error'))).toBe(false);
});
it('returns false for edge cases', () => {
expect(isNoCredentialsError(null)).toBe(false);
expect(isNoCredentialsError(undefined)).toBe(false);
expect(isNoCredentialsError('string')).toBe(false);
expect(isNoCredentialsError(123)).toBe(false);
expect(isNoCredentialsError({})).toBe(false);
});
});
describe('isStackInProgressError', () => {
it('returns true for in-progress states', () => {
const states = ['UPDATE_IN_PROGRESS', 'CREATE_IN_PROGRESS', 'DELETE_IN_PROGRESS', 'ROLLBACK_IN_PROGRESS'];
for (const state of states) {
expect(isStackInProgressError(new Error(`Stack is in ${state} state`)), `Should detect state: ${state}`).toBe(
true
);
}
});
it('returns true for state and cannot be updated pattern', () => {
expect(
isStackInProgressError(new Error('Stack is in UPDATE_ROLLBACK_IN_PROGRESS state and cannot be updated'))
).toBe(true);
});
it('returns true for currently being updated', () => {
expect(isStackInProgressError(new Error('stack is currently being updated'))).toBe(true);
});
it('returns false for other errors', () => {
expect(isStackInProgressError(new Error('Stack not found'))).toBe(false);
expect(isStackInProgressError(new Error('some other error'))).toBe(false);
});
it('returns false for edge cases', () => {
expect(isStackInProgressError(null)).toBe(false);
expect(isStackInProgressError(undefined)).toBe(false);
expect(isStackInProgressError({})).toBe(false);
});
});
describe('isChangesetInProgressError', () => {
it('returns true for InvalidChangeSetStatus errors', () => {
expect(
isChangesetInProgressError(
new Error('InvalidChangeSetStatusException: An operation on this ChangeSet is currently in progress.')
)
).toBe(true);
});
it('returns true for changeset in progress message patterns', () => {
expect(isChangesetInProgressError(new Error('ChangeSet is currently in progress'))).toBe(true);
expect(isChangesetInProgressError(new Error('An operation on this changeset is currently in progress'))).toBe(
true
);
});
it('returns false for other errors', () => {
expect(isChangesetInProgressError(new Error('Stack not found'))).toBe(false);
expect(isChangesetInProgressError(new Error('some other error'))).toBe(false);
expect(isChangesetInProgressError(new Error('UPDATE_IN_PROGRESS'))).toBe(false);
});
it('returns false for edge cases', () => {
expect(isChangesetInProgressError(null)).toBe(false);
expect(isChangesetInProgressError(undefined)).toBe(false);
expect(isChangesetInProgressError({})).toBe(false);
});
});
});