Skip to content

Commit d9bc089

Browse files
committed
add tests for informer components
1 parent d0bac17 commit d9bc089

12 files changed

+696
-96
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package io.kubernetes.client.informer.cache;
2+
3+
import static org.junit.Assert.*;
4+
5+
import io.kubernetes.client.models.V1ObjectMeta;
6+
import io.kubernetes.client.models.V1Pod;
7+
import java.util.Arrays;
8+
import java.util.Collection;
9+
import java.util.List;
10+
import org.junit.Rule;
11+
import org.junit.Test;
12+
import org.junit.contrib.java.lang.system.EnvironmentVariables;
13+
import org.junit.runner.RunWith;
14+
import org.junit.runners.Parameterized;
15+
16+
@RunWith(Parameterized.class)
17+
public class CacheTest {
18+
19+
@Rule public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
20+
21+
private static String mockIndexName = "mock";
22+
23+
private static List<String> mockIndexFunc(Object obj) {
24+
if (obj == null) {
25+
return Arrays.asList("null");
26+
}
27+
return Arrays.asList(obj.getClass().getName());
28+
}
29+
30+
private static String mockKeyFunc(Object obj) {
31+
if (obj == null) {
32+
return "null";
33+
}
34+
return String.valueOf(System.identityHashCode(obj));
35+
}
36+
37+
private static Cache cache =
38+
new Cache<>(mockIndexName, CacheTest::mockIndexFunc, CacheTest::mockKeyFunc);
39+
40+
public CacheTest(Object obj, String index) {
41+
this.obj = obj;
42+
this.index = index;
43+
}
44+
45+
private Object obj;
46+
private String index;
47+
48+
@Parameterized.Parameters
49+
public static Collection data() {
50+
51+
V1Pod normalPod = new V1Pod();
52+
V1ObjectMeta normalPodMeta = new V1ObjectMeta();
53+
normalPodMeta.setName("foo");
54+
normalPodMeta.setNamespace("default");
55+
normalPod.setMetadata(normalPodMeta);
56+
57+
V1Pod missingNamespacePod = new V1Pod();
58+
V1ObjectMeta missingNamespacePodMeta = new V1ObjectMeta();
59+
missingNamespacePodMeta.setName("foo");
60+
missingNamespacePodMeta.setNamespace(null);
61+
missingNamespacePod.setMetadata(missingNamespacePodMeta);
62+
63+
V1Pod missingNamePod = new V1Pod();
64+
V1ObjectMeta missingNamePodMeta = new V1ObjectMeta();
65+
missingNamePodMeta.setName(null);
66+
missingNamePodMeta.setNamespace("default");
67+
missingNamePod.setMetadata(missingNamePodMeta);
68+
69+
return Arrays.asList(
70+
new Object[][] {
71+
{normalPod, "io.kubernetes.client.models.V1Pod"},
72+
{missingNamespacePod, "io.kubernetes.client.models.V1Pod"},
73+
{missingNamePod, "io.kubernetes.client.models.V1Pod"},
74+
{null, "null"},
75+
});
76+
}
77+
78+
@Test
79+
public void testCacheIndex() {
80+
cache.replace(Arrays.asList(this.obj), "0");
81+
82+
String index = mockIndexFunc(this.obj).get(0);
83+
String key = mockKeyFunc(this.obj);
84+
assertEquals(this.index, index);
85+
86+
List indexedObjectList = cache.byIndex(mockIndexName, index);
87+
assertEquals(this.obj, indexedObjectList.get(0));
88+
89+
List indexedObjectlist2 = cache.index(mockIndexName, this.obj);
90+
assertEquals(this.obj, indexedObjectlist2.get(0));
91+
92+
List<String> allExistingKeys = cache.listKeys();
93+
assertEquals(1, allExistingKeys.size());
94+
assertEquals(key, allExistingKeys.get(0));
95+
}
96+
97+
@Test
98+
public void testCacheStore() {
99+
if (this.obj == null) {
100+
// skip null object storing test b/c it should be checked before invoking cache
101+
return;
102+
}
103+
104+
cache.replace(Arrays.asList(this.obj), "0");
105+
106+
cache.delete(this.obj);
107+
108+
V1Pod pod = ((V1Pod) this.obj);
109+
List indexedObjectList = cache.byIndex(mockIndexName, this.index);
110+
assertEquals(0, indexedObjectList.size());
111+
assertEquals(null, pod.getMetadata().getClusterName());
112+
113+
cache.add(this.obj);
114+
115+
// replace cached object w/ null value
116+
String newClusterName = "test_cluster";
117+
pod.getMetadata().setClusterName(newClusterName);
118+
cache.update(this.obj);
119+
120+
assertEquals(1, cache.list().size());
121+
assertEquals(newClusterName, pod.getMetadata().getClusterName());
122+
}
123+
124+
@Test
125+
public void testDefaultNamespaceIndex() {
126+
if (this.obj == null) {
127+
// skip null object storing test b/c it should be checked before invoking cache
128+
return;
129+
}
130+
131+
V1Pod pod = ((V1Pod) this.obj);
132+
133+
List<String> indices = Cache.metaNamespaceIndexFunc(this.obj);
134+
assertEquals(pod.getMetadata().getNamespace(), indices.get(0));
135+
}
136+
137+
@Test
138+
public void testDefaultNamespaceNameKey() {
139+
if (this.obj == null) {
140+
// skip null object storing test b/c it should be checked before invoking cache
141+
return;
142+
}
143+
144+
Cache.metaNamespaceKeyFunc(this.obj);
145+
}
146+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package io.kubernetes.client.informer.cache;
2+
3+
import static org.junit.Assert.*;
4+
5+
import io.kubernetes.client.ApiException;
6+
import io.kubernetes.client.informer.EventType;
7+
import io.kubernetes.client.informer.ListerWatcher;
8+
import io.kubernetes.client.models.V1ListMeta;
9+
import io.kubernetes.client.models.V1ObjectMeta;
10+
import io.kubernetes.client.models.V1Pod;
11+
import io.kubernetes.client.models.V1PodList;
12+
import io.kubernetes.client.util.CallGeneratorParams;
13+
import io.kubernetes.client.util.Watch;
14+
import io.kubernetes.client.util.Watchable;
15+
import java.util.Arrays;
16+
import java.util.concurrent.atomic.AtomicBoolean;
17+
import java.util.concurrent.atomic.AtomicInteger;
18+
import org.junit.Rule;
19+
import org.junit.Test;
20+
import org.junit.contrib.java.lang.system.EnvironmentVariables;
21+
22+
public class ControllerTest {
23+
24+
@Rule public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
25+
26+
@Test
27+
public void testControllerProcessDeltas() throws InterruptedException {
28+
29+
AtomicInteger receivingDeltasCount = new AtomicInteger(0);
30+
V1Pod foo1 = new V1Pod().metadata(new V1ObjectMeta().name("foo1").namespace("default"));
31+
V1Pod foo2 = new V1Pod().metadata(new V1ObjectMeta().name("foo2").namespace("default"));
32+
V1Pod foo3 = new V1Pod().metadata(new V1ObjectMeta().name("foo3").namespace("default"));
33+
34+
V1PodList podList =
35+
new V1PodList().metadata(new V1ListMeta()).items(Arrays.asList(foo1, foo2, foo3));
36+
DeltaFIFO<V1Pod> deltaFIFO =
37+
new DeltaFIFO<>(Cache::deletionHandlingMetaNamespaceKeyFunc, new Cache());
38+
39+
AtomicBoolean runOnce = new AtomicBoolean(false);
40+
ListerWatcher<V1Pod, V1PodList> listerWatcher =
41+
new ListerWatcher<V1Pod, V1PodList>() {
42+
@Override
43+
public V1PodList list(CallGeneratorParams params) throws ApiException {
44+
return podList;
45+
}
46+
47+
@Override
48+
public Watchable<V1Pod> watch(CallGeneratorParams params) throws ApiException {
49+
if (!runOnce.get()) {
50+
runOnce.set(true);
51+
return new MockWatch<V1Pod>(
52+
new Watch.Response<V1Pod>(EventType.MODIFIED.name(), foo3));
53+
} else {
54+
return new MockWatch<V1Pod>();
55+
}
56+
}
57+
};
58+
59+
Controller<V1Pod, V1PodList> controller =
60+
new Controller<>(
61+
V1Pod.class,
62+
deltaFIFO,
63+
listerWatcher,
64+
(deltas) -> {
65+
receivingDeltasCount.incrementAndGet();
66+
});
67+
Thread controllerThread = new Thread(controller::run);
68+
controllerThread.setDaemon(true);
69+
controllerThread.start();
70+
71+
// sleep 1s for processing all the deltas
72+
Thread.sleep(1000);
73+
74+
try {
75+
assertEquals(4, receivingDeltasCount.get());
76+
77+
} catch (Throwable t) {
78+
throw new RuntimeException(t);
79+
} finally {
80+
controller.stop();
81+
}
82+
}
83+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package io.kubernetes.client.informer.cache;
2+
3+
import static org.junit.Assert.*;
4+
5+
import io.kubernetes.client.models.V1ObjectMeta;
6+
import io.kubernetes.client.models.V1Pod;
7+
import java.util.ArrayList;
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import org.junit.Rule;
11+
import org.junit.Test;
12+
import org.junit.contrib.java.lang.system.EnvironmentVariables;
13+
14+
public class DeltaFIFOTest {
15+
16+
@Rule public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
17+
18+
@Test
19+
public void testDeltaFIFOBasic() throws InterruptedException {
20+
List<Deltas.Delta<Object>> receivingDeltas = new ArrayList<>();
21+
V1Pod foo1 = new V1Pod().metadata(new V1ObjectMeta().name("foo1").namespace("default"));
22+
Cache cache = new Cache();
23+
DeltaFIFO<V1Pod> deltaFIFO =
24+
new DeltaFIFO<>(Cache::deletionHandlingMetaNamespaceKeyFunc, cache);
25+
26+
Deltas.Delta<Object> receivingDelta;
27+
// basic add operation
28+
deltaFIFO.add(foo1);
29+
cache.add(foo1);
30+
deltaFIFO.pop(
31+
(deltas) -> {
32+
List<Deltas.Delta<Object>> deltaList = deltas.getDeltas();
33+
Deltas.Delta<Object> delta = deltaList.get(0);
34+
receivingDeltas.add(delta);
35+
});
36+
receivingDelta = receivingDeltas.get(0);
37+
receivingDeltas.remove(0);
38+
assertEquals(foo1, receivingDelta.getObj());
39+
assertEquals(Deltas.DeltaType.Added, receivingDelta.getType());
40+
41+
// basic update operation
42+
deltaFIFO.update(foo1);
43+
cache.update(foo1);
44+
deltaFIFO.pop(
45+
(deltas) -> {
46+
List<Deltas.Delta<Object>> deltaList = deltas.getDeltas();
47+
Deltas.Delta<Object> delta = deltaList.get(0);
48+
receivingDeltas.add(delta);
49+
});
50+
receivingDelta = receivingDeltas.get(0);
51+
receivingDeltas.remove(0);
52+
assertEquals(foo1, receivingDelta.getObj());
53+
assertEquals(Deltas.DeltaType.Updated, receivingDelta.getType());
54+
55+
// basic delete operation
56+
deltaFIFO.delete(foo1);
57+
cache.delete(foo1);
58+
deltaFIFO.pop(
59+
(deltas) -> {
60+
List<Deltas.Delta<Object>> deltaList = deltas.getDeltas();
61+
Deltas.Delta<Object> delta = deltaList.get(0);
62+
receivingDeltas.add(delta);
63+
});
64+
receivingDelta = receivingDeltas.get(0);
65+
receivingDeltas.remove(0);
66+
assertEquals(foo1, receivingDelta.getObj());
67+
assertEquals(Deltas.DeltaType.Deleted, receivingDelta.getType());
68+
69+
// basic sync operation
70+
deltaFIFO.replace(Arrays.asList(foo1), "0");
71+
cache.replace(Arrays.asList(foo1), "0");
72+
deltaFIFO.pop(
73+
(deltas) -> {
74+
List<Deltas.Delta<Object>> deltaList = deltas.getDeltas();
75+
Deltas.Delta<Object> delta = deltaList.get(0);
76+
receivingDeltas.add(delta);
77+
});
78+
receivingDelta = receivingDeltas.get(0);
79+
receivingDeltas.remove(0);
80+
assertEquals(foo1, receivingDelta.getObj());
81+
assertEquals(Deltas.DeltaType.Sync, receivingDelta.getType());
82+
}
83+
84+
@Test
85+
public void testDeltaFIFODedup() {
86+
V1Pod foo1 = new V1Pod().metadata(new V1ObjectMeta().name("foo1").namespace("default"));
87+
Cache cache = new Cache();
88+
DeltaFIFO<V1Pod> deltaFIFO =
89+
new DeltaFIFO<>(Cache::deletionHandlingMetaNamespaceKeyFunc, cache);
90+
Deltas<V1Pod> deltas;
91+
92+
// add-delete dedup
93+
deltaFIFO.add(foo1);
94+
deltaFIFO.delete(foo1);
95+
deltas = deltaFIFO.getItems().get(Cache.deletionHandlingMetaNamespaceKeyFunc(foo1));
96+
assertEquals(Deltas.DeltaType.Deleted, deltas.newest().getType());
97+
assertEquals(foo1, deltas.newest().getObj());
98+
assertEquals(Deltas.DeltaType.Added, deltas.oldest().getType());
99+
assertEquals(foo1, deltas.oldest().getObj());
100+
assertEquals(2, deltas.getDeltas().size());
101+
deltaFIFO.getItems().remove(Cache.deletionHandlingMetaNamespaceKeyFunc(foo1));
102+
103+
// add-delete-delete dedup
104+
deltaFIFO.add(foo1);
105+
deltaFIFO.delete(foo1);
106+
deltaFIFO.delete(foo1);
107+
deltas = deltaFIFO.getItems().get(Cache.deletionHandlingMetaNamespaceKeyFunc(foo1));
108+
assertEquals(Deltas.DeltaType.Deleted, deltas.newest().getType());
109+
assertEquals(foo1, deltas.newest().getObj());
110+
assertEquals(Deltas.DeltaType.Added, deltas.oldest().getType());
111+
assertEquals(foo1, deltas.oldest().getObj());
112+
assertEquals(2, deltas.getDeltas().size());
113+
deltaFIFO.getItems().remove(Cache.deletionHandlingMetaNamespaceKeyFunc(foo1));
114+
}
115+
116+
@Test
117+
public void testDeltaFIFOResync() {
118+
V1Pod foo1 = new V1Pod().metadata(new V1ObjectMeta().name("foo1").namespace("default"));
119+
Cache cache = new Cache();
120+
DeltaFIFO<V1Pod> deltaFIFO =
121+
new DeltaFIFO<>(Cache::deletionHandlingMetaNamespaceKeyFunc, cache);
122+
123+
// sync after add
124+
cache.add(foo1);
125+
deltaFIFO.resync();
126+
127+
Deltas<V1Pod> deltas =
128+
deltaFIFO.getItems().get(Cache.deletionHandlingMetaNamespaceKeyFunc(foo1));
129+
130+
assertEquals(1, deltas.getDeltas().size());
131+
assertEquals(foo1, deltas.newest().getObj());
132+
assertEquals(Deltas.DeltaType.Sync, deltas.newest().getType());
133+
}
134+
}

0 commit comments

Comments
 (0)