Throw if target states gets a 304 without an ETAG

The API uses 304 as a mechanism for load management on target state
requests. This may cause that the supervisor receives a 304 response
without having received a copy of the target state first, leading to
issues. This change checks for an etag when receiving a 304, throwing an
exception otherwise.

Change-type: patch
This commit is contained in:
Felipe Lalanne 2022-01-25 17:13:29 -03:00
parent fba0317620
commit f471ad736c
2 changed files with 21 additions and 2 deletions

View File

@ -150,7 +150,7 @@ export const update = async (
.getAsync(endpoint, params)
.timeout(apiTimeout);
if (statusCode === 304) {
if (statusCode === 304 && cache?.etag != null) {
// There's no change so no need to update the cache
// only emit the target state if it hasn't been emitted yet
cache.emitted = emitTargetState(cache, force, isFromApi);

View File

@ -37,7 +37,7 @@ const req = {
Promise.resolve([
{
statusCode: 200,
headers: {},
headers: { etag: 'abc' },
} as any,
JSON.stringify(stateEndpointBody),
]),
@ -60,6 +60,25 @@ describe('Target state', () => {
});
describe('update', () => {
it('should throw if a 304 is received but no local cache exists', async () => {
// new request returns 304
const newReq = {
getAsync: () =>
Promise.resolve([
{
statusCode: 304,
headers: {},
} as any,
]),
};
(request.getRequestInstance as SinonStub).resolves(newReq as any);
// Perform target state request
await expect(TargetState.update()).to.be.rejected;
expect(request.getRequestInstance).to.be.calledOnce;
});
it('should emit target state when a new one is available', async () => {
// Setup target state listener
const listener = stub();