From 069b4660d51e2f7f2abe3cf22e4243d72ae1c0eb Mon Sep 17 00:00:00 2001 From: Philippe Martin Date: Mon, 14 Oct 2024 19:46:32 +0200 Subject: [PATCH 1/2] fix: reset resourceVersion when error 410 --- src/cache.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cache.ts b/src/cache.ts index 65b5ccc98e4..ade3d4611a6 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -186,6 +186,11 @@ export class ListWatch implements ObjectCache, In private watchHandler(phase: string, obj: T, watchObj?: any): void { switch (phase) { + case 'ERROR': + if ((obj as { code?: number }).code === 410) { + this.resourceVersion = ''; + } + break; case 'ADDED': case 'MODIFIED': addOrUpdateObject( From 95072a6d6ac5c0173beca60f7644c9473a1c2301 Mon Sep 17 00:00:00 2001 From: Philippe Martin Date: Tue, 15 Oct 2024 20:55:40 +0200 Subject: [PATCH 2/2] unit test for Reset resource version --- src/cache_test.ts | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/cache_test.ts b/src/cache_test.ts index 876494ede73..e5bf2de5aab 100644 --- a/src/cache_test.ts +++ b/src/cache_test.ts @@ -1098,6 +1098,75 @@ describe('ListWatchCache', () => { expect(listCalls).to.be.equal(2); }); + it('should list if the watch cannot be restarted from the latest resourceVersion with an ERROR event', async () => { + const fakeWatch = mock.mock(Watch); + const list: V1Pod[] = []; + const listObj = { + metadata: { + resourceVersion: '12345', + } as V1ListMeta, + items: list, + } as V1NamespaceList; + + let listCalls = 0; + const listFn: ListPromise = function (): Promise { + return new Promise((resolve) => { + listCalls++; + resolve(listObj); + }); + }; + let promise = new Promise((resolve) => { + mock.when( + fakeWatch.watch(mock.anything(), mock.anything(), mock.anything(), mock.anything()), + ).thenCall(() => { + resolve(new AbortController()); + }); + }); + + const informer = new ListWatch('/some/path', mock.instance(fakeWatch), listFn, false); + + informer.start(); + await promise; + + const [, , watchHandler] = mock.capture(fakeWatch.watch).last(); + watchHandler( + 'ADDED', + { + metadata: { + name: 'name3', + } as V1ObjectMeta, + } as V1Namespace, + { metadata: { resourceVersion: '23456' } }, + ); + + await informer.stop(); + + let errorEmitted = false; + informer.on('error', () => (errorEmitted = true)); + + promise = new Promise((resolve) => { + mock.when( + fakeWatch.watch(mock.anything(), mock.anything(), mock.anything(), mock.anything()), + ).thenCall(() => { + resolve(new AbortController()); + }); + }); + + informer.start(); + await promise; + + const [, , watchHandler2, doneHandler] = mock.capture(fakeWatch.watch).last(); + watchHandler2('ERROR', { + code: 410, + }); + doneHandler(undefined); + mock.verify( + fakeWatch.watch(mock.anything(), mock.anything(), mock.anything(), mock.anything()), + ).twice(); + expect(errorEmitted).to.equal(false); + expect(listCalls).to.be.equal(2); + }); + it('should send label selector', async () => { const APP_LABEL_SELECTOR = 'app=foo';