diff options
author | Valerij Fredriksen <valerijf@oath.com> | 2019-01-10 14:21:45 +0100 |
---|---|---|
committer | Valerij Fredriksen <valerijf@oath.com> | 2019-01-10 14:21:45 +0100 |
commit | 0e81d4e9cc14091d6f5dc4f6cadacf7fbec9da9c (patch) | |
tree | 3c6cd3d196ee7bfa3135aba86959f56163433557 /node-admin/src | |
parent | ecae1271b5d13f53f3849561f1f8df6b585e084a (diff) |
Add NodeAgentContextManager tests
Diffstat (limited to 'node-admin/src')
-rw-r--r-- | node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextManagerTest.java | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextManagerTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextManagerTest.java new file mode 100644 index 00000000000..c560d0590a4 --- /dev/null +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextManagerTest.java @@ -0,0 +1,140 @@ +// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.nodeagent; + +import org.junit.Test; + +import java.time.Clock; +import java.time.Duration; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +/** + * @author freva + */ +public class NodeAgentContextManagerTest { + + private final Clock clock = Clock.systemUTC(); + private final NodeAgentContext initialContext = generateContext(); + private final NodeAgentContextManager manager = new NodeAgentContextManager(clock, initialContext); + + @Test(timeout = 1000) + public void returns_immediately_if_next_context_is_ready() throws InterruptedException { + NodeAgentContext context1 = generateContext(); + manager.scheduleTickWith(context1); + + assertSame(initialContext, manager.currentContext()); + assertSame(context1, manager.nextContext()); + assertSame(context1, manager.currentContext()); + } + + @Test(timeout = 1000) + public void blocks_in_nextContext_until_one_is_scheduled() throws InterruptedException { + AsyncExecutor<NodeAgentContext> async = new AsyncExecutor<>(manager::nextContext); + assertFalse(async.response.isPresent()); + Thread.sleep(10); + assertFalse(async.response.isPresent()); + + NodeAgentContext context1 = generateContext(); + manager.scheduleTickWith(context1); + + async.awaitResult(); + assertEquals(Optional.of(context1), async.response); + assertFalse(async.exception.isPresent()); + } + + @Test(timeout = 1000) + public void blocks_in_nextContext_until_interrupt() throws InterruptedException { + AsyncExecutor<NodeAgentContext> async = new AsyncExecutor<>(manager::nextContext); + assertFalse(async.response.isPresent()); + Thread.sleep(10); + assertFalse(async.response.isPresent()); + + manager.interrupt(); + + async.awaitResult(); + assertEquals(Optional.of(InterruptedException.class), async.exception.map(Exception::getClass)); + assertFalse(async.response.isPresent()); + } + + @Test(timeout = 1000) + public void setFrozen_does_not_block_with_no_timeout() throws InterruptedException { + assertFalse(manager.setFrozen(false, Duration.ZERO)); + + // Generate new context and get it from the supplier, this completes the unfreeze + NodeAgentContext context1 = generateContext(); + manager.scheduleTickWith(context1); + assertSame(context1, manager.nextContext()); + + assertTrue(manager.setFrozen(false, Duration.ZERO)); + } + + @Test(timeout = 1000) + public void setFrozen_blocks_at_least_for_duration_of_timeout() { + long wantedDurationMillis = 100; + long start = clock.millis(); + assertFalse(manager.setFrozen(false, Duration.ofMillis(wantedDurationMillis))); + long actualDurationMillis = clock.millis() - start; + + assertTrue(actualDurationMillis >= wantedDurationMillis); + } + + @Test(timeout = 1000) + public void setFrozen_is_successful_if_converged_in_time() throws InterruptedException { + AsyncExecutor<Boolean> async = new AsyncExecutor<>(() -> manager.setFrozen(false, Duration.ofMillis(500))); + + assertFalse(async.response.isPresent()); + + NodeAgentContext context1 = generateContext(); + manager.scheduleTickWith(context1); + assertSame(context1, manager.nextContext()); + + async.awaitResult(); + assertEquals(Optional.of(true), async.response); + assertFalse(async.exception.isPresent()); + } + + private static NodeAgentContext generateContext() { + return new NodeAgentContextImpl.Builder("container-123.domain.tld").build(); + } + + private class AsyncExecutor<T> { + private final Object monitor = new Object(); + private final Thread thread; + private volatile Optional<T> response = Optional.empty(); + private volatile Optional<Exception> exception = Optional.empty(); + private boolean completed = false; + + private AsyncExecutor(ThrowingSupplier<T> supplier) { + this.thread = new Thread(() -> { + try { + response = Optional.of(supplier.get()); + } catch (Exception e) { + exception = Optional.of(e); + } + synchronized (monitor) { + completed = true; + monitor.notifyAll(); + } + }); + this.thread.start(); + } + + private void awaitResult() { + synchronized (monitor) { + while (!completed) { + try { + monitor.wait(); + } catch (InterruptedException ignored) { } + } + } + } + } + + private interface ThrowingSupplier<T> { + T get() throws Exception; + } +}
\ No newline at end of file |