/** * Prepare the original diamond-dependency problem, where B depends on A and C depends on both A * and B. We need to guarantee that C can read all of its dependencies only when they're in a * 'consistent' state, which is when they've received all events from their dependencies, and * their dependencies are in a consistent state. * * <p>A --> B --. This diagram shows A --> B, B --> C and A --> C. | | The only safe notification * order of events is | V for B to receive events from A before C receives '-------> C those same * events. */ public void testDiamondDependency() { SequenceDependenciesEventPublisher publisher = new SequenceDependenciesEventPublisher(); DependentSubjectListener a = new DependentSubjectListener("A", publisher); DependentSubjectListener b = new DependentSubjectListener("B", publisher); DependentSubjectListener c = new DependentSubjectListener("C", publisher); a.addListener(c); a.increment(10); assertEquals(10, a.latestRevision); assertEquals(0, b.latestRevision); assertEquals(10, c.latestRevision); c.increment(5); assertEquals(10, a.latestRevision); assertEquals(0, b.latestRevision); assertEquals(15, c.latestRevision); b.increment(20); assertEquals(10, a.latestRevision); assertEquals(20, b.latestRevision); assertEquals(15, c.latestRevision); b.addListener(c); assertEquals(10, a.latestRevision); assertEquals(20, b.latestRevision); assertEquals(20, c.latestRevision); b.increment(2); assertEquals(10, a.latestRevision); assertEquals(22, b.latestRevision); assertEquals(22, c.latestRevision); a.increment(15); assertEquals(25, a.latestRevision); assertEquals(22, b.latestRevision); assertEquals(25, c.latestRevision); a.addListener(b); assertEquals(25, a.latestRevision); assertEquals(25, b.latestRevision); assertEquals(25, c.latestRevision); a.increment(4); assertEquals(29, a.latestRevision); assertEquals(29, b.latestRevision); assertEquals(29, c.latestRevision); }
/** * The publisher should throw an IllegalStateException when a cycle in the listener graph is * created. */ public void testCycleThrows() { SequenceDependenciesEventPublisher publisher = new SequenceDependenciesEventPublisher(); DependentSubjectListener a = new DependentSubjectListener("A", publisher); DependentSubjectListener b = new DependentSubjectListener("B", publisher); DependentSubjectListener c = new DependentSubjectListener("C", publisher); // simple cycle of three a.addListener(b); b.addListener(c); try { c.addListener(a); fail("Cycle not detected"); } catch (IllegalStateException e) { // expected } // cycle of 10 publisher = new SequenceDependenciesEventPublisher(); DependentSubjectListener[] subjects = new DependentSubjectListener[10]; for (int i = 0; i < 10; i++) { subjects[i] = new DependentSubjectListener("" + i, publisher); if (i > 0) subjects[i - 1].addListener(subjects[i]); } try { subjects[9].addListener(subjects[0]); fail("Cycle not detected"); } catch (IllegalStateException e) { // expected } // cycle of 1 publisher = new SequenceDependenciesEventPublisher(); a = new DependentSubjectListener("A", publisher); try { a.addListener(a); fail("Cycle not detected"); } catch (IllegalStateException e) { // expected } }