/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.coordinator.impl; import org.osgi.service.coordinator.Coordination; import org.osgi.service.coordinator.CoordinationException; import org.osgi.service.coordinator.Participant; import junit.framework.TestCase; public class CoordinatorImplTest extends TestCase { private CoordinationMgr mgr; private CoordinatorImpl coordinator; @Override protected void setUp() throws Exception { super.setUp(); mgr = new CoordinationMgr(); coordinator = new CoordinatorImpl(null, mgr); } public void test_createCoordination() { final String name = "test"; final Coordination c1 = coordinator.create(name, 0); assertNotNull(c1); assertEquals(name, c1.getName()); assertNull(coordinator.peek()); assertNull(c1.getFailure()); assertFalse(c1.isTerminated()); assertTrue(c1.getParticipants().isEmpty()); Exception cause = new Exception(); assertTrue(c1.fail(cause)); assertSame(cause, c1.getFailure()); assertTrue(c1.isTerminated()); assertNull(coordinator.peek()); assertFalse(c1.fail(new Exception())); try { c1.end(); fail("Expected CoordinationException.FAILED on end() after fail()"); } catch (CoordinationException ce) { // expected failed assertEquals(CoordinationException.FAILED, ce.getType()); } final Coordination c2 = coordinator.create(name, 0); assertNotNull(c2); assertEquals(name, c2.getName()); assertNull(coordinator.peek()); assertNull(c2.getFailure()); assertFalse(c2.isTerminated()); assertTrue(c2.getParticipants().isEmpty()); c2.end(); assertNull(c2.getFailure()); assertTrue(c2.isTerminated()); assertNull(coordinator.peek()); assertFalse(c2.fail(new Exception())); try { c2.end(); fail("Expected CoordinationException.ALREADY_ENDED on second end()"); } catch (CoordinationException ce) { // expected already terminated assertEquals(CoordinationException.ALREADY_ENDED, ce.getType()); } } public void test_beginCoordination() { final String name = "test"; final Coordination c1 = coordinator.begin(name, 0); assertNotNull(c1); assertEquals(name, c1.getName()); assertEquals(c1, coordinator.peek()); assertEquals(c1, coordinator.pop()); assertNull(coordinator.peek()); c1.push(); assertEquals(c1, coordinator.peek()); c1.end(); assertNull(coordinator.peek()); final Coordination c2 = coordinator.begin(name, 0); assertNotNull(c2); assertEquals(name, c2.getName()); assertEquals(c2, coordinator.peek()); c2.fail(new Exception()); assertNotNull(coordinator.peek()); try { c2.end(); fail("Exception should be thrown"); } catch (CoordinationException ce) { // ignore } assertNull(coordinator.peek()); } public void test_beginCoordination_stack() { final String name = "test"; final Coordination c1 = coordinator.begin(name, 0); assertNotNull(c1); assertEquals(name, c1.getName()); assertEquals(c1, coordinator.peek()); final Coordination c2 = coordinator.begin(name, 0); assertNotNull(c2); assertEquals(name, c2.getName()); assertEquals(c2, coordinator.peek()); c2.end(); assertEquals(c1, coordinator.peek()); c1.end(); assertNull(coordinator.peek()); } public void test_beginCoordination_stack2() { final String name = "test"; final Coordination c1 = coordinator.begin(name, 0); assertNotNull(c1); assertEquals(name, c1.getName()); assertEquals(c1, coordinator.peek()); final Coordination c2 = coordinator.begin(name, 0); assertNotNull(c2); assertEquals(name, c2.getName()); assertEquals(c2, coordinator.peek()); c1.end(); assertNull(coordinator.peek()); try { c2.end(); fail("c2 is already terminated"); } catch (CoordinationException ce) { assertEquals(CoordinationException.ALREADY_ENDED, ce.getType()); } assertNull(coordinator.peek()); } public void test_addParticipant_with_ended() { final String name = "test"; final Coordination c1 = coordinator.create(name, 0); final MockParticipant p1 = new MockParticipant(); c1.addParticipant(p1); assertTrue(c1.getParticipants().contains(p1)); assertEquals(1, c1.getParticipants().size()); c1.end(); assertTrue(p1.ended); assertFalse(p1.failed); assertEquals(c1, p1.c); // assert order of call final Coordination c2 = coordinator.create(name, 0); final MockParticipant p21 = new MockParticipant(); final MockParticipant p22 = new MockParticipant(); c2.addParticipant(p21); c2.addParticipant(p22); assertTrue(c2.getParticipants().contains(p21)); assertTrue(c2.getParticipants().contains(p22)); assertEquals(2, c2.getParticipants().size()); c2.end(); assertTrue(p21.ended); assertEquals(c2, p21.c); assertTrue(p22.ended); assertEquals(c2, p22.c); assertTrue("p22 must be called before p21", p22.time < p21.time); // assert order of call with two registrations final Coordination c3 = coordinator.create(name, 0); final MockParticipant p31 = new MockParticipant(); final MockParticipant p32 = new MockParticipant(); c3.addParticipant(p31); c3.addParticipant(p32); c3.addParticipant(p31); // should be "ignored" assertTrue(c3.getParticipants().contains(p31)); assertTrue(c3.getParticipants().contains(p32)); assertEquals(2, c3.getParticipants().size()); c3.end(); assertTrue(p31.ended); assertEquals(c3, p31.c); assertTrue(p32.ended); assertEquals(c3, p32.c); assertTrue("p32 must be called before p31", p32.time < p31.time); } public void test_addParticipant_with_failed() { final String name = "test"; final Coordination c1 = coordinator.create(name, 0); final MockParticipant p1 = new MockParticipant(); c1.addParticipant(p1); assertTrue(c1.getParticipants().contains(p1)); assertEquals(1, c1.getParticipants().size()); c1.fail(new Exception()); assertFalse(p1.ended); assertTrue(p1.failed); assertEquals(c1, p1.c); // assert order of call final Coordination c2 = coordinator.create(name, 0); final MockParticipant p21 = new MockParticipant(); final MockParticipant p22 = new MockParticipant(); c2.addParticipant(p21); c2.addParticipant(p22); assertTrue(c2.getParticipants().contains(p21)); assertTrue(c2.getParticipants().contains(p22)); assertEquals(2, c2.getParticipants().size()); c2.fail(new Exception()); assertTrue(p21.failed); assertEquals(c2, p21.c); assertTrue(p22.failed); assertEquals(c2, p22.c); assertTrue("p22 must be called before p21", p22.time < p21.time); // assert order of call with two registrations final Coordination c3 = coordinator.create(name, 0); final MockParticipant p31 = new MockParticipant(); final MockParticipant p32 = new MockParticipant(); c3.addParticipant(p31); c3.addParticipant(p32); c3.addParticipant(p31); // should be "ignored" assertTrue(c3.getParticipants().contains(p31)); assertTrue(c3.getParticipants().contains(p32)); assertEquals(2, c3.getParticipants().size()); c3.fail(new Exception()); assertTrue(p31.failed); assertEquals(c3, p31.c); assertTrue(p32.failed); assertEquals(c3, p32.c); assertTrue("p31 must be called before p32", p32.time < p31.time); } public void test_Coordination_timeout() throws InterruptedException { final String name = "test"; final Coordination c1 = coordinator.create(name, 200); final MockParticipant p1 = new MockParticipant(); c1.addParticipant(p1); assertTrue(c1.getParticipants().contains(p1)); assertEquals(1, c1.getParticipants().size()); // wait for the coordination to time out Thread.sleep(250); // expect coordination to have terminated assertTrue(c1.isTerminated()); assertSame(Coordination.TIMEOUT, c1.getFailure()); // expect Participant.failed() being called assertTrue(p1.failed); assertEquals(c1, p1.c); } public void test_Coordination_addParticipant_timeout() throws InterruptedException { final String name1 = "test1"; final String name2 = "test2"; final MockParticipant p1 = new MockParticipant(); // ensure short timeout for participation mgr.configure(200); final Coordination c1 = coordinator.create(name1, 0); c1.addParticipant(p1); assertTrue(c1.getParticipants().contains(p1)); assertEquals(1, c1.getParticipants().size()); // preset p1PartFailure to be be sure the participation actually starts p1.addParticipantFailure(new Exception("Not Started yet")); Thread c2Thread = new Thread() { @Override public void run() { final Coordination c2 = coordinator.create(name2, 0); try { p1.addParticipantFailure(null); c2.addParticipant(p1); } catch (Throwable t) { p1.addParticipantFailure(t); } finally { c2.end(); } } }; c2Thread.start(); // wait at most 2 seconds for the second thread to terminate // we expect this if the participation properly times out c2Thread.join(2000); assertFalse("Thread for second Coordination did not terminate....", c2Thread.isAlive()); Throwable p1PartFailure = p1.addParticipantFailure; if (p1PartFailure == null) { fail("Expecting CoordinationException/FAILED for second participation"); } else if (p1PartFailure instanceof CoordinationException) { assertEquals(CoordinationException.FAILED, ((CoordinationException) p1PartFailure).getType()); } else { fail("Unexpected Throwable while trying to addParticipant: " + p1PartFailure); } c1.end(); // make sure c2Thread has terminated if (c2Thread.isAlive()) { c2Thread.interrupt(); c2Thread.join(1000); assertFalse("Thread for second Coordination did still not terminate....", c2Thread.isAlive()); } } static final class MockParticipant implements Participant { long time; Coordination c; boolean failed; boolean ended; Throwable addParticipantFailure; public void failed(Coordination c) throws Exception { this.failed = true; this.c = c; this.time = System.nanoTime(); } public void ended(Coordination c) throws Exception { this.ended = true; this.c = c; this.time = System.nanoTime(); } void addParticipantFailure(Throwable t) { this.addParticipantFailure = t; } } }