Skip to content

Commit

Permalink
bug/64795 Tech support - send service bus messages (#2807)
Browse files Browse the repository at this point in the history
* implement service bus messaging for tech support

* lint fixes

* add error handling
  • Loading branch information
GuyHarwood authored Jun 7, 2024
1 parent 9ea2ef8 commit 78e3392
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 10 deletions.
26 changes: 26 additions & 0 deletions admin/controllers/tech-support.js
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,32 @@ const controller = {
} catch (error) {
return next(error)
}
},

getSbQueueSubmit: async function getSbQueueSubmit (req, res, next) {
try {
req.breadcrumbs('Submit Service Bus Queue Message')
res.locals.pageTitle = 'Submit Service Bus Queue Message'
res.render('tech-support/sb-queue-submit', {
breadcrumbs: req.breadcrumbs(),
error: ''
})
} catch (error) {
return next(error)
}
},

postSbQueueSubmit: async function postSbQueueSubmit (req, res, next) {
res.locals.pageTitle = 'Submit Service Bus Queue Message'
try {
await queueMgmtService.sendServiceBusQueueMessage(req.body.queueName, req.body.message, req.body.contentType)
return res.redirect('/tech-support/queue-overview')
} catch (error) {
res.render('tech-support/sb-queue-submit', {
breadcrumbs: req.breadcrumbs(),
error: error.message
})
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"scripts": {
"build": "gulp build",
"build:watch": "yarn tsc --watch",
"dev": "yarn start:dev",
"dev-build": "gulp dev-build",
"shell-build": "./build.sh",
"clean": "rm -rf dist; rm -f .env",
Expand All @@ -30,7 +31,7 @@
"watch:integration": "yarn jest --watch --coverage=no --config ./tests-integration/jest.integration.config.js"
},
"mtc": {
"assets-version": "0e643b584571fcff14c5678866f830eb"
"assets-version": "8066100cea64f449580402f1ebd4ae94"
},
"engines": {
"node": ">= 18"
Expand Down
18 changes: 16 additions & 2 deletions admin/routes/tech-support.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,29 @@ router.get(
techSupportController.showQueueOverview
)

router.get(
'/sb-queue-submit',
isAuthenticated([roles.techSupport]),
techSupportController.getSbQueueSubmit
)

router.post(
'/sb-queue-submit',
isAuthenticated([roles.techSupport]),
techSupportController.postSbQueueSubmit
)

router.get(
'/clear-service-bus-queue/:queueName',
isAuthenticated([roles.techSupport]),
techSupportController.getClearServiceBusQueue)
techSupportController.getClearServiceBusQueue
)

router.post(
'/clear-service-bus-queue/:queueName',
isAuthenticated([roles.techSupport]),
techSupportController.postClearServiceBusQueue)
techSupportController.postClearServiceBusQueue
)

router.get(
'/results-resync-check',
Expand Down
21 changes: 18 additions & 3 deletions admin/services/data-access/service-bus-queue-admin.data.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const serviceBusQueueAdminService = {
getQueueNames: async function getQueueNames () {
if (queueNames) return queueNames
queueNames = []
const queues = await getQueueClient().listQueues()
const queues = await getServiceBusAdminClient().listQueues()
let q = await queues.next()
while (!q.done) {
queueNames.push(q.value.name)
Expand Down Expand Up @@ -44,18 +44,33 @@ const serviceBusQueueAdminService = {
getQueueActiveMessageCount: async function getQueueActiveMessageCount (queueName) {
const counts = await getQueueMessageCount(queueName)
return counts.activeMessageCount
},

sendMessageToQueue: async function sendMessageToQueue (queueName, message, contentType) {
let sbClient, sender
try {
sbClient = new sb.ServiceBusClient(config.ServiceBus.connectionString)
sender = sbClient.createSender(queueName)
await sender.sendMessages({
body: message,
contentType
})
} finally {
await sender.close()
await sbClient.close()
}
}
}

function getQueueClient () {
function getServiceBusAdminClient () {
if (!adminClient) {
adminClient = new sb.ServiceBusAdministrationClient(config.ServiceBus.connectionString)
}
return adminClient
}

async function getQueueMessageCount (queueName) {
const props = await getQueueClient().getQueueRuntimeProperties(queueName)
const props = await getServiceBusAdminClient().getQueueRuntimeProperties(queueName)
return {
name: queueName,
activeMessageCount: props.activeMessageCount,
Expand Down
7 changes: 7 additions & 0 deletions admin/services/queue-management.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ const service = {
const activeMessageCount = await serviceBusQueueAdminService.getQueueActiveMessageCount(queueName)
if (activeMessageCount === 0) return
return serviceBusQueueAdminService.clearQueue(queueName, activeMessageCount)
},

sendServiceBusQueueMessage: async function sendServiceBusQueueMessage (queueName, message, contentType) {
if (contentType === 'application/json') {
message = JSON.parse(message)
}
await serviceBusQueueAdminService.sendMessageToQueue(queueName, message, contentType)
}
}

Expand Down
54 changes: 54 additions & 0 deletions admin/spec/back-end/controllers/tech-support.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,58 @@ describe('tech-support controller', () => {
expect(CheckSubmitService.submitV3CheckPayload).toHaveBeenCalledWith(req.body.isJson, req.body.payload)
})
})

describe('/sb-queue-submit', () => {
test('GET: should render page', async () => {
const reqParams = getReqParams('/tech-support/sb-queue-submit', 'GET')
const req = getRequest(reqParams)
const res = getResponse()
jest.spyOn(res, 'render').mockImplementation()
await sut.getSbQueueSubmit(req, res, next)
expect(res.statusCode).toBe(200)
expect(res.render).toHaveBeenCalled()
expect(next).not.toHaveBeenCalled()
})

test('POST: should submit message to service and redirect to overview', async () => {
const reqParams = getReqParams('/tech-support/sb-queue-submit', 'POST')
const req = getRequest(reqParams)
req.body = {
message: 'sfsdfkdsf',
queueName: 'myqueue',
contentType: 'application/json'
}
const res = getResponse()
jest.spyOn(queueMgmtService, 'sendServiceBusQueueMessage').mockImplementation()
jest.spyOn(res, 'redirect').mockImplementation()
await sut.postSbQueueSubmit(req, res, next)
expect(res.statusCode).toBe(200)
expect(res.redirect).toHaveBeenCalledWith('/tech-support/queue-overview')
expect(next).not.toHaveBeenCalled()
expect(queueMgmtService.sendServiceBusQueueMessage)
.toHaveBeenCalledWith(req.body.queueName, req.body.message, req.body.contentType)
})

test('POST: if error thrown it should render error message', async () => {
const reqParams = getReqParams('/tech-support/sb-queue-submit', 'POST')
const req = getRequest(reqParams)
req.body = {
message: 'sfsdfkdsf',
queueName: 'myqueue',
contentType: 'application/json'
}
const res = getResponse()
const errorMessage = 'mock error'
jest.spyOn(queueMgmtService, 'sendServiceBusQueueMessage').mockRejectedValue(new Error(errorMessage))
jest.spyOn(res, 'render').mockImplementation((url, objs) => {
console.log(`url: ${url}, objs: ${JSON.stringify(objs)}`)
})
jest.spyOn(res, 'redirect').mockImplementation()
await sut.postSbQueueSubmit(req, res, next)
expect(res.redirect).not.toHaveBeenCalled()
expect(res.statusCode).toBe(200)
expect(res.render).toHaveBeenCalled()
expect(next).not.toHaveBeenCalled()
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ describe('tech support queue management service', () => {
expect(serviceBusQueueAdminService.getQueueActiveMessageCount).toHaveBeenCalledTimes(1)
expect(serviceBusQueueAdminService.clearQueue).not.toHaveBeenCalled()
})

test('should send a message to a service bus queue', async () => {})
test('if message is JSON, should convert to object before sending', async () => {
const queueName = 'q1'
const message = '{"pupilUUID":"1234","version":1}'
const contentType = 'application/json'
jest.spyOn(serviceBusQueueAdminService, 'sendMessageToQueue').mockResolvedValueOnce()
await sut.sendServiceBusQueueMessage(queueName, message, contentType)
expect(serviceBusQueueAdminService.sendMessageToQueue).toHaveBeenCalledWith(queueName, JSON.parse(message), contentType)
})
})

describe('storage account functionality', () => {
Expand Down
7 changes: 5 additions & 2 deletions admin/views/tech-support/home.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@
<h2 class="govuk-heading-s arrow-up"><a class="govuk-link" href="/tech-support/redis-overview">Redis</a></h2>
</li>
<li class="govuk-!-margin-bottom-4">
<h2 class="govuk-heading-s arrow-up"><a class="govuk-link" href="/tech-support/queue-overview">Queues</a></h2>
<h2 class="govuk-heading-s arrow-up"><a class="govuk-link" href="/tech-support/queue-overview">Queues Overview</a></h2>
</li>
<li class="govuk-!-margin-bottom-4">
<h2 class="govuk-heading-s arrow-up"><a class="govuk-link" href="/tech-support/check-submit">Submit Check to Queue</a></h2>
<h2 class="govuk-heading-s arrow-up"><a class="govuk-link" href="/tech-support/sb-queue-submit">Submit Service Bus Queue Message</a></h2>
</li>
<li class="govuk-!-margin-bottom-4">
<h2 class="govuk-heading-s arrow-up"><a class="govuk-link" href="/tech-support/check-submit">Submit Check</a></h2>
</li>
<li class="govuk-!-margin-bottom-4">
<h2 class="govuk-heading-s arrow-up">
Expand Down
18 changes: 18 additions & 0 deletions admin/views/tech-support/ps-report-run.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,23 @@
</div>
<% } %>
</div>

<div class="govuk-grid-column-one-third" aria-label="sidebar">
<aside class="app-related-items" role="complementary">
<h2 class="govuk-heading-m" id="subsection-title">
Related
</h2>
<nav role="navigation" aria-labelledby="subsection-title">
<ul class="govuk-list govuk-!-font-size-16">
<li>
<a class="govuk-link" href="/tech-support/queue-overview">Queue Overview</a>
</li>
<li>
<a class="govuk-link" href="/tech-support/sb-queue-submit">Submit Queue Message</a>
</li>
</ul>
</nav>
</aside>
</div>
</div>
</main>
4 changes: 2 additions & 2 deletions admin/views/tech-support/queue-overview.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@
<nav role="navigation" aria-labelledby="subsection-title">
<ul class="govuk-list govuk-!-font-size-16">
<li>
<a class="govuk-link" href="/tech-support/queues/summary">Summary</a>
<a class="govuk-link" href="/tech-support/sb-queue-submit">Submit Queue Message</a>
</li>
<li>
<a class="govuk-link" href="/tech-support/queues/replay">Replay Messages</a>
<a class="govuk-link" href="/tech-support/ps-report-run">Run PS Report</a>
</li>
</ul>
</nav>
Expand Down
59 changes: 59 additions & 0 deletions admin/views/tech-support/sb-queue-submit.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<%- partial('partials/_gds_breadcrumbs_and_sign_out', { breadcrumbs }) %>
<main class="govuk-main-wrapper govuk-body" id="main-content" role="main">
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form action="/tech-support/sb-queue-submit" method="post" autocomplete="off">
<input type="hidden" name="_csrf" value="<%= csrftoken %>" />
<h1 class="govuk-label-wrapper"><label class="govuk-label govuk-label--l" for="payload">
Submit a message to a service bus queue
</label>
</h1>
<div class="govuk-form-group">
<label class="govuk-label" for="queueName">Target Queue:</label>
<input class="govuk-input govuk-!-width-one-half" type="text"
id="queueName" name="queueName"
value="ps-report-staging-start"
spellcheck="false"
autocorrect="off">
</div>
<div class="govuk-form-group">
<label class="govuk-label" for="contentType">Content Type:</label>
<input class="govuk-input govuk-!-width-one-half" type="text"
id="contentType" name="contentType"
value="application/json"
spellcheck="false"
autocorrect="off">
</div>
<div class="govuk-form-group">
<label class="govuk-label" for="message">Message:</label>
<textarea id="message" name="message" class="govuk-textarea govuk-!-width-three-quarters"
rows="10"
spellcheck="false" autocorrect="off" autocapitalize="off">{}</textarea>
</div>
<button type="submit" id="submit-btn" class="govuk-button">Submit</button>
<a class="govuk-button govuk-button--secondary" href="/tech-support/home">Cancel</a>
</form>
<% if (error && error.length > 0) { %>
<p class="govuk-error-summary"><%= error %></p>
<% } %>
</div>

<div class="govuk-grid-column-one-third" aria-label="sidebar">
<aside class="app-related-items" role="complementary">
<h2 class="govuk-heading-m" id="subsection-title">
Related
</h2>
<nav role="navigation" aria-labelledby="subsection-title">
<ul class="govuk-list govuk-!-font-size-16">
<li>
<a class="govuk-link" href="/tech-support/queue-overview">Queue Overview</a>
</li>
<li>
<a class="govuk-link" href="/tech-support/ps-report-run">Run PS Report</a>
</li>
</ul>
</nav>
</aside>
</div>
</div>
</main>

0 comments on commit 78e3392

Please sign in to comment.