blob: 8844540826b28dd180416233899b41adc8843eee [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2013 VMware Inc.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SpringSource, a division of VMware - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.equinox.region.internal.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.*;
import org.eclipse.equinox.region.*;
import org.eclipse.equinox.region.RegionDigraph.FilteredRegion;
import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.*;
public class StandardRegionDigraphTests {
private RegionDigraph digraph;
private Region mockRegion1;
private Region mockRegion2;
private Region mockRegion3;
private RegionFilter regionFilter1;
private RegionFilter regionFilter2;
@Before
public void setUp() throws Exception {
StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc");
StubBundleContext stubBundleContext = new StubBundleContext();
stubBundleContext.addInstalledBundle(stubSystemBundle);
this.digraph = RegionReflectionUtils.newStandardRegionDigraph(stubBundleContext, new ThreadLocal<Region>());
this.mockRegion1 = mock(Region.class);
when(this.mockRegion1.getName()).thenReturn("mockRegion1");
when(this.mockRegion1.getRegionDigraph()).thenReturn(this.digraph);
this.mockRegion2 = mock(Region.class);
when(this.mockRegion2.getName()).thenReturn("mockRegion2");
when(this.mockRegion2.getRegionDigraph()).thenReturn(this.digraph);
this.mockRegion3 = mock(Region.class);
when(this.mockRegion3.getName()).thenReturn("mockRegion3");
when(this.mockRegion3.getRegionDigraph()).thenReturn(this.digraph);
}
private void setDefaultFilters() {
this.regionFilter1 = digraph.createRegionFilterBuilder().build();
this.regionFilter2 = digraph.createRegionFilterBuilder().build();
}
private void setAllowedFilters(String b1Name, Version b1Version, String b2Name, Version b2Version)
throws InvalidSyntaxException {
String filter1 = "(&(" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + "=" + b1Name + ")("
+ Constants.BUNDLE_VERSION_ATTRIBUTE + "=" + b1Version + "))";
regionFilter1 = digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, filter1)
.build();
String filter2 = "(&(" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + "=" + b2Name + ")("
+ Constants.BUNDLE_VERSION_ATTRIBUTE + "=" + b2Version + "))";
regionFilter2 = digraph.createRegionFilterBuilder().allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, filter2)
.build();
}
@Test
public void testConnect() throws BundleException {
setDefaultFilters();
this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2);
}
@Test
public void testConnectWithFilterContents() throws BundleException, InvalidSyntaxException {
String b1Name = "b1";
Version b1Version = new Version("0");
String b2Name = "b2";
Version b2Version = new Version("0");
setAllowedFilters(b1Name, b1Version, b2Name, b2Version);
when(this.mockRegion1.getBundle(b1Name, b1Version)).thenReturn(null);
when(this.mockRegion1.getBundle(b2Name, b2Version)).thenReturn(null);
this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2);
this.digraph.connect(this.mockRegion1, this.regionFilter2, this.mockRegion3);
}
@Test(expected = BundleException.class)
public void testConnectLoop() throws BundleException {
setDefaultFilters();
this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion1);
}
@Test(expected = BundleException.class)
public void testDuplicateConnection() throws BundleException {
setDefaultFilters();
this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2);
this.digraph.connect(this.mockRegion1, this.regionFilter2, this.mockRegion2);
}
@Test
public void testReplaceConnection() throws BundleException {
setDefaultFilters();
RegionFilter existing;
existing = this.digraph.replaceConnection(this.mockRegion1, this.regionFilter1, this.mockRegion2);
assertEquals("Wrong existing filter.", null, existing);
existing = this.digraph.replaceConnection(this.mockRegion1, this.regionFilter2, this.mockRegion2);
assertEquals("Wrong existing filter.", this.regionFilter1, existing);
existing = this.digraph.replaceConnection(this.mockRegion1, null, this.mockRegion2);
assertEquals("Wrong existing filter.", this.regionFilter2, existing);
existing = this.digraph.replaceConnection(this.mockRegion1, this.regionFilter1, this.mockRegion2);
assertEquals("Wrong existing filter.", null, existing);
}
@Test
public void testGetEdges() throws BundleException {
setDefaultFilters();
this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2);
this.digraph.connect(this.mockRegion1, this.regionFilter2, this.mockRegion3);
this.digraph.connect(this.mockRegion2, this.regionFilter2, this.mockRegion1);
Set<FilteredRegion> edges = this.digraph.getEdges(this.mockRegion1);
assertEquals(2, edges.size());
for (FilteredRegion edge : edges) {
if (edge.getRegion().equals(this.mockRegion2)) {
assertEquals(this.regionFilter1, edge.getFilter());
} else if (edge.getRegion().equals(this.mockRegion3)) {
assertEquals(this.regionFilter2, edge.getFilter());
} else {
fail("unexpected edge");
}
}
this.digraph.replaceConnection(this.mockRegion1, this.regionFilter2, this.mockRegion2);
edges = this.digraph.getEdges(this.mockRegion1);
assertEquals(2, edges.size());
for (FilteredRegion edge : edges) {
if (edge.getRegion().equals(this.mockRegion2)) {
assertEquals(this.regionFilter2, edge.getFilter());
} else if (edge.getRegion().equals(this.mockRegion3)) {
assertEquals(this.regionFilter2, edge.getFilter());
} else {
fail("unexpected edge");
}
}
}
@Test
public void testRemoveRegion() throws BundleException {
setDefaultFilters();
this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2);
this.digraph.connect(this.mockRegion2, this.regionFilter2, this.mockRegion1);
assertNotNull(this.digraph.getRegion("mockRegion1"));
assertNotNull(this.digraph.getRegion("mockRegion2"));
this.digraph.removeRegion(this.mockRegion1);
assertNull(this.digraph.getRegion("mockRegion1"));
assertNotNull(this.digraph.getRegion("mockRegion2"));
}
@Test
public void testGetRegions() throws BundleException {
setDefaultFilters();
this.digraph.connect(this.mockRegion1, this.regionFilter1, this.mockRegion2);
Set<Region> regions = this.digraph.getRegions();
assertEquals(2, regions.size());
assertTrue(regions.contains(this.mockRegion1));
assertTrue(regions.contains(this.mockRegion2));
}
private static final String REGION_A = "A";
private static final String REGION_B = "B";
private static final String REGION_C = "C";
private static final String REGION_D = "D";
@Test
public void testCopyRegion() throws BundleException, InvalidSyntaxException {
RegionDigraph testDigraph = RegionReflectionUtils.newStandardRegionDigraph();
long bundleId = 1;
Region a = testDigraph.createRegion(REGION_A);
a.addBundle(bundleId++);
a.addBundle(bundleId++);
Region b = testDigraph.createRegion(REGION_B);
b.addBundle(bundleId++);
b.addBundle(bundleId++);
Region c = testDigraph.createRegion(REGION_C);
c.addBundle(bundleId++);
c.addBundle(bundleId++);
Region d = testDigraph.createRegion(REGION_D);
d.addBundle(bundleId++);
d.addBundle(bundleId++);
testDigraph.connect(a, testDigraph.createRegionFilterBuilder().allow("a", "(a=x)").build(), b);
testDigraph.connect(b, testDigraph.createRegionFilterBuilder().allow("b", "(b=x)").build(), c);
testDigraph.connect(c, testDigraph.createRegionFilterBuilder().allow("c", "(c=x)").build(), d);
testDigraph.connect(d, testDigraph.createRegionFilterBuilder().allow("d", "(d=x)").build(), a);
RegionDigraph testCopy = testDigraph.copy();
StandardRegionDigraphPeristenceTests.assertEquals(testDigraph, testCopy);
a = testCopy.getRegion(REGION_A);
b = testCopy.getRegion(REGION_B);
c = testCopy.getRegion(REGION_C);
d = testCopy.getRegion(REGION_D);
for (Region region : testCopy) {
testCopy.removeRegion(region);
}
testCopy.connect(a, testCopy.createRegionFilterBuilder().allow("a", "(a=x)").build(), d);
testCopy.connect(b, testCopy.createRegionFilterBuilder().allow("b", "(b=x)").build(), a);
testCopy.connect(c, testCopy.createRegionFilterBuilder().allow("c", "(c=x)").build(), b);
testCopy.connect(d, testCopy.createRegionFilterBuilder().allow("d", "(d=x)").build(), c);
try {
StandardRegionDigraphPeristenceTests.assertEquals(testDigraph, testCopy);
fail("Digraphs must not be equal");
} catch (AssertionError e) {
// expected
}
testDigraph.replace(testCopy);
StandardRegionDigraphPeristenceTests.assertEquals(testDigraph, testCopy);
// test that we can continue to use the copy to replace as long as it is upto
// date with the last replace
Region testAdd1 = testCopy.createRegion("testAdd1");
testCopy.connect(testAdd1, testCopy.createRegionFilterBuilder().allow("testAdd1", "(testAdd=x)").build(), a);
try {
StandardRegionDigraphPeristenceTests.assertEquals(testDigraph, testCopy);
fail("Digraphs must not be equal");
} catch (AssertionError e) {
// expected
}
testDigraph.replace(testCopy);
StandardRegionDigraphPeristenceTests.assertEquals(testDigraph, testCopy);
// test that we fail if the digraph was modified since last copy/replace
testCopy = testDigraph.copy();
// add a new bundle to the original
Region origA = testDigraph.getRegion(REGION_A);
origA.addBundle(bundleId++);
try {
testDigraph.replace(testCopy);
fail("Digraph changed since copy.");
} catch (BundleException e) {
// expected
}
// test that we fail if the digraph was modified since last copy/replace
testCopy = testDigraph.copy();
// add a new bundle to the original
origA.removeBundle(bundleId);
try {
testDigraph.replace(testCopy);
fail("Digraph changed since copy.");
} catch (BundleException e) {
// expected
}
testCopy = testDigraph.copy();
// add a new region to the original
Region testAdd2 = testDigraph.createRegion("testAdd2");
testDigraph.connect(testAdd2, testCopy.createRegionFilterBuilder().allow("testAdd2", "(testAdd=x)").build(),
origA);
try {
testDigraph.replace(testCopy);
fail("Digraph changed since copy.");
} catch (BundleException e) {
// expected
}
testCopy = testDigraph.copy();
// change a connection in the original
testDigraph.removeRegion(testAdd2);
testDigraph.connect(testAdd2, testCopy.createRegionFilterBuilder().allow("testAdd2", "(testAdd=y)").build(),
origA);
try {
testDigraph.replace(testCopy);
fail("Digraph changed since copy.");
} catch (BundleException e) {
// expected
}
testCopy = testDigraph.copy();
Region origB = testDigraph.getRegion(REGION_B);
// add a connection in the original
testDigraph.connect(testAdd2, testCopy.createRegionFilterBuilder().allow("testAdd2", "(testAdd=y)").build(),
origB);
try {
testDigraph.replace(testCopy);
fail("Digraph changed since copy.");
} catch (BundleException e) {
// expected
}
}
static class TestRegionDigraphVisitor implements RegionDigraphVisitor {
final Collection<Region> visited = new ArrayList<Region>();
final String namespace;
final Map<String, ?> attributes;
public TestRegionDigraphVisitor(String namespace, Map<String, ?> attributes) {
super();
this.namespace = namespace;
this.attributes = attributes;
}
@Override
public boolean visit(Region region) {
visited.add(region);
return true;
}
@Override
public boolean preEdgeTraverse(RegionFilter regionFilter) {
return regionFilter.isAllowed(namespace, attributes);
}
@Override
public void postEdgeTraverse(RegionFilter regionFilter) {
// nothing
}
Collection<Region> clearVisited() {
Collection<Region> result = new ArrayList<Region>(visited);
visited.clear();
return result;
}
}
@Test
public void testVisitRegions() throws BundleException, InvalidSyntaxException {
RegionDigraph testDigraph = RegionReflectionUtils.newStandardRegionDigraph();
Region a = testDigraph.createRegion(REGION_A);
Region b = testDigraph.createRegion(REGION_B);
Region c = testDigraph.createRegion(REGION_C);
Region d = testDigraph.createRegion(REGION_D);
testDigraph.connect(a, testDigraph.createRegionFilterBuilder().allow("b", "(b=x)").allow("c", "(c=x)")
.allow("d", "(d=x)").build(), b);
testDigraph.connect(b, testDigraph.createRegionFilterBuilder().allow("c", "(c=x)").allow("d", "(d=x)").build(),
c);
testDigraph.connect(c, testDigraph.createRegionFilterBuilder().allow("d", "(d=x)").build(), d);
Map<String, String> attributes = new HashMap<String, String>();
attributes.put("d", "x");
TestRegionDigraphVisitor visitor = new TestRegionDigraphVisitor("d", attributes);
Collection<Region> expected = new ArrayList<Region>(Arrays.asList(a, b, c, d));
for (Region region : expected.toArray(new Region[0])) {
testDigraph.visitSubgraph(region, visitor);
Collection<Region> visited = visitor.clearVisited();
assertEquals("Wrong number of visited: " + region, expected.size(), visited.size());
assertTrue("Wrong visited content: " + region, visited.containsAll(expected));
expected.remove(region);
}
attributes.clear();
attributes.put("c", "x");
visitor = new TestRegionDigraphVisitor("c", attributes);
expected = new ArrayList<Region>(Arrays.asList(a, b, c));
for (Region region : expected.toArray(new Region[0])) {
testDigraph.visitSubgraph(region, visitor);
Collection<Region> visited = visitor.clearVisited();
assertEquals("Wrong number of visited: " + region, expected.size(), visited.size());
assertTrue("Wrong visited content: " + region, visited.containsAll(expected));
expected.remove(region);
}
attributes.clear();
attributes.put("b", "x");
visitor = new TestRegionDigraphVisitor("b", attributes);
expected = new ArrayList<Region>(Arrays.asList(a, b));
for (Region region : expected.toArray(new Region[0])) {
testDigraph.visitSubgraph(region, visitor);
Collection<Region> visited = visitor.clearVisited();
assertEquals("Wrong number of visited: " + region, expected.size(), visited.size());
assertTrue("Wrong visited content: " + region, visited.containsAll(expected));
expected.remove(region);
}
}
@Test
public void testGetHooks() throws BundleException {
setDefaultFilters();
assertNotNull("Resolver Hook is null", digraph.getResolverHookFactory());
assertNotNull("Bundle Event Hook is null", digraph.getBundleEventHook());
assertNotNull("Bundle Find Hook is null", digraph.getBundleFindHook());
assertNotNull("Servie Event Hook is null", digraph.getServiceEventHook());
assertNotNull("Service Find Hook is null", digraph.getServiceFindHook());
RegionDigraph copy = digraph.copy();
assertNotNull("Resolver Hook is null", copy.getResolverHookFactory());
assertNotNull("Bundle Event Hook is null", copy.getBundleEventHook());
assertNotNull("Bundle Find Hook is null", copy.getBundleFindHook());
assertNotNull("Servie Event Hook is null", copy.getServiceEventHook());
assertNotNull("Service Find Hook is null", copy.getServiceFindHook());
}
}