Skip to content

Commit 4c5ce02

Browse files
committed
Fix a bug where the lists were never cleared
1 parent a4a6c03 commit 4c5ce02

File tree

2 files changed

+127
-3
lines changed

2 files changed

+127
-3
lines changed

src/cache.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,15 @@ export class ListWatch<T extends KubernetesObject> implements ObjectCache<T>, In
9696
const promise = this.listFn();
9797
const result = await promise;
9898
const list = result.body;
99-
deleteItems(this.objects, list.items, this.callbackCache[DELETE].slice());
99+
this.objects = deleteItems(this.objects, list.items, this.callbackCache[DELETE].slice());
100+
Object.keys(this.indexCache).forEach((key) => {
101+
const updateObjects = deleteItems(this.indexCache[key], list.items);
102+
if (updateObjects.length !== 0) {
103+
this.indexCache[key] = updateObjects;
104+
} else {
105+
delete this.indexCache[key];
106+
}
107+
});
100108
this.addOrUpdateItems(list.items);
101109
await this.watch.watch(
102110
this.path,

src/cache_test.ts

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ describe('ListWatchCache', () => {
4040
{
4141
metadata: {
4242
name: 'name1',
43+
namespace: 'default',
4344
} as V1ObjectMeta,
4445
} as V1Namespace,
4546
{
4647
metadata: {
4748
name: 'name2',
49+
namespace: 'default',
4850
} as V1ObjectMeta,
4951
} as V1Namespace,
5052
];
@@ -55,13 +57,32 @@ describe('ListWatchCache', () => {
5557
items: list,
5658
} as V1NamespaceList;
5759

60+
const emptyObj = {
61+
metadata: {
62+
resourceVersion: '123456',
63+
} as V1ListMeta,
64+
items: [
65+
{
66+
metadata: {
67+
name: 'name3',
68+
namespace: 'default',
69+
} as V1ObjectMeta,
70+
} as V1Namespace,
71+
],
72+
} as V1NamespaceList;
73+
74+
var calls = 0;
5875
const listFn: ListPromise<V1Namespace> = function(): Promise<{
5976
response: http.IncomingMessage;
6077
body: V1NamespaceList;
6178
}> {
6279
return new Promise<{ response: http.IncomingMessage; body: V1NamespaceList }>(
6380
(resolve, reject) => {
64-
resolve({ response: {} as http.IncomingMessage, body: listObj });
81+
if (calls++ === 0) {
82+
resolve({ response: {} as http.IncomingMessage, body: listObj });
83+
} else {
84+
resolve({ response: {} as http.IncomingMessage, body: emptyObj });
85+
}
6586
},
6687
);
6788
};
@@ -80,25 +101,34 @@ describe('ListWatchCache', () => {
80101
});
81102
const cache = new ListWatch('/some/path', mock.instance(fakeWatch), listFn);
82103
await promise;
83-
const [pathOut, , watchHandler] = mock.capture(fakeWatch.watch).last();
104+
const [pathOut, , watchHandler, doneHandler] = mock.capture(fakeWatch.watch).last();
84105
expect(pathOut).to.equal('/some/path');
85106
expect(cache.list()).to.deep.equal(list);
86107

87108
expect(cache.get('name1')).to.equal(list[0]);
88109
expect(cache.get('name2')).to.equal(list[1]);
89110

111+
expect(cache.list('default')).to.deep.equal(list);
112+
expect(cache.list('non-existent')).to.be.undefined;
113+
90114
watchHandler('ADDED', {
91115
metadata: {
92116
name: 'name3',
117+
namespace: 'other',
93118
} as V1ObjectMeta,
94119
} as V1Namespace);
95120

96121
expect(cache.list().length).to.equal(3);
97122
expect(cache.get('name3')).to.not.equal(null);
98123

124+
expect(cache.list('default').length).to.equal(2);
125+
expect(cache.list('other').length).to.equal(1);
126+
expect(cache.list('non-existent')).to.be.undefined;
127+
99128
watchHandler('MODIFIED', {
100129
metadata: {
101130
name: 'name3',
131+
namespace: 'other',
102132
resourceVersion: 'baz',
103133
} as V1ObjectMeta,
104134
} as V1Namespace);
@@ -113,10 +143,26 @@ describe('ListWatchCache', () => {
113143
watchHandler('DELETED', {
114144
metadata: {
115145
name: 'name2',
146+
namespace: 'default',
116147
} as V1ObjectMeta,
117148
} as V1Namespace);
118149
expect(cache.list().length).to.equal(2);
119150
expect(cache.get('name2')).to.equal(undefined);
151+
152+
expect(cache.list('default').length).to.equal(1);
153+
expect(cache.list('other').length).to.equal(1);
154+
155+
watchHandler('ADDED', {
156+
metadata: {
157+
name: 'name2',
158+
namespace: 'default',
159+
} as V1ObjectMeta,
160+
} as V1Namespace);
161+
162+
await doneHandler();
163+
expect(cache.list().length, 'all namespace list').to.equal(1);
164+
expect(cache.list('default').length, 'default namespace list').to.equal(1);
165+
expect(cache.list('other'), 'other namespace list').to.be.undefined;
120166
});
121167

122168
it('should perform work as an informer', async () => {
@@ -754,6 +800,76 @@ describe('ListWatchCache', () => {
754800
await startPromise;
755801
expect(cache.list().length).to.equal(2);
756802
});
803+
804+
it('should only call update handlers once', async () => {
805+
const fakeWatch = mock.mock(Watch);
806+
const list: V1Namespace[] = [];
807+
const listObj = {
808+
metadata: {
809+
resourceVersion: '12345',
810+
} as V1ListMeta,
811+
items: list,
812+
} as V1NamespaceList;
813+
const listFn: ListPromise<V1Namespace> = function(): Promise<{
814+
response: http.IncomingMessage;
815+
body: V1NamespaceList;
816+
}> {
817+
return new Promise<{ response: http.IncomingMessage; body: V1NamespaceList }>((resolve) => {
818+
resolve({ response: {} as http.IncomingMessage, body: listObj });
819+
});
820+
};
821+
const watchCalled = new Promise((resolve) => {
822+
mock.when(
823+
fakeWatch.watch(
824+
mock.anything(),
825+
mock.anything(),
826+
mock.anything(),
827+
mock.anything(),
828+
mock.anything(),
829+
),
830+
).thenCall(resolve);
831+
});
832+
const informer = new ListWatch('/some/path', mock.instance(fakeWatch), listFn);
833+
834+
const addedList1: V1Namespace[] = [];
835+
const addToList1Fn = function(obj: V1Namespace) {
836+
addedList1.push(obj);
837+
};
838+
const addedList2: V1Namespace[] = [];
839+
const addToList2Fn = function(obj: V1Namespace) {
840+
addedList2.push(obj);
841+
};
842+
843+
informer.start();
844+
845+
await watchCalled;
846+
const [, , watchHandler] = mock.capture(fakeWatch.watch).last();
847+
848+
let adds = 0;
849+
informer.on(ADD, () => adds++);
850+
informer.on(ADD, addToList1Fn);
851+
informer.on(ADD, addToList2Fn);
852+
853+
watchHandler('ADDED', {
854+
metadata: {
855+
name: 'name1',
856+
namespace: 'something',
857+
} as V1ObjectMeta,
858+
} as V1Namespace);
859+
860+
informer.off(ADD, addToList2Fn);
861+
862+
watchHandler('ADDED', {
863+
metadata: {
864+
name: 'name2',
865+
namespace: 'something',
866+
} as V1ObjectMeta,
867+
} as V1Namespace);
868+
869+
expect(adds).to.equal(2);
870+
expect(addedList1.length).to.equal(2);
871+
expect(addedList2.length).to.equal(1);
872+
});
757873
});
758874

759875
describe('delete items', () => {

0 commit comments

Comments
 (0)