Skip to content

Commit d4fcfc9

Browse files
committed
fix: userConsent req to return specific http sts codes
Signed-off-by: Cheah, Kit Hwa <[email protected]>
1 parent ee71352 commit d4fcfc9

File tree

7 files changed

+375
-18
lines changed

7 files changed

+375
-18
lines changed

src/routes/amt/userConsent/cancel.test.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('cancel user consent code', () => {
4646
expect(resSpy.status).toHaveBeenCalledWith(200)
4747
expect(resSpy.json).toHaveBeenCalledWith(result)
4848
})
49-
it('Should give an error when return value is not 0', async () => {
49+
it('should return 409 when return value is NOT_READY', async () => {
5050
const result = {
5151
Header: {
5252
To: 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
@@ -62,11 +62,54 @@ describe('cancel user consent code', () => {
6262
}
6363
}
6464
}
65-
const response = { Header: result.Header, Body: result.Body.CancelOptIn_OUTPUT }
65+
cancelUserConsetCodeSpy.mockResolvedValueOnce(result)
66+
await cancel(req, resSpy)
67+
expect(resSpy.status).toHaveBeenCalledWith(409)
68+
expect(resSpy.json).toHaveBeenCalledWith(expect.objectContaining({
69+
error: 'Conflict',
70+
message: expect.any(String),
71+
details: expect.any(Object),
72+
amtResponse: expect.objectContaining({
73+
Header: result.Header,
74+
Body: expect.objectContaining({
75+
ReturnValue: '2',
76+
ReturnValueStr: 'NOT_READY'
77+
})
78+
})
79+
}))
80+
})
81+
82+
it('should return 400 for other non-zero return values', async () => {
83+
const result = {
84+
Header: {
85+
To: 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
86+
RelatesTo: '0',
87+
Action: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService/CancelOptInResponse',
88+
MessageID: 'uuid:00000000-8086-8086-8086-000000000786',
89+
ResourceURI: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService'
90+
},
91+
Body: {
92+
CancelOptIn_OUTPUT: {
93+
ReturnValue: '1',
94+
ReturnValueStr: 'INTERNAL_ERROR'
95+
}
96+
}
97+
}
6698
cancelUserConsetCodeSpy.mockResolvedValueOnce(result)
6799
await cancel(req, resSpy)
68100
expect(resSpy.status).toHaveBeenCalledWith(400)
69-
expect(resSpy.json).toHaveBeenCalledWith(response)
101+
expect(resSpy.json).toHaveBeenCalledWith(expect.objectContaining({
102+
error: 'Bad Request',
103+
message: expect.stringContaining('INTERNAL_ERROR'),
104+
details: expect.any(Object),
105+
amtResponse: expect.objectContaining({
106+
Header: result.Header,
107+
Body: expect.objectContaining({
108+
ReturnValue: '1',
109+
ReturnValueStr: 'INTERNAL_ERROR'
110+
})
111+
})
112+
}))
70113
})
71114
it('should get an error with status code 400, when failed to cancel user consent code', async () => {
72115
cancelUserConsetCodeSpy.mockResolvedValueOnce(null)

src/routes/amt/userConsent/cancel.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { logger, messages } from '../../../logging/index.js'
88
import { ErrorResponse } from '../../../utils/amtHelper.js'
99
import { MqttProvider } from '../../../utils/MqttProvider.js'
1010
import { AMTStatusCodes } from '../../../utils/constants.js'
11+
import { mapAMTReturnValueToHttpStatus, getDetailedErrorMessage } from './statusMapper.js'
1112

1213
export async function cancel(req: Request, res: Response): Promise<void> {
1314
try {
@@ -20,13 +21,23 @@ export async function cancel(req: Request, res: Response): Promise<void> {
2021
Body: response.Body.CancelOptIn_OUTPUT
2122
}
2223
result.Body.ReturnValueStr = AMTStatusCodes[result.Body.ReturnValue]
24+
2325
if (result.Body?.ReturnValue.toString() === '0') {
2426
MqttProvider.publishEvent('success', ['Cancel_User_Consent_Code'], messages.USER_CONSENT_CANCEL_SUCCESS, guid)
2527
res.status(200).json(result)
26-
} else if (result.Body?.ReturnValue.toString() !== '0') {
27-
logger.error(`${messages.USER_CONSENT_CANCEL_FAILED} : ${guid}.`)
28+
} else {
29+
// Map AMT return value to appropriate HTTP status code
30+
const httpStatus = mapAMTReturnValueToHttpStatus(result.Body.ReturnValueStr)
31+
const errorDetail = getDetailedErrorMessage(result.Body.ReturnValue, result.Body.ReturnValueStr, 'cancel')
32+
33+
logger.error(`${messages.USER_CONSENT_CANCEL_FAILED} : ${guid}. ReturnValue: ${result.Body.ReturnValue} (${result.Body.ReturnValueStr})`)
2834
MqttProvider.publishEvent('fail', ['Cancel_User_Consent_Code'], messages.USER_CONSENT_CANCEL_FAILED, guid)
29-
res.status(400).json(result)
35+
36+
// Return detailed error response with original AMT data
37+
res.status(httpStatus).json({
38+
...errorDetail,
39+
amtResponse: result
40+
})
3041
}
3142
} else {
3243
logger.error(`${messages.USER_CONSENT_CANCEL_FAILED} for guid : ${guid}.`)

src/routes/amt/userConsent/request.test.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('request user consent code', () => {
4646
expect(resSpy.status).toHaveBeenCalledWith(200)
4747
expect(resSpy.json).toHaveBeenCalledWith(result)
4848
})
49-
it('Should give an error when return value is not 0', async () => {
49+
it('should return 409 when return value is NOT_READY', async () => {
5050
const result = {
5151
Header: {
5252
To: 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
@@ -62,11 +62,54 @@ describe('request user consent code', () => {
6262
}
6363
}
6464
}
65-
const response = { Header: result.Header, Body: result.Body.StartOptIn_OUTPUT }
65+
requestUserConsetCodeSpy.mockResolvedValueOnce(result)
66+
await request(req, resSpy)
67+
expect(resSpy.status).toHaveBeenCalledWith(409)
68+
expect(resSpy.json).toHaveBeenCalledWith(expect.objectContaining({
69+
error: 'Conflict',
70+
message: expect.any(String),
71+
details: expect.any(Object),
72+
amtResponse: expect.objectContaining({
73+
Header: result.Header,
74+
Body: expect.objectContaining({
75+
ReturnValue: '2',
76+
ReturnValueStr: 'NOT_READY'
77+
})
78+
})
79+
}))
80+
})
81+
82+
it('should return 400 for other non-zero return values', async () => {
83+
const result = {
84+
Header: {
85+
To: 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
86+
RelatesTo: '0',
87+
Action: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService/StartOptInResponse',
88+
MessageID: 'uuid:00000000-8086-8086-8086-00000000008D',
89+
ResourceURI: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService'
90+
},
91+
Body: {
92+
StartOptIn_OUTPUT: {
93+
ReturnValue: '1',
94+
ReturnValueStr: 'INTERNAL_ERROR'
95+
}
96+
}
97+
}
6698
requestUserConsetCodeSpy.mockResolvedValueOnce(result)
6799
await request(req, resSpy)
68100
expect(resSpy.status).toHaveBeenCalledWith(400)
69-
expect(resSpy.json).toHaveBeenCalledWith(response)
101+
expect(resSpy.json).toHaveBeenCalledWith(expect.objectContaining({
102+
error: 'Bad Request',
103+
message: expect.stringContaining('INTERNAL_ERROR'),
104+
details: expect.any(Object),
105+
amtResponse: expect.objectContaining({
106+
Header: result.Header,
107+
Body: expect.objectContaining({
108+
ReturnValue: '1',
109+
ReturnValueStr: 'INTERNAL_ERROR'
110+
})
111+
})
112+
}))
70113
})
71114
it('should get an error with status code 400, when failed to request user consent code', async () => {
72115
requestUserConsetCodeSpy.mockResolvedValueOnce(null)

src/routes/amt/userConsent/request.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { logger, messages } from '../../../logging/index.js'
88
import { ErrorResponse } from '../../../utils/amtHelper.js'
99
import { MqttProvider } from '../../../utils/MqttProvider.js'
1010
import { AMTStatusCodes } from '../../../utils/constants.js'
11+
import { mapAMTReturnValueToHttpStatus, getDetailedErrorMessage } from './statusMapper.js'
1112

1213
export async function request(req: Request, res: Response): Promise<void> {
1314
try {
@@ -20,13 +21,23 @@ export async function request(req: Request, res: Response): Promise<void> {
2021
Body: response.Body.StartOptIn_OUTPUT
2122
}
2223
result.Body.ReturnValueStr = AMTStatusCodes[result.Body.ReturnValue]
24+
2325
if (result.Body.ReturnValue.toString() === '0') {
2426
MqttProvider.publishEvent('success', ['Request_User_Consent_Code'], messages.USER_CONSENT_REQUEST_SUCCESS, guid)
2527
res.status(200).json(result)
2628
} else {
27-
logger.error(`${messages.USER_CONSENT_REQUEST_FAILED} for guid : ${guid}.`)
29+
// Map AMT return value to appropriate HTTP status code
30+
const httpStatus = mapAMTReturnValueToHttpStatus(result.Body.ReturnValueStr)
31+
const errorDetail = getDetailedErrorMessage(result.Body.ReturnValue, result.Body.ReturnValueStr, 'request')
32+
33+
logger.error(`${messages.USER_CONSENT_REQUEST_FAILED} for guid : ${guid}. ReturnValue: ${result.Body.ReturnValue} (${result.Body.ReturnValueStr})`)
2834
MqttProvider.publishEvent('fail', ['Request_User_Consent_Code'], messages.USER_CONSENT_REQUEST_FAILED, guid)
29-
res.status(400).json(result)
35+
36+
// Return detailed error response with original AMT data
37+
res.status(httpStatus).json({
38+
...errorDetail,
39+
amtResponse: result
40+
})
3041
}
3142
} else {
3243
logger.error(`${messages.USER_CONSENT_REQUEST_FAILED} for guid : ${guid}.`)

src/routes/amt/userConsent/send.test.ts

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('send user consent code', () => {
4747
expect(resSpy.status).toHaveBeenCalledWith(200)
4848
expect(resSpy.json).toHaveBeenCalledWith(result)
4949
})
50-
it('Should give an error when return value is not 0', async () => {
50+
it('should return 409 when return value is NOT_READY', async () => {
5151
const result = {
5252
Header: {
5353
To: 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
@@ -63,11 +63,87 @@ describe('send user consent code', () => {
6363
}
6464
}
6565
}
66-
const response = { Header: result.Header, Body: result.Body.SendOptInCode_OUTPUT }
66+
sendUserConsetCodeSpy.mockResolvedValueOnce(result)
67+
await send(req, resSpy)
68+
expect(resSpy.status).toHaveBeenCalledWith(409)
69+
expect(resSpy.json).toHaveBeenCalledWith(expect.objectContaining({
70+
error: 'Conflict',
71+
message: expect.any(String),
72+
details: expect.any(Object),
73+
amtResponse: expect.objectContaining({
74+
Header: result.Header,
75+
Body: expect.objectContaining({
76+
ReturnValue: '2',
77+
ReturnValueStr: 'NOT_READY'
78+
})
79+
})
80+
}))
81+
})
82+
83+
it('should return 422 when return value is UNSUPPORTED (wrong consent code)', async () => {
84+
const result = {
85+
Header: {
86+
To: 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
87+
RelatesTo: '3',
88+
Action: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService/SendOptInCodeResponse',
89+
MessageID: 'uuid:00000000-8086-8086-8086-000000000093',
90+
ResourceURI: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService'
91+
},
92+
Body: {
93+
SendOptInCode_OUTPUT: {
94+
ReturnValue: '2066',
95+
ReturnValueStr: 'UNSUPPORTED'
96+
}
97+
}
98+
}
99+
sendUserConsetCodeSpy.mockResolvedValueOnce(result)
100+
await send(req, resSpy)
101+
expect(resSpy.status).toHaveBeenCalledWith(422)
102+
expect(resSpy.json).toHaveBeenCalledWith(expect.objectContaining({
103+
error: 'Unprocessable Entity',
104+
message: 'Invalid consent code provided',
105+
details: expect.any(Object),
106+
amtResponse: expect.objectContaining({
107+
Header: result.Header,
108+
Body: expect.objectContaining({
109+
ReturnValue: '2066',
110+
ReturnValueStr: 'UNSUPPORTED'
111+
})
112+
})
113+
}))
114+
})
115+
116+
it('should return 400 for other non-zero return values', async () => {
117+
const result = {
118+
Header: {
119+
To: 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
120+
RelatesTo: '3',
121+
Action: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService/SendOptInCodeResponse',
122+
MessageID: 'uuid:00000000-8086-8086-8086-000000000093',
123+
ResourceURI: 'http://intel.com/wbem/wscim/1/ips-schema/1/IPS_OptInService'
124+
},
125+
Body: {
126+
SendOptInCode_OUTPUT: {
127+
ReturnValue: '1',
128+
ReturnValueStr: 'INTERNAL_ERROR'
129+
}
130+
}
131+
}
67132
sendUserConsetCodeSpy.mockResolvedValueOnce(result)
68133
await send(req, resSpy)
69134
expect(resSpy.status).toHaveBeenCalledWith(400)
70-
expect(resSpy.json).toHaveBeenCalledWith(response)
135+
expect(resSpy.json).toHaveBeenCalledWith(expect.objectContaining({
136+
error: 'Bad Request',
137+
message: expect.stringContaining('INTERNAL_ERROR'),
138+
details: expect.any(Object),
139+
amtResponse: expect.objectContaining({
140+
Header: result.Header,
141+
Body: expect.objectContaining({
142+
ReturnValue: '1',
143+
ReturnValueStr: 'INTERNAL_ERROR'
144+
})
145+
})
146+
}))
71147
})
72148
it('should get an error with status code 400, when failed to request user consent code', async () => {
73149
sendUserConsetCodeSpy.mockResolvedValueOnce(null)

src/routes/amt/userConsent/send.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,37 @@ import { logger, messages } from '../../../logging/index.js'
88
import { ErrorResponse } from '../../../utils/amtHelper.js'
99
import { MqttProvider } from '../../../utils/MqttProvider.js'
1010
import { AMTStatusCodes } from '../../../utils/constants.js'
11+
import { mapAMTReturnValueToHttpStatus, getDetailedErrorMessage } from './statusMapper.js'
1112

1213
export async function send(req: Request, res: Response): Promise<void> {
1314
const userConsentCode: number = req.body.consentCode
1415
const guid: string = req.params.guid
1516
try {
16-
// Cancel a previous opt-in code request.
17+
// Send in the consent code obtained from Client as verification
1718
const response = await req.deviceAction.sendUserConsentCode(userConsentCode)
1819
if (response != null) {
1920
const result = {
2021
Header: response.Header,
2122
Body: response.Body.SendOptInCode_OUTPUT
2223
}
2324
result.Body.ReturnValueStr = AMTStatusCodes[result.Body.ReturnValue]
25+
2426
if (result.Body?.ReturnValue.toString() === '0') {
2527
MqttProvider.publishEvent('success', ['Send_User_Consent_Code'], messages.USER_CONSENT_SENT_SUCCESS, guid)
26-
result.Body.ReturnValueStr = AMTStatusCodes[result.Body.ReturnValue]
2728
res.status(200).json(result)
2829
} else {
29-
logger.error(`${messages.USER_CONSENT_SENT_FAILED} for guid : ${guid}.`)
30+
// Map AMT return value to appropriate HTTP status code
31+
const httpStatus = mapAMTReturnValueToHttpStatus(result.Body.ReturnValueStr)
32+
const errorDetail = getDetailedErrorMessage(result.Body.ReturnValue, result.Body.ReturnValueStr, 'send')
33+
34+
logger.error(`${messages.USER_CONSENT_SENT_FAILED} for guid : ${guid}. ReturnValue: ${result.Body.ReturnValue} (${result.Body.ReturnValueStr})`)
3035
MqttProvider.publishEvent('fail', ['Send_User_Consent_Code'], messages.USER_CONSENT_SENT_FAILED, guid)
31-
res.status(400).json(result)
36+
37+
// Return detailed error response with original AMT data
38+
res.status(httpStatus).json({
39+
...errorDetail,
40+
amtResponse: result
41+
})
3242
}
3343
} else {
3444
logger.error(`${messages.USER_CONSENT_SENT_FAILED} for guid : ${guid}.`)

0 commit comments

Comments
 (0)