Simon Hunt

ONOS-4971: Synthetic Link Data -- WIP

- Enhancing UiRegion to capture the hierarchical (parent/child) relationships captured in the UiTopoLayouts.

Change-Id: I152e0d52d4580b14b679f3387402077f16f61e6a
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 */ 15 */
16 package org.onosproject.ui; 16 package org.onosproject.ui;
17 17
18 +import org.onosproject.net.region.RegionId;
18 import org.onosproject.ui.model.topo.UiTopoLayout; 19 import org.onosproject.ui.model.topo.UiTopoLayout;
19 import org.onosproject.ui.model.topo.UiTopoLayoutId; 20 import org.onosproject.ui.model.topo.UiTopoLayoutId;
20 21
...@@ -57,6 +58,15 @@ public interface UiTopoLayoutService { ...@@ -57,6 +58,15 @@ public interface UiTopoLayoutService {
57 UiTopoLayout getLayout(UiTopoLayoutId layoutId); 58 UiTopoLayout getLayout(UiTopoLayoutId layoutId);
58 59
59 /** 60 /**
61 + * Returns the layout which has the backing region identified by
62 + * the given region identifier.
63 + *
64 + * @param regionId region identifier
65 + * @return corresponding layout
66 + */
67 + UiTopoLayout getLayout(RegionId regionId);
68 +
69 + /**
60 * Returns the set of peer layouts of the specified layout. That is, 70 * Returns the set of peer layouts of the specified layout. That is,
61 * those layouts that share the same parent. 71 * those layouts that share the same parent.
62 * 72 *
......
...@@ -24,11 +24,20 @@ import org.onosproject.net.host.HostService; ...@@ -24,11 +24,20 @@ import org.onosproject.net.host.HostService;
24 import org.onosproject.net.intent.IntentService; 24 import org.onosproject.net.intent.IntentService;
25 import org.onosproject.net.link.LinkService; 25 import org.onosproject.net.link.LinkService;
26 import org.onosproject.net.region.RegionService; 26 import org.onosproject.net.region.RegionService;
27 +import org.onosproject.ui.UiTopoLayoutService;
27 28
28 /** 29 /**
29 * A bundle of services to pass to elements that might need a reference to them. 30 * A bundle of services to pass to elements that might need a reference to them.
30 */ 31 */
31 public interface ServiceBundle { 32 public interface ServiceBundle {
33 +
34 + /**
35 + * Reference to a UI Topology Layout service implementation.
36 + *
37 + * @return layout service
38 + */
39 + UiTopoLayoutService layout();
40 +
32 /** 41 /**
33 * Reference to a cluster service implementation. 42 * Reference to a cluster service implementation.
34 * 43 *
......
...@@ -61,6 +61,10 @@ public class UiRegion extends UiNode { ...@@ -61,6 +61,10 @@ public class UiRegion extends UiNode {
61 61
62 private final Region region; 62 private final Region region;
63 63
64 + // keep track of hierarchy (inferred from UiTopoLayoutService)
65 + private RegionId parent;
66 + private final Set<RegionId> kids = new HashSet<>();
67 +
64 /** 68 /**
65 * Constructs a UI region, with a reference to the specified backing region. 69 * Constructs a UI region, with a reference to the specified backing region.
66 * 70 *
...@@ -103,6 +107,52 @@ public class UiRegion extends UiNode { ...@@ -103,6 +107,52 @@ public class UiRegion extends UiNode {
103 return region == null ? NULL_ID : region.id(); 107 return region == null ? NULL_ID : region.id();
104 } 108 }
105 109
110 + /**
111 + * Returns the identity of the parent region.
112 + *
113 + * @return parent region ID
114 + */
115 + public RegionId parent() {
116 + return parent;
117 + }
118 +
119 + /**
120 + * Returns true if this is the root (default) region.
121 + *
122 + * @return true if root region
123 + */
124 + public boolean isRoot() {
125 + return id().equals(parent);
126 + }
127 +
128 + /**
129 + * Returns the identities of the child regions.
130 + *
131 + * @return child region IDs
132 + */
133 + public Set<RegionId> children() {
134 + return ImmutableSet.copyOf(kids);
135 + }
136 +
137 + /**
138 + * Sets the parent ID for this region.
139 + *
140 + * @param parentId parent ID
141 + */
142 + public void setParent(RegionId parentId) {
143 + parent = parentId;
144 + }
145 +
146 + /**
147 + * Sets the children IDs for this region.
148 + *
149 + * @param children children IDs
150 + */
151 + public void setChildren(Set<RegionId> children) {
152 + kids.clear();
153 + kids.addAll(children);
154 + }
155 +
106 @Override 156 @Override
107 public String idAsString() { 157 public String idAsString() {
108 return id().toString(); 158 return id().toString();
...@@ -138,6 +188,8 @@ public class UiRegion extends UiNode { ...@@ -138,6 +188,8 @@ public class UiRegion extends UiNode {
138 return toStringHelper(this) 188 return toStringHelper(this)
139 .add("id", id()) 189 .add("id", id())
140 .add("name", name()) 190 .add("name", name())
191 + .add("parent", parent)
192 + .add("kids", kids)
141 .add("devices", deviceIds) 193 .add("devices", deviceIds)
142 .add("#hosts", hostIds.size()) 194 .add("#hosts", hostIds.size())
143 .add("#links", uiLinkIds.size()) 195 .add("#links", uiLinkIds.size())
......
...@@ -68,13 +68,16 @@ public class UiTopoLayout { ...@@ -68,13 +68,16 @@ public class UiTopoLayout {
68 } 68 }
69 69
70 /** 70 /**
71 - * Returns the identifier of the backing region. Will be null if the 71 + * Returns the identifier of the backing region. If this is the default
72 - * region is null. 72 + * layout, the null-region ID will be returned, otherwise the ID of the
73 + * backing region for this layout will be returned; null in the case that
74 + * there is no backing region.
73 * 75 *
74 * @return backing region identifier 76 * @return backing region identifier
75 */ 77 */
76 public RegionId regionId() { 78 public RegionId regionId() {
77 - return region == null ? null : region.id(); 79 + return isRoot() ? UiRegion.NULL_ID
80 + : (region == null ? null : region.id());
78 } 81 }
79 82
80 /** 83 /**
......
...@@ -151,7 +151,8 @@ public class UiTopology extends UiElement { ...@@ -151,7 +151,8 @@ public class UiTopology extends UiElement {
151 151
152 152
153 /** 153 /**
154 - * Returns all regions in the model. 154 + * Returns all regions in the model (except the
155 + * {@link #nullRegion() null region}).
155 * 156 *
156 * @return all regions 157 * @return all regions
157 */ 158 */
...@@ -177,7 +178,7 @@ public class UiTopology extends UiElement { ...@@ -177,7 +178,7 @@ public class UiTopology extends UiElement {
177 * @return corresponding UI region 178 * @return corresponding UI region
178 */ 179 */
179 public UiRegion findRegion(RegionId id) { 180 public UiRegion findRegion(RegionId id) {
180 - return regionLookup.get(id); 181 + return UiRegion.NULL_ID.equals(id) ? nullRegion() : regionLookup.get(id);
181 } 182 }
182 183
183 /** 184 /**
......
...@@ -28,6 +28,7 @@ import org.onosproject.net.intent.IntentService; ...@@ -28,6 +28,7 @@ import org.onosproject.net.intent.IntentService;
28 import org.onosproject.net.link.LinkService; 28 import org.onosproject.net.link.LinkService;
29 import org.onosproject.net.region.RegionService; 29 import org.onosproject.net.region.RegionService;
30 import org.onosproject.ui.AbstractUiTest; 30 import org.onosproject.ui.AbstractUiTest;
31 +import org.onosproject.ui.UiTopoLayoutService;
31 32
32 /** 33 /**
33 * Base class for UI model unit tests. 34 * Base class for UI model unit tests.
...@@ -42,6 +43,11 @@ public class AbstractUiModelTest extends AbstractUiTest { ...@@ -42,6 +43,11 @@ public class AbstractUiModelTest extends AbstractUiTest {
42 protected static final ServiceBundle MOCK_SERVICES = 43 protected static final ServiceBundle MOCK_SERVICES =
43 new ServiceBundle() { 44 new ServiceBundle() {
44 @Override 45 @Override
46 + public UiTopoLayoutService layout() {
47 + return null;
48 + }
49 +
50 + @Override
45 public ClusterService cluster() { 51 public ClusterService cluster() {
46 return MOCK_CLUSTER; 52 return MOCK_CLUSTER;
47 } 53 }
......
...@@ -24,17 +24,20 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -24,17 +24,20 @@ import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 24 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.apache.felix.scr.annotations.Service; 25 import org.apache.felix.scr.annotations.Service;
26 import org.onlab.util.KryoNamespace; 26 import org.onlab.util.KryoNamespace;
27 +import org.onosproject.net.region.RegionId;
27 import org.onosproject.store.serializers.KryoNamespaces; 28 import org.onosproject.store.serializers.KryoNamespaces;
28 import org.onosproject.store.service.ConsistentMap; 29 import org.onosproject.store.service.ConsistentMap;
29 import org.onosproject.store.service.Serializer; 30 import org.onosproject.store.service.Serializer;
30 import org.onosproject.store.service.StorageService; 31 import org.onosproject.store.service.StorageService;
31 import org.onosproject.ui.UiTopoLayoutService; 32 import org.onosproject.ui.UiTopoLayoutService;
33 +import org.onosproject.ui.model.topo.UiRegion;
32 import org.onosproject.ui.model.topo.UiTopoLayout; 34 import org.onosproject.ui.model.topo.UiTopoLayout;
33 import org.onosproject.ui.model.topo.UiTopoLayoutId; 35 import org.onosproject.ui.model.topo.UiTopoLayoutId;
34 import org.slf4j.Logger; 36 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory; 37 import org.slf4j.LoggerFactory;
36 38
37 import java.util.Collections; 39 import java.util.Collections;
40 +import java.util.List;
38 import java.util.Map; 41 import java.util.Map;
39 import java.util.Objects; 42 import java.util.Objects;
40 import java.util.Set; 43 import java.util.Set;
...@@ -111,6 +114,18 @@ public class UiTopoLayoutManager implements UiTopoLayoutService { ...@@ -111,6 +114,18 @@ public class UiTopoLayoutManager implements UiTopoLayoutService {
111 } 114 }
112 115
113 @Override 116 @Override
117 + public UiTopoLayout getLayout(RegionId regionId) {
118 + if (regionId == null || regionId.equals(UiRegion.NULL_ID)) {
119 + return getRootLayout();
120 + }
121 +
122 + List<UiTopoLayout> matchingLayouts = layoutMap.values().stream()
123 + .filter(l -> Objects.equals(regionId, l.regionId()))
124 + .collect(Collectors.toList());
125 + return matchingLayouts.isEmpty() ? null : matchingLayouts.get(0);
126 + }
127 +
128 + @Override
114 public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) { 129 public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
115 checkNotNull(layoutId, ID_NULL); 130 checkNotNull(layoutId, ID_NULL);
116 131
......
...@@ -29,6 +29,7 @@ public class ListRegions extends AbstractElementCommand { ...@@ -29,6 +29,7 @@ public class ListRegions extends AbstractElementCommand {
29 @Override 29 @Override
30 protected void execute() { 30 protected void execute() {
31 UiSharedTopologyModel model = get(UiSharedTopologyModel.class); 31 UiSharedTopologyModel model = get(UiSharedTopologyModel.class);
32 + print("%s", model.getNullRegion());
32 sorted(model.getRegions()).forEach(r -> print("%s", r)); 33 sorted(model.getRegions()).forEach(r -> print("%s", r));
33 } 34 }
34 } 35 }
......
...@@ -29,6 +29,7 @@ import org.onosproject.net.HostLocation; ...@@ -29,6 +29,7 @@ import org.onosproject.net.HostLocation;
29 import org.onosproject.net.Link; 29 import org.onosproject.net.Link;
30 import org.onosproject.net.region.Region; 30 import org.onosproject.net.region.Region;
31 import org.onosproject.net.region.RegionId; 31 import org.onosproject.net.region.RegionId;
32 +import org.onosproject.ui.UiTopoLayoutService;
32 import org.onosproject.ui.model.ServiceBundle; 33 import org.onosproject.ui.model.ServiceBundle;
33 import org.onosproject.ui.model.topo.UiClusterMember; 34 import org.onosproject.ui.model.topo.UiClusterMember;
34 import org.onosproject.ui.model.topo.UiDevice; 35 import org.onosproject.ui.model.topo.UiDevice;
...@@ -37,6 +38,8 @@ import org.onosproject.ui.model.topo.UiHost; ...@@ -37,6 +38,8 @@ import org.onosproject.ui.model.topo.UiHost;
37 import org.onosproject.ui.model.topo.UiLink; 38 import org.onosproject.ui.model.topo.UiLink;
38 import org.onosproject.ui.model.topo.UiLinkId; 39 import org.onosproject.ui.model.topo.UiLinkId;
39 import org.onosproject.ui.model.topo.UiRegion; 40 import org.onosproject.ui.model.topo.UiRegion;
41 +import org.onosproject.ui.model.topo.UiTopoLayout;
42 +import org.onosproject.ui.model.topo.UiTopoLayoutId;
40 import org.onosproject.ui.model.topo.UiTopology; 43 import org.onosproject.ui.model.topo.UiTopology;
41 import org.slf4j.Logger; 44 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory; 45 import org.slf4j.LoggerFactory;
...@@ -202,6 +205,34 @@ class ModelCache { ...@@ -202,6 +205,34 @@ class ModelCache {
202 205
203 // Make sure the region object refers to the devices 206 // Make sure the region object refers to the devices
204 region.reconcileDevices(deviceIds); 207 region.reconcileDevices(deviceIds);
208 +
209 + fixupContainmentHierarchy(region);
210 + }
211 +
212 + private void fixupContainmentHierarchy(UiRegion region) {
213 + UiTopoLayoutService ls = services.layout();
214 + RegionId regionId = region.id();
215 +
216 + UiTopoLayout layout = ls.getLayout(regionId);
217 + if (layout == null) {
218 + // no layout backed by this region
219 + log.warn("No layout backed by region {}", regionId);
220 + return;
221 + }
222 +
223 + UiTopoLayoutId layoutId = layout.id();
224 +
225 + if (!layout.isRoot()) {
226 + UiTopoLayoutId parentId = layout.parent();
227 + UiTopoLayout parentLayout = ls.getLayout(parentId);
228 + RegionId parentRegionId = parentLayout.regionId();
229 + region.setParent(parentRegionId);
230 + }
231 +
232 + Set<UiTopoLayout> kids = ls.getChildren(layoutId);
233 + Set<RegionId> kidRegionIds = new HashSet<>(kids.size());
234 + kids.forEach(k -> kidRegionIds.add(k.regionId()));
235 + region.setChildren(kidRegionIds);
205 } 236 }
206 237
207 private void loadRegions() { 238 private void loadRegions() {
...@@ -478,7 +509,11 @@ class ModelCache { ...@@ -478,7 +509,11 @@ class ModelCache {
478 public void refresh() { 509 public void refresh() {
479 // fix up internal linkages if they aren't correct 510 // fix up internal linkages if they aren't correct
480 511
481 - // at the moment, this is making sure devices are in the correct region 512 + // make sure regions reflect layout containment hierarchy
513 + fixupContainmentHierarchy(uiTopology.nullRegion());
514 + uiTopology.allRegions().forEach(this::fixupContainmentHierarchy);
515 +
516 + // make sure devices are in the correct region
482 Set<UiDevice> allDevices = uiTopology.allDevices(); 517 Set<UiDevice> allDevices = uiTopology.allDevices();
483 518
484 services.region().getRegions().forEach(r -> { 519 services.region().getRegions().forEach(r -> {
......
...@@ -60,6 +60,7 @@ import org.onosproject.net.region.RegionListener; ...@@ -60,6 +60,7 @@ import org.onosproject.net.region.RegionListener;
60 import org.onosproject.net.region.RegionService; 60 import org.onosproject.net.region.RegionService;
61 import org.onosproject.net.statistic.StatisticService; 61 import org.onosproject.net.statistic.StatisticService;
62 import org.onosproject.net.topology.TopologyService; 62 import org.onosproject.net.topology.TopologyService;
63 +import org.onosproject.ui.UiTopoLayoutService;
63 import org.onosproject.ui.impl.topo.UiTopoSession; 64 import org.onosproject.ui.impl.topo.UiTopoSession;
64 import org.onosproject.ui.model.ServiceBundle; 65 import org.onosproject.ui.model.ServiceBundle;
65 import org.onosproject.ui.model.topo.UiClusterMember; 66 import org.onosproject.ui.model.topo.UiClusterMember;
...@@ -87,6 +88,9 @@ public final class UiSharedTopologyModel ...@@ -87,6 +88,9 @@ public final class UiSharedTopologyModel
87 LoggerFactory.getLogger(UiSharedTopologyModel.class); 88 LoggerFactory.getLogger(UiSharedTopologyModel.class);
88 89
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 + private UiTopoLayoutService layoutService;
92 +
93 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 private ClusterService clusterService; 94 private ClusterService clusterService;
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 private MastershipService mastershipService; 96 private MastershipService mastershipService;
...@@ -282,6 +286,11 @@ public final class UiSharedTopologyModel ...@@ -282,6 +286,11 @@ public final class UiSharedTopologyModel
282 */ 286 */
283 private class DefaultServiceBundle implements ServiceBundle { 287 private class DefaultServiceBundle implements ServiceBundle {
284 @Override 288 @Override
289 + public UiTopoLayoutService layout() {
290 + return layoutService;
291 + }
292 +
293 + @Override
285 public ClusterService cluster() { 294 public ClusterService cluster() {
286 return clusterService; 295 return clusterService;
287 } 296 }
......
...@@ -54,8 +54,11 @@ import org.onosproject.net.region.Region; ...@@ -54,8 +54,11 @@ import org.onosproject.net.region.Region;
54 import org.onosproject.net.region.RegionId; 54 import org.onosproject.net.region.RegionId;
55 import org.onosproject.net.region.RegionListener; 55 import org.onosproject.net.region.RegionListener;
56 import org.onosproject.net.region.RegionService; 56 import org.onosproject.net.region.RegionService;
57 +import org.onosproject.ui.UiTopoLayoutService;
57 import org.onosproject.ui.impl.AbstractUiImplTest; 58 import org.onosproject.ui.impl.AbstractUiImplTest;
58 import org.onosproject.ui.model.ServiceBundle; 59 import org.onosproject.ui.model.ServiceBundle;
60 +import org.onosproject.ui.model.topo.UiTopoLayout;
61 +import org.onosproject.ui.model.topo.UiTopoLayoutId;
59 62
60 import java.util.ArrayList; 63 import java.util.ArrayList;
61 import java.util.Collections; 64 import java.util.Collections;
...@@ -69,6 +72,7 @@ import static org.onosproject.cluster.NodeId.nodeId; ...@@ -69,6 +72,7 @@ import static org.onosproject.cluster.NodeId.nodeId;
69 import static org.onosproject.net.DeviceId.deviceId; 72 import static org.onosproject.net.DeviceId.deviceId;
70 import static org.onosproject.net.HostId.hostId; 73 import static org.onosproject.net.HostId.hostId;
71 import static org.onosproject.net.PortNumber.portNumber; 74 import static org.onosproject.net.PortNumber.portNumber;
75 +import static org.onosproject.ui.model.topo.UiTopoLayoutId.layoutId;
72 76
73 /** 77 /**
74 * Base class for model test classes. 78 * Base class for model test classes.
...@@ -90,6 +94,12 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -90,6 +94,12 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
90 94
91 Twelve hosts (two per D4 ... D9) H4a, H4b, H5a, H5b, ... 95 Twelve hosts (two per D4 ... D9) H4a, H4b, H5a, H5b, ...
92 96
97 + Layouts:
98 + LROOT : (default)
99 + +-- L1 : R1
100 + +-- L2 : R2
101 + +-- L3 : R3
102 +
93 Regions: 103 Regions:
94 R1 : D1, D2, D3 104 R1 : D1, D2, D3
95 R2 : D4, D5, D6 105 R2 : D4, D5, D6
...@@ -136,6 +146,27 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -136,6 +146,27 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
136 protected static final Set<Region> REGION_SET = 146 protected static final Set<Region> REGION_SET =
137 ImmutableSet.of(REGION_1, REGION_2, REGION_3); 147 ImmutableSet.of(REGION_1, REGION_2, REGION_3);
138 148
149 + protected static final String LROOT = "LROOT";
150 + protected static final String L1 = "L1";
151 + protected static final String L2 = "L2";
152 + protected static final String L3 = "L3";
153 +
154 + protected static final UiTopoLayout LAYOUT_ROOT = layout(LROOT, null, null);
155 + protected static final UiTopoLayout LAYOUT_1 = layout(L1, REGION_1, LROOT);
156 + protected static final UiTopoLayout LAYOUT_2 = layout(L2, REGION_2, LROOT);
157 + protected static final UiTopoLayout LAYOUT_3 = layout(L3, REGION_3, LROOT);
158 +
159 + protected static final Set<UiTopoLayout> LAYOUT_SET =
160 + ImmutableSet.of(LAYOUT_ROOT, LAYOUT_1, LAYOUT_2, LAYOUT_3);
161 + protected static final Set<UiTopoLayout> ROOT_KIDS =
162 + ImmutableSet.of(LAYOUT_1, LAYOUT_2, LAYOUT_3);
163 + protected static final Set<UiTopoLayout> PEERS_OF_1 =
164 + ImmutableSet.of(LAYOUT_2, LAYOUT_3);
165 + protected static final Set<UiTopoLayout> PEERS_OF_2 =
166 + ImmutableSet.of(LAYOUT_1, LAYOUT_3);
167 + protected static final Set<UiTopoLayout> PEERS_OF_3 =
168 + ImmutableSet.of(LAYOUT_1, LAYOUT_2);
169 +
139 protected static final String D1 = "d1"; 170 protected static final String D1 = "d1";
140 protected static final String D2 = "d2"; 171 protected static final String D2 = "d2";
141 protected static final String D3 = "d3"; 172 protected static final String D3 = "d3";
...@@ -222,6 +253,21 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -222,6 +253,21 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
222 } 253 }
223 254
224 /** 255 /**
256 + * Returns UI topology layout instance with the specified parameters.
257 + *
258 + * @param layoutId the layout ID
259 + * @param region the backing region
260 + * @param parentId the parent layout ID
261 + * @return layout instance
262 + */
263 + protected static UiTopoLayout layout(String layoutId, Region region,
264 + String parentId) {
265 + UiTopoLayoutId pid = parentId == null
266 + ? UiTopoLayoutId.DEFAULT_ID : layoutId(parentId);
267 + return new UiTopoLayout(layoutId(layoutId), region, pid);
268 + }
269 +
270 + /**
225 * Returns a region instance with specified parameters. 271 * Returns a region instance with specified parameters.
226 * 272 *
227 * @param id region id 273 * @param id region id
...@@ -255,6 +301,11 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -255,6 +301,11 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
255 protected static final ServiceBundle MOCK_SERVICES = 301 protected static final ServiceBundle MOCK_SERVICES =
256 new ServiceBundle() { 302 new ServiceBundle() {
257 @Override 303 @Override
304 + public UiTopoLayoutService layout() {
305 + return MOCK_LAYOUT;
306 + }
307 +
308 + @Override
258 public ClusterService cluster() { 309 public ClusterService cluster() {
259 return MOCK_CLUSTER; 310 return MOCK_CLUSTER;
260 } 311 }
...@@ -297,6 +348,7 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -297,6 +348,7 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
297 348
298 private static final ClusterService MOCK_CLUSTER = new MockClusterService(); 349 private static final ClusterService MOCK_CLUSTER = new MockClusterService();
299 private static final MastershipService MOCK_MASTER = new MockMasterService(); 350 private static final MastershipService MOCK_MASTER = new MockMasterService();
351 + private static final UiTopoLayoutService MOCK_LAYOUT = new MockLayoutService();
300 private static final RegionService MOCK_REGION = new MockRegionService(); 352 private static final RegionService MOCK_REGION = new MockRegionService();
301 private static final DeviceService MOCK_DEVICE = new MockDeviceService(); 353 private static final DeviceService MOCK_DEVICE = new MockDeviceService();
302 private static final LinkService MOCK_LINK = new MockLinkService(); 354 private static final LinkService MOCK_LINK = new MockLinkService();
...@@ -384,6 +436,71 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest { ...@@ -384,6 +436,71 @@ abstract class AbstractTopoModelTest extends AbstractUiImplTest {
384 } 436 }
385 } 437 }
386 438
439 + // TODO: consider implementing UiTopoLayoutServiceAdapter and extending that here
440 + private static class MockLayoutService implements UiTopoLayoutService {
441 + private final Map<UiTopoLayoutId, UiTopoLayout> map = new HashMap<>();
442 + private final Map<UiTopoLayoutId, Set<UiTopoLayout>> peers = new HashMap<>();
443 + private final Map<RegionId, UiTopoLayout> byRegion = new HashMap<>();
444 +
445 + MockLayoutService() {
446 + map.put(LAYOUT_ROOT.id(), LAYOUT_ROOT);
447 + map.put(LAYOUT_1.id(), LAYOUT_1);
448 + map.put(LAYOUT_2.id(), LAYOUT_2);
449 + map.put(LAYOUT_3.id(), LAYOUT_3);
450 +
451 + peers.put(LAYOUT_ROOT.id(), ImmutableSet.of());
452 + peers.put(LAYOUT_1.id(), ImmutableSet.of(LAYOUT_2, LAYOUT_3));
453 + peers.put(LAYOUT_2.id(), ImmutableSet.of(LAYOUT_1, LAYOUT_3));
454 + peers.put(LAYOUT_3.id(), ImmutableSet.of(LAYOUT_1, LAYOUT_2));
455 +
456 + byRegion.put(REGION_1.id(), LAYOUT_1);
457 + byRegion.put(REGION_2.id(), LAYOUT_2);
458 + byRegion.put(REGION_3.id(), LAYOUT_3);
459 + }
460 +
461 + @Override
462 + public UiTopoLayout getRootLayout() {
463 + return LAYOUT_ROOT;
464 + }
465 +
466 + @Override
467 + public Set<UiTopoLayout> getLayouts() {
468 + return LAYOUT_SET;
469 + }
470 +
471 + @Override
472 + public boolean addLayout(UiTopoLayout layout) {
473 + return false;
474 + }
475 +
476 + @Override
477 + public UiTopoLayout getLayout(UiTopoLayoutId layoutId) {
478 + return map.get(layoutId);
479 + }
480 +
481 + @Override
482 + public UiTopoLayout getLayout(RegionId regionId) {
483 + return byRegion.get(regionId);
484 + }
485 +
486 + @Override
487 + public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
488 + return peers.get(layoutId);
489 + }
490 +
491 + @Override
492 + public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
493 + return LAYOUT_ROOT.id().equals(layoutId)
494 + ? ROOT_KIDS
495 + : Collections.emptySet();
496 + }
497 +
498 + @Override
499 + public boolean removeLayout(UiTopoLayout layout) {
500 + return false;
501 + }
502 + }
503 +
387 // TODO: consider implementing RegionServiceAdapter and extending that here 504 // TODO: consider implementing RegionServiceAdapter and extending that here
388 private static class MockRegionService implements RegionService { 505 private static class MockRegionService implements RegionService {
389 506
......