Committed by
Gerrit Code Review
ONOS-4326: Focusing on add/remove cluster member. (WIP).
If reviewing this, please refer to http://tinyurl.com/onos-ui-topo-model Change-Id: Ic6568074ac768ec828f9103e92caab5e9a06ade6
Showing
18 changed files
with
823 additions
and
27 deletions
1 | +/* | ||
2 | + * Copyright 2016-present Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.onosproject.ui.model; | ||
18 | + | ||
19 | +import org.onosproject.cluster.ClusterService; | ||
20 | +import org.onosproject.mastership.MastershipService; | ||
21 | +import org.onosproject.net.device.DeviceService; | ||
22 | +import org.onosproject.net.flow.FlowRuleService; | ||
23 | +import org.onosproject.net.host.HostService; | ||
24 | +import org.onosproject.net.intent.IntentService; | ||
25 | +import org.onosproject.net.link.LinkService; | ||
26 | +import org.onosproject.net.region.RegionService; | ||
27 | + | ||
28 | +/** | ||
29 | + * A bundle of services to pass to elements that might need a reference to them. | ||
30 | + */ | ||
31 | +public interface ServiceBundle { | ||
32 | + /** | ||
33 | + * Reference to a cluster service implementation. | ||
34 | + * | ||
35 | + * @return cluster service | ||
36 | + */ | ||
37 | + ClusterService cluster(); | ||
38 | + | ||
39 | + /** | ||
40 | + * Reference to a mastership service implementation. | ||
41 | + * | ||
42 | + * @return mastership service | ||
43 | + */ | ||
44 | + MastershipService mastership(); | ||
45 | + | ||
46 | + /** | ||
47 | + * Reference to a region service implementation. | ||
48 | + * | ||
49 | + * @return region service | ||
50 | + */ | ||
51 | + RegionService region(); | ||
52 | + | ||
53 | + /** | ||
54 | + * Reference to a device service implementation. | ||
55 | + * | ||
56 | + * @return device service | ||
57 | + */ | ||
58 | + DeviceService device(); | ||
59 | + | ||
60 | + /** | ||
61 | + * Reference to a link service implementation. | ||
62 | + * | ||
63 | + * @return link service | ||
64 | + */ | ||
65 | + LinkService link(); | ||
66 | + | ||
67 | + /** | ||
68 | + * Reference to a host service implementation. | ||
69 | + * | ||
70 | + * @return host service | ||
71 | + */ | ||
72 | + HostService host(); | ||
73 | + | ||
74 | + /** | ||
75 | + * Reference to a intent service implementation. | ||
76 | + * | ||
77 | + * @return intent service | ||
78 | + */ | ||
79 | + IntentService intent(); | ||
80 | + | ||
81 | + /** | ||
82 | + * Reference to a flow service implementation. | ||
83 | + * | ||
84 | + * @return flow service | ||
85 | + */ | ||
86 | + FlowRuleService flow(); | ||
87 | +} |
... | @@ -28,12 +28,14 @@ import java.util.Map; | ... | @@ -28,12 +28,14 @@ import java.util.Map; |
28 | */ | 28 | */ |
29 | class UiCluster extends UiElement { | 29 | class UiCluster extends UiElement { |
30 | 30 | ||
31 | + private static final String DEFAULT_CLUSTER_ID = "CLUSTER-0"; | ||
32 | + | ||
31 | private final List<UiClusterMember> members = new ArrayList<>(); | 33 | private final List<UiClusterMember> members = new ArrayList<>(); |
32 | private final Map<NodeId, UiClusterMember> lookup = new HashMap<>(); | 34 | private final Map<NodeId, UiClusterMember> lookup = new HashMap<>(); |
33 | 35 | ||
34 | @Override | 36 | @Override |
35 | public String toString() { | 37 | public String toString() { |
36 | - return String.valueOf(members.size()) + "-member cluster"; | 38 | + return String.valueOf(size()) + "-member cluster"; |
37 | } | 39 | } |
38 | 40 | ||
39 | /** | 41 | /** |
... | @@ -65,6 +67,16 @@ class UiCluster extends UiElement { | ... | @@ -65,6 +67,16 @@ class UiCluster extends UiElement { |
65 | } | 67 | } |
66 | 68 | ||
67 | /** | 69 | /** |
70 | + * Removes the given member from the cluster. | ||
71 | + * | ||
72 | + * @param member member to remove | ||
73 | + */ | ||
74 | + public void remove(UiClusterMember member) { | ||
75 | + members.remove(member); | ||
76 | + lookup.remove(member.id()); | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
68 | * Returns the number of members in the cluster. | 80 | * Returns the number of members in the cluster. |
69 | * | 81 | * |
70 | * @return number of members | 82 | * @return number of members |
... | @@ -72,4 +84,9 @@ class UiCluster extends UiElement { | ... | @@ -72,4 +84,9 @@ class UiCluster extends UiElement { |
72 | public int size() { | 84 | public int size() { |
73 | return members.size(); | 85 | return members.size(); |
74 | } | 86 | } |
87 | + | ||
88 | + @Override | ||
89 | + public String idAsString() { | ||
90 | + return DEFAULT_CLUSTER_ID; | ||
91 | + } | ||
75 | } | 92 | } | ... | ... |
... | @@ -16,9 +16,12 @@ | ... | @@ -16,9 +16,12 @@ |
16 | 16 | ||
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | +import org.onlab.packet.IpAddress; | ||
19 | import org.onosproject.cluster.ControllerNode; | 20 | import org.onosproject.cluster.ControllerNode; |
20 | import org.onosproject.cluster.NodeId; | 21 | import org.onosproject.cluster.NodeId; |
21 | 22 | ||
23 | +import static org.onosproject.cluster.ControllerNode.State.INACTIVE; | ||
24 | + | ||
22 | /** | 25 | /** |
23 | * Represents an individual member of the cluster (ONOS instance). | 26 | * Represents an individual member of the cluster (ONOS instance). |
24 | */ | 27 | */ |
... | @@ -26,6 +29,9 @@ public class UiClusterMember extends UiElement { | ... | @@ -26,6 +29,9 @@ public class UiClusterMember extends UiElement { |
26 | 29 | ||
27 | private final ControllerNode cnode; | 30 | private final ControllerNode cnode; |
28 | 31 | ||
32 | + private int deviceCount = 0; | ||
33 | + private ControllerNode.State state = INACTIVE; | ||
34 | + | ||
29 | /** | 35 | /** |
30 | * Constructs a cluster member, with a reference to the specified | 36 | * Constructs a cluster member, with a reference to the specified |
31 | * controller node instance. | 37 | * controller node instance. |
... | @@ -36,13 +42,33 @@ public class UiClusterMember extends UiElement { | ... | @@ -36,13 +42,33 @@ public class UiClusterMember extends UiElement { |
36 | this.cnode = cnode; | 42 | this.cnode = cnode; |
37 | } | 43 | } |
38 | 44 | ||
45 | + @Override | ||
46 | + public String toString() { | ||
47 | + return "UiClusterMember{" + cnode + | ||
48 | + ", online=" + isOnline() + | ||
49 | + ", ready=" + isReady() + | ||
50 | + ", #devices=" + deviceCount + | ||
51 | + "}"; | ||
52 | + } | ||
53 | + | ||
54 | + | ||
39 | /** | 55 | /** |
40 | - * Updates the information about this cluster member. | 56 | + * Sets the state of this cluster member. |
41 | * | 57 | * |
42 | - * @param cnode underlying controller node | 58 | + * @param state the state |
43 | */ | 59 | */ |
44 | - public void update(ControllerNode cnode) { | 60 | + public void setState(ControllerNode.State state) { |
45 | - // TODO: update our information cache appropriately | 61 | + this.state = state; |
62 | + } | ||
63 | + | ||
64 | + | ||
65 | + /** | ||
66 | + * Sets the number of devices for which this cluster member is master. | ||
67 | + * | ||
68 | + * @param deviceCount number of devices | ||
69 | + */ | ||
70 | + public void setDeviceCount(int deviceCount) { | ||
71 | + this.deviceCount = deviceCount; | ||
46 | } | 72 | } |
47 | 73 | ||
48 | /** | 74 | /** |
... | @@ -53,4 +79,45 @@ public class UiClusterMember extends UiElement { | ... | @@ -53,4 +79,45 @@ public class UiClusterMember extends UiElement { |
53 | public NodeId id() { | 79 | public NodeId id() { |
54 | return cnode.id(); | 80 | return cnode.id(); |
55 | } | 81 | } |
82 | + | ||
83 | + /** | ||
84 | + * Returns the IP address of the cluster member. | ||
85 | + * | ||
86 | + * @return the IP address | ||
87 | + */ | ||
88 | + public IpAddress ip() { | ||
89 | + return cnode.ip(); | ||
90 | + } | ||
91 | + | ||
92 | + /** | ||
93 | + * Returns true if this cluster member is online (active). | ||
94 | + * | ||
95 | + * @return true if online, false otherwise | ||
96 | + */ | ||
97 | + public boolean isOnline() { | ||
98 | + return state.isActive(); | ||
99 | + } | ||
100 | + | ||
101 | + /** | ||
102 | + * Returns true if this cluster member is considered ready. | ||
103 | + * | ||
104 | + * @return true if ready, false otherwise | ||
105 | + */ | ||
106 | + public boolean isReady() { | ||
107 | + return state.isReady(); | ||
108 | + } | ||
109 | + | ||
110 | + /** | ||
111 | + * Returns the number of devices for which this cluster member is master. | ||
112 | + * | ||
113 | + * @return number of devices for which this member is master | ||
114 | + */ | ||
115 | + public int deviceCount() { | ||
116 | + return deviceCount; | ||
117 | + } | ||
118 | + | ||
119 | + @Override | ||
120 | + public String idAsString() { | ||
121 | + return id().toString(); | ||
122 | + } | ||
56 | } | 123 | } | ... | ... |
... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | import org.onosproject.net.Device; | 19 | import org.onosproject.net.Device; |
20 | +import org.onosproject.net.DeviceId; | ||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * Represents a device. | 23 | * Represents a device. |
... | @@ -29,4 +30,18 @@ public class UiDevice extends UiNode { | ... | @@ -29,4 +30,18 @@ public class UiDevice extends UiNode { |
29 | protected void destroy() { | 30 | protected void destroy() { |
30 | device = null; | 31 | device = null; |
31 | } | 32 | } |
33 | + | ||
34 | + /** | ||
35 | + * Returns the identity of the device. | ||
36 | + * | ||
37 | + * @return device ID | ||
38 | + */ | ||
39 | + public DeviceId id() { | ||
40 | + return device.id(); | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public String idAsString() { | ||
45 | + return id().toString(); | ||
46 | + } | ||
32 | } | 47 | } | ... | ... |
... | @@ -19,7 +19,7 @@ package org.onosproject.ui.model.topo; | ... | @@ -19,7 +19,7 @@ package org.onosproject.ui.model.topo; |
19 | /** | 19 | /** |
20 | * Abstract base class of all elements in the UI topology model. | 20 | * Abstract base class of all elements in the UI topology model. |
21 | */ | 21 | */ |
22 | -public class UiElement { | 22 | +public abstract class UiElement { |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * Removes all external references, and prepares the instance for | 25 | * Removes all external references, and prepares the instance for |
... | @@ -28,4 +28,11 @@ public class UiElement { | ... | @@ -28,4 +28,11 @@ public class UiElement { |
28 | protected void destroy() { | 28 | protected void destroy() { |
29 | // does nothing | 29 | // does nothing |
30 | } | 30 | } |
31 | + | ||
32 | + /** | ||
33 | + * Returns a string representation of the element identifier. | ||
34 | + * | ||
35 | + * @return the element unique identifier | ||
36 | + */ | ||
37 | + public abstract String idAsString(); | ||
31 | } | 38 | } | ... | ... |
... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | import org.onosproject.net.Host; | 19 | import org.onosproject.net.Host; |
20 | +import org.onosproject.net.HostId; | ||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * Represents an end-station host. | 23 | * Represents an end-station host. |
... | @@ -29,4 +30,18 @@ public class UiHost extends UiNode { | ... | @@ -29,4 +30,18 @@ public class UiHost extends UiNode { |
29 | protected void destroy() { | 30 | protected void destroy() { |
30 | host = null; | 31 | host = null; |
31 | } | 32 | } |
33 | + | ||
34 | + /** | ||
35 | + * Returns the identity of the host. | ||
36 | + * | ||
37 | + * @return host ID | ||
38 | + */ | ||
39 | + public HostId id() { | ||
40 | + return host.id(); | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public String idAsString() { | ||
45 | + return id().toString(); | ||
46 | + } | ||
32 | } | 47 | } | ... | ... |
... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | import org.onosproject.net.region.Region; | 19 | import org.onosproject.net.region.Region; |
20 | +import org.onosproject.net.region.RegionId; | ||
20 | 21 | ||
21 | import java.util.Set; | 22 | import java.util.Set; |
22 | import java.util.TreeSet; | 23 | import java.util.TreeSet; |
... | @@ -46,4 +47,17 @@ public class UiRegion extends UiNode { | ... | @@ -46,4 +47,17 @@ public class UiRegion extends UiNode { |
46 | region = null; | 47 | region = null; |
47 | } | 48 | } |
48 | 49 | ||
50 | + /** | ||
51 | + * Returns the identity of the region. | ||
52 | + * | ||
53 | + * @return region ID | ||
54 | + */ | ||
55 | + public RegionId id() { | ||
56 | + return region.id(); | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
60 | + public String idAsString() { | ||
61 | + return id().toString(); | ||
62 | + } | ||
49 | } | 63 | } | ... | ... |
... | @@ -28,6 +28,8 @@ import java.util.TreeSet; | ... | @@ -28,6 +28,8 @@ import java.util.TreeSet; |
28 | */ | 28 | */ |
29 | public class UiTopology extends UiElement { | 29 | public class UiTopology extends UiElement { |
30 | 30 | ||
31 | + private static final String DEFAULT_TOPOLOGY_ID = "TOPOLOGY-0"; | ||
32 | + | ||
31 | private static final Logger log = LoggerFactory.getLogger(UiTopology.class); | 33 | private static final Logger log = LoggerFactory.getLogger(UiTopology.class); |
32 | 34 | ||
33 | private final UiCluster uiCluster = new UiCluster(); | 35 | private final UiCluster uiCluster = new UiCluster(); |
... | @@ -69,6 +71,15 @@ public class UiTopology extends UiElement { | ... | @@ -69,6 +71,15 @@ public class UiTopology extends UiElement { |
69 | } | 71 | } |
70 | 72 | ||
71 | /** | 73 | /** |
74 | + * Removes the given cluster member from the topology model. | ||
75 | + * | ||
76 | + * @param member cluster member to remove | ||
77 | + */ | ||
78 | + public void remove(UiClusterMember member) { | ||
79 | + uiCluster.remove(member); | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
72 | * Returns the number of members in the cluster. | 83 | * Returns the number of members in the cluster. |
73 | * | 84 | * |
74 | * @return number of cluster members | 85 | * @return number of cluster members |
... | @@ -85,4 +96,9 @@ public class UiTopology extends UiElement { | ... | @@ -85,4 +96,9 @@ public class UiTopology extends UiElement { |
85 | public int regionCount() { | 96 | public int regionCount() { |
86 | return uiRegions.size(); | 97 | return uiRegions.size(); |
87 | } | 98 | } |
99 | + | ||
100 | + @Override | ||
101 | + public String idAsString() { | ||
102 | + return DEFAULT_TOPOLOGY_ID; | ||
103 | + } | ||
88 | } | 104 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016-present Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.onosproject.ui; | ||
18 | + | ||
19 | +/** | ||
20 | + * Abstract base class for UI tests. | ||
21 | + */ | ||
22 | +public abstract class AbstractUiTest { | ||
23 | + | ||
24 | + /** | ||
25 | + * System agnostic end-of-line character. | ||
26 | + */ | ||
27 | + protected static final String EOL = String.format("%n"); | ||
28 | + | ||
29 | + /** | ||
30 | + * Prints the given string to stdout. | ||
31 | + * | ||
32 | + * @param s string to print | ||
33 | + */ | ||
34 | + protected static void print(String s) { | ||
35 | + System.out.println(s); | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * Prints the toString() of the given object to stdout. | ||
40 | + * | ||
41 | + * @param o object to print | ||
42 | + */ | ||
43 | + protected static void print(Object o) { | ||
44 | + if (o == null) { | ||
45 | + print("<null>"); | ||
46 | + } else { | ||
47 | + print(o.toString()); | ||
48 | + } | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * Prints the formatted string to stdout. | ||
53 | + * | ||
54 | + * @param fmt format string | ||
55 | + * @param params parameters | ||
56 | + * @see String#format(String, Object...) | ||
57 | + */ | ||
58 | + protected static void print(String fmt, Object... params) { | ||
59 | + print(String.format(fmt, params)); | ||
60 | + } | ||
61 | + | ||
62 | + /** | ||
63 | + * Prints a title, to delimit individual unit test output. | ||
64 | + * | ||
65 | + * @param s a title for the test | ||
66 | + */ | ||
67 | + protected static void title(String s) { | ||
68 | + print(EOL + "=== %s ===", s); | ||
69 | + } | ||
70 | +} |
1 | +/* | ||
2 | + * Copyright 2016-present Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.onosproject.ui.model; | ||
18 | + | ||
19 | +import org.onosproject.cluster.ClusterService; | ||
20 | +import org.onosproject.cluster.ClusterServiceAdapter; | ||
21 | +import org.onosproject.cluster.ControllerNode; | ||
22 | +import org.onosproject.cluster.NodeId; | ||
23 | +import org.onosproject.mastership.MastershipService; | ||
24 | +import org.onosproject.net.device.DeviceService; | ||
25 | +import org.onosproject.net.flow.FlowRuleService; | ||
26 | +import org.onosproject.net.host.HostService; | ||
27 | +import org.onosproject.net.intent.IntentService; | ||
28 | +import org.onosproject.net.link.LinkService; | ||
29 | +import org.onosproject.net.region.RegionService; | ||
30 | +import org.onosproject.ui.AbstractUiTest; | ||
31 | + | ||
32 | +/** | ||
33 | + * Base class for UI model unit tests. | ||
34 | + */ | ||
35 | +public class AbstractUiModelTest extends AbstractUiTest { | ||
36 | + | ||
37 | + /** | ||
38 | + * Returns canned results. | ||
39 | + * At some future point, we may make this "programmable", so that | ||
40 | + * it returns certain values based on element IDs etc. | ||
41 | + */ | ||
42 | + protected static final ServiceBundle MOCK_SERVICES = | ||
43 | + new ServiceBundle() { | ||
44 | + @Override | ||
45 | + public ClusterService cluster() { | ||
46 | + return MOCK_CLUSTER; | ||
47 | + } | ||
48 | + | ||
49 | + @Override | ||
50 | + public MastershipService mastership() { | ||
51 | + return null; | ||
52 | + } | ||
53 | + | ||
54 | + @Override | ||
55 | + public RegionService region() { | ||
56 | + return null; | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
60 | + public DeviceService device() { | ||
61 | + return null; | ||
62 | + } | ||
63 | + | ||
64 | + @Override | ||
65 | + public LinkService link() { | ||
66 | + return null; | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
70 | + public HostService host() { | ||
71 | + return null; | ||
72 | + } | ||
73 | + | ||
74 | + @Override | ||
75 | + public IntentService intent() { | ||
76 | + return null; | ||
77 | + } | ||
78 | + | ||
79 | + @Override | ||
80 | + public FlowRuleService flow() { | ||
81 | + return null; | ||
82 | + } | ||
83 | + }; | ||
84 | + | ||
85 | + private static final ClusterService MOCK_CLUSTER = new MockClusterService(); | ||
86 | + | ||
87 | + | ||
88 | + private static class MockClusterService extends ClusterServiceAdapter { | ||
89 | + @Override | ||
90 | + public ControllerNode.State getState(NodeId nodeId) { | ||
91 | + // For now, a hardcoded state of ACTIVE (but not READY) | ||
92 | + // irrespective of the node ID. | ||
93 | + return ControllerNode.State.ACTIVE; | ||
94 | + } | ||
95 | + } | ||
96 | + | ||
97 | +} |
1 | +/* | ||
2 | + * Copyright 2016-present Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.onosproject.ui.model.topo; | ||
18 | + | ||
19 | +import org.junit.Test; | ||
20 | +import org.onlab.packet.IpAddress; | ||
21 | +import org.onosproject.cluster.ControllerNode; | ||
22 | +import org.onosproject.cluster.DefaultControllerNode; | ||
23 | +import org.onosproject.cluster.NodeId; | ||
24 | +import org.onosproject.ui.model.AbstractUiModelTest; | ||
25 | + | ||
26 | +import static org.junit.Assert.assertEquals; | ||
27 | + | ||
28 | +/** | ||
29 | + * Unit tests for {@link UiClusterMember}. | ||
30 | + */ | ||
31 | +public class UiClusterMemberTest extends AbstractUiModelTest { | ||
32 | + | ||
33 | + private static final NodeId NODE_ID = NodeId.nodeId("Node-1"); | ||
34 | + private static final IpAddress NODE_IP = IpAddress.valueOf("1.2.3.4"); | ||
35 | + | ||
36 | + private static final ControllerNode CNODE_1 = | ||
37 | + new DefaultControllerNode(NODE_ID, NODE_IP); | ||
38 | + | ||
39 | + private UiClusterMember member; | ||
40 | + | ||
41 | + @Test | ||
42 | + public void basic() { | ||
43 | + title("basic"); | ||
44 | + member = new UiClusterMember(CNODE_1); | ||
45 | + print(member); | ||
46 | + | ||
47 | + assertEquals("wrong id", NODE_ID, member.id()); | ||
48 | + assertEquals("wrong IP", NODE_IP, member.ip()); | ||
49 | + assertEquals("unex. online", false, member.isOnline()); | ||
50 | + assertEquals("unex. ready", false, member.isReady()); | ||
51 | + assertEquals("unex. device count", 0, member.deviceCount()); | ||
52 | + } | ||
53 | +} |
... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
17 | package org.onosproject.ui.impl.topo.model; | 17 | package org.onosproject.ui.impl.topo.model; |
18 | 18 | ||
19 | import org.onosproject.cluster.ControllerNode; | 19 | import org.onosproject.cluster.ControllerNode; |
20 | +import org.onosproject.cluster.NodeId; | ||
20 | import org.onosproject.cluster.RoleInfo; | 21 | import org.onosproject.cluster.RoleInfo; |
21 | import org.onosproject.event.EventDispatcher; | 22 | import org.onosproject.event.EventDispatcher; |
22 | import org.onosproject.net.Device; | 23 | import org.onosproject.net.Device; |
... | @@ -24,11 +25,16 @@ import org.onosproject.net.DeviceId; | ... | @@ -24,11 +25,16 @@ import org.onosproject.net.DeviceId; |
24 | import org.onosproject.net.Host; | 25 | import org.onosproject.net.Host; |
25 | import org.onosproject.net.Link; | 26 | import org.onosproject.net.Link; |
26 | import org.onosproject.net.region.Region; | 27 | import org.onosproject.net.region.Region; |
28 | +import org.onosproject.ui.model.ServiceBundle; | ||
27 | import org.onosproject.ui.model.topo.UiClusterMember; | 29 | import org.onosproject.ui.model.topo.UiClusterMember; |
28 | import org.onosproject.ui.model.topo.UiDevice; | 30 | import org.onosproject.ui.model.topo.UiDevice; |
29 | import org.onosproject.ui.model.topo.UiTopology; | 31 | import org.onosproject.ui.model.topo.UiTopology; |
32 | +import org.slf4j.Logger; | ||
33 | +import org.slf4j.LoggerFactory; | ||
30 | 34 | ||
31 | -import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_ADDED; | 35 | +import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.CLUSTER_MEMBER_ADDED_OR_UPDATED; |
36 | +import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.CLUSTER_MEMBER_REMOVED; | ||
37 | +import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_ADDED_OR_UPDATED; | ||
32 | import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_REMOVED; | 38 | import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_REMOVED; |
33 | 39 | ||
34 | /** | 40 | /** |
... | @@ -36,10 +42,14 @@ import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_REMOVE | ... | @@ -36,10 +42,14 @@ import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_REMOVE |
36 | */ | 42 | */ |
37 | class ModelCache { | 43 | class ModelCache { |
38 | 44 | ||
45 | + private static final Logger log = LoggerFactory.getLogger(ModelCache.class); | ||
46 | + | ||
47 | + private final ServiceBundle services; | ||
39 | private final EventDispatcher dispatcher; | 48 | private final EventDispatcher dispatcher; |
40 | private final UiTopology uiTopology = new UiTopology(); | 49 | private final UiTopology uiTopology = new UiTopology(); |
41 | 50 | ||
42 | - ModelCache(EventDispatcher eventDispatcher) { | 51 | + ModelCache(ServiceBundle services, EventDispatcher eventDispatcher) { |
52 | + this.services = services; | ||
43 | this.dispatcher = eventDispatcher; | 53 | this.dispatcher = eventDispatcher; |
44 | } | 54 | } |
45 | 55 | ||
... | @@ -59,6 +69,7 @@ class ModelCache { | ... | @@ -59,6 +69,7 @@ class ModelCache { |
59 | * Create our internal model of the global topology. | 69 | * Create our internal model of the global topology. |
60 | */ | 70 | */ |
61 | void load() { | 71 | void load() { |
72 | + // TODO - implement loading of initial state | ||
62 | // loadClusterMembers(); | 73 | // loadClusterMembers(); |
63 | // loadRegions(); | 74 | // loadRegions(); |
64 | // loadDevices(); | 75 | // loadDevices(); |
... | @@ -74,20 +85,36 @@ class ModelCache { | ... | @@ -74,20 +85,36 @@ class ModelCache { |
74 | * @param cnode controller node to be added/updated | 85 | * @param cnode controller node to be added/updated |
75 | */ | 86 | */ |
76 | void addOrUpdateClusterMember(ControllerNode cnode) { | 87 | void addOrUpdateClusterMember(ControllerNode cnode) { |
77 | - UiClusterMember member = uiTopology.findClusterMember(cnode.id()); | 88 | + NodeId id = cnode.id(); |
78 | - if (member != null) { | 89 | + UiClusterMember member = uiTopology.findClusterMember(id); |
79 | - member.update(cnode); | 90 | + if (member == null) { |
80 | - } else { | ||
81 | member = new UiClusterMember(cnode); | 91 | member = new UiClusterMember(cnode); |
82 | uiTopology.add(member); | 92 | uiTopology.add(member); |
83 | } | 93 | } |
84 | 94 | ||
85 | - // TODO: post event | 95 | + // inject computed data about the cluster node, into the model object |
96 | + ControllerNode.State state = services.cluster().getState(id); | ||
97 | + member.setState(state); | ||
98 | + member.setDeviceCount(services.mastership().getDevicesOf(id).size()); | ||
99 | + // NOTE: UI-attached is session-based data, not global | ||
100 | + | ||
101 | + dispatcher.post(new UiModelEvent(CLUSTER_MEMBER_ADDED_OR_UPDATED, member)); | ||
86 | } | 102 | } |
87 | 103 | ||
104 | + /** | ||
105 | + * Removes from the model the specified controller node. | ||
106 | + * | ||
107 | + * @param cnode controller node to be removed | ||
108 | + */ | ||
88 | void removeClusterMember(ControllerNode cnode) { | 109 | void removeClusterMember(ControllerNode cnode) { |
89 | - // TODO: find cluster member assoc. with parameter; remove from model | 110 | + NodeId id = cnode.id(); |
90 | - // TODO: post event | 111 | + UiClusterMember member = uiTopology.findClusterMember(id); |
112 | + if (member != null) { | ||
113 | + uiTopology.remove(member); | ||
114 | + dispatcher.post(new UiModelEvent(CLUSTER_MEMBER_REMOVED, member)); | ||
115 | + } else { | ||
116 | + log.warn("Tried to remove non-member cluster node {}", id); | ||
117 | + } | ||
91 | } | 118 | } |
92 | 119 | ||
93 | void updateMasterships(DeviceId deviceId, RoleInfo roleInfo) { | 120 | void updateMasterships(DeviceId deviceId, RoleInfo roleInfo) { |
... | @@ -111,7 +138,7 @@ class ModelCache { | ... | @@ -111,7 +138,7 @@ class ModelCache { |
111 | UiDevice uiDevice = new UiDevice(); | 138 | UiDevice uiDevice = new UiDevice(); |
112 | 139 | ||
113 | // TODO: post the (correct) event | 140 | // TODO: post the (correct) event |
114 | - dispatcher.post(new UiModelEvent(DEVICE_ADDED, uiDevice)); | 141 | + dispatcher.post(new UiModelEvent(DEVICE_ADDED_OR_UPDATED, uiDevice)); |
115 | } | 142 | } |
116 | 143 | ||
117 | void removeDevice(Device device) { | 144 | void removeDevice(Device device) { | ... | ... |
... | @@ -29,8 +29,12 @@ public class UiModelEvent extends AbstractEvent<UiModelEvent.Type, UiElement> { | ... | @@ -29,8 +29,12 @@ public class UiModelEvent extends AbstractEvent<UiModelEvent.Type, UiElement> { |
29 | } | 29 | } |
30 | 30 | ||
31 | enum Type { | 31 | enum Type { |
32 | - DEVICE_ADDED, | 32 | + CLUSTER_MEMBER_ADDED_OR_UPDATED, |
33 | + CLUSTER_MEMBER_REMOVED, | ||
34 | + | ||
35 | + DEVICE_ADDED_OR_UPDATED, | ||
33 | DEVICE_REMOVED, | 36 | DEVICE_REMOVED, |
37 | + | ||
34 | // TODO... | 38 | // TODO... |
35 | } | 39 | } |
36 | } | 40 | } | ... | ... |
... | @@ -59,6 +59,7 @@ import org.onosproject.net.region.RegionService; | ... | @@ -59,6 +59,7 @@ import org.onosproject.net.region.RegionService; |
59 | import org.onosproject.net.statistic.StatisticService; | 59 | import org.onosproject.net.statistic.StatisticService; |
60 | import org.onosproject.net.topology.TopologyService; | 60 | import org.onosproject.net.topology.TopologyService; |
61 | import org.onosproject.ui.impl.topo.UiTopoSession; | 61 | import org.onosproject.ui.impl.topo.UiTopoSession; |
62 | +import org.onosproject.ui.model.ServiceBundle; | ||
62 | import org.slf4j.Logger; | 63 | import org.slf4j.Logger; |
63 | import org.slf4j.LoggerFactory; | 64 | import org.slf4j.LoggerFactory; |
64 | 65 | ||
... | @@ -122,7 +123,7 @@ public final class UiSharedTopologyModel | ... | @@ -122,7 +123,7 @@ public final class UiSharedTopologyModel |
122 | 123 | ||
123 | @Activate | 124 | @Activate |
124 | protected void activate() { | 125 | protected void activate() { |
125 | - cache = new ModelCache(eventDispatcher); | 126 | + cache = new ModelCache(new DefaultServiceBundle(), eventDispatcher); |
126 | 127 | ||
127 | eventDispatcher.addSink(UiModelEvent.class, listenerRegistry); | 128 | eventDispatcher.addSink(UiModelEvent.class, listenerRegistry); |
128 | 129 | ||
... | @@ -180,6 +181,52 @@ public final class UiSharedTopologyModel | ... | @@ -180,6 +181,52 @@ public final class UiSharedTopologyModel |
180 | removeListener(session); | 181 | removeListener(session); |
181 | } | 182 | } |
182 | 183 | ||
184 | + /** | ||
185 | + * Default implementation of service bundle to return references to our | ||
186 | + * dynamically injected services. | ||
187 | + */ | ||
188 | + private class DefaultServiceBundle implements ServiceBundle { | ||
189 | + @Override | ||
190 | + public ClusterService cluster() { | ||
191 | + return clusterService; | ||
192 | + } | ||
193 | + | ||
194 | + @Override | ||
195 | + public MastershipService mastership() { | ||
196 | + return mastershipService; | ||
197 | + } | ||
198 | + | ||
199 | + @Override | ||
200 | + public RegionService region() { | ||
201 | + return regionService; | ||
202 | + } | ||
203 | + | ||
204 | + @Override | ||
205 | + public DeviceService device() { | ||
206 | + return deviceService; | ||
207 | + } | ||
208 | + | ||
209 | + @Override | ||
210 | + public LinkService link() { | ||
211 | + return linkService; | ||
212 | + } | ||
213 | + | ||
214 | + @Override | ||
215 | + public HostService host() { | ||
216 | + return hostService; | ||
217 | + } | ||
218 | + | ||
219 | + @Override | ||
220 | + public IntentService intent() { | ||
221 | + return intentService; | ||
222 | + } | ||
223 | + | ||
224 | + @Override | ||
225 | + public FlowRuleService flow() { | ||
226 | + return flowService; | ||
227 | + } | ||
228 | + } | ||
229 | + | ||
183 | 230 | ||
184 | private class InternalClusterListener implements ClusterEventListener { | 231 | private class InternalClusterListener implements ClusterEventListener { |
185 | @Override | 232 | @Override | ... | ... |
... | @@ -14,12 +14,12 @@ | ... | @@ -14,12 +14,12 @@ |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | -package org.onosproject.ui.impl.topo.model; | 17 | +package org.onosproject.ui.impl; |
18 | 18 | ||
19 | /** | 19 | /** |
20 | - * Base class for model test classes. | 20 | + * Base class for unit tests. |
21 | */ | 21 | */ |
22 | -public abstract class AbstractModelTest { | 22 | +public class AbstractUiImplTest { |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * System agnostic end-of-line character. | 25 | * System agnostic end-of-line character. |
... | @@ -41,7 +41,11 @@ public abstract class AbstractModelTest { | ... | @@ -41,7 +41,11 @@ public abstract class AbstractModelTest { |
41 | * @param o object to print | 41 | * @param o object to print |
42 | */ | 42 | */ |
43 | protected void print(Object o) { | 43 | protected void print(Object o) { |
44 | - print(o.toString()); | 44 | + if (o == null) { |
45 | + print("<null>"); | ||
46 | + } else { | ||
47 | + print(o.toString()); | ||
48 | + } | ||
45 | } | 49 | } |
46 | 50 | ||
47 | /** | 51 | /** |
... | @@ -55,4 +59,12 @@ public abstract class AbstractModelTest { | ... | @@ -55,4 +59,12 @@ public abstract class AbstractModelTest { |
55 | print(String.format(fmt, params)); | 59 | print(String.format(fmt, params)); |
56 | } | 60 | } |
57 | 61 | ||
62 | + /** | ||
63 | + * Prints a title, to delimit individual unit test output. | ||
64 | + * | ||
65 | + * @param s a title for the test | ||
66 | + */ | ||
67 | + protected void title(String s) { | ||
68 | + print(EOL + "=== %s ===", s); | ||
69 | + } | ||
58 | } | 70 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016-present Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.onosproject.ui.impl.topo.model; | ||
18 | + | ||
19 | +import com.google.common.collect.ImmutableSet; | ||
20 | +import org.onosproject.cluster.ClusterService; | ||
21 | +import org.onosproject.cluster.ClusterServiceAdapter; | ||
22 | +import org.onosproject.cluster.ControllerNode; | ||
23 | +import org.onosproject.cluster.NodeId; | ||
24 | +import org.onosproject.mastership.MastershipService; | ||
25 | +import org.onosproject.mastership.MastershipServiceAdapter; | ||
26 | +import org.onosproject.net.DeviceId; | ||
27 | +import org.onosproject.net.device.DeviceService; | ||
28 | +import org.onosproject.net.flow.FlowRuleService; | ||
29 | +import org.onosproject.net.host.HostService; | ||
30 | +import org.onosproject.net.intent.IntentService; | ||
31 | +import org.onosproject.net.link.LinkService; | ||
32 | +import org.onosproject.net.region.RegionService; | ||
33 | +import org.onosproject.ui.impl.AbstractUiImplTest; | ||
34 | +import org.onosproject.ui.model.ServiceBundle; | ||
35 | + | ||
36 | +import java.util.HashMap; | ||
37 | +import java.util.Map; | ||
38 | +import java.util.Set; | ||
39 | + | ||
40 | +import static org.onosproject.net.DeviceId.deviceId; | ||
41 | + | ||
42 | +/** | ||
43 | + * Base class for model test classes. | ||
44 | + */ | ||
45 | +abstract class AbstractTopoModelTest extends AbstractUiImplTest { | ||
46 | + | ||
47 | + /** | ||
48 | + * Returns canned results. | ||
49 | + * At some future point, we may make this "programmable", so that | ||
50 | + * it returns certain values based on element IDs etc. | ||
51 | + */ | ||
52 | + protected static final ServiceBundle MOCK_SERVICES = | ||
53 | + new ServiceBundle() { | ||
54 | + @Override | ||
55 | + public ClusterService cluster() { | ||
56 | + return MOCK_CLUSTER; | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
60 | + public MastershipService mastership() { | ||
61 | + return MOCK_MASTER; | ||
62 | + } | ||
63 | + | ||
64 | + @Override | ||
65 | + public RegionService region() { | ||
66 | + return null; | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
70 | + public DeviceService device() { | ||
71 | + return null; | ||
72 | + } | ||
73 | + | ||
74 | + @Override | ||
75 | + public LinkService link() { | ||
76 | + return null; | ||
77 | + } | ||
78 | + | ||
79 | + @Override | ||
80 | + public HostService host() { | ||
81 | + return null; | ||
82 | + } | ||
83 | + | ||
84 | + @Override | ||
85 | + public IntentService intent() { | ||
86 | + return null; | ||
87 | + } | ||
88 | + | ||
89 | + @Override | ||
90 | + public FlowRuleService flow() { | ||
91 | + return null; | ||
92 | + } | ||
93 | + }; | ||
94 | + | ||
95 | + private static final ClusterService MOCK_CLUSTER = new MockClusterService(); | ||
96 | + private static final MastershipService MOCK_MASTER = new MockMasterService(); | ||
97 | + // TODO: fill out as necessary | ||
98 | + | ||
99 | + /* | ||
100 | + Our mock environment: | ||
101 | + | ||
102 | + Three controllers: C1, C2, C3 | ||
103 | + | ||
104 | + Nine devices: D1 .. D9 | ||
105 | + | ||
106 | + D4 ---+ +--- D7 | ||
107 | + | | | ||
108 | + D5 --- D1 --- D2 --- D3 --- D8 | ||
109 | + | | | ||
110 | + D6 ---+ +--- D9 | ||
111 | + | ||
112 | + Twelve hosts (two per D4 ... D9) H41, H42, H51, H52, ... | ||
113 | + | ||
114 | + Regions: | ||
115 | + R1 : D1, D2, D3 | ||
116 | + R2 : D4, D5, D6 | ||
117 | + R3 : D7, D8, D9 | ||
118 | + | ||
119 | + Mastership: | ||
120 | + C1 : D1, D2, D3 | ||
121 | + C2 : D4, D5, D6 | ||
122 | + C3 : D7, D8, D9 | ||
123 | + */ | ||
124 | + | ||
125 | + | ||
126 | + private static class MockClusterService extends ClusterServiceAdapter { | ||
127 | + private final Map<NodeId, ControllerNode.State> states = new HashMap<>(); | ||
128 | + | ||
129 | + | ||
130 | + @Override | ||
131 | + public ControllerNode.State getState(NodeId nodeId) { | ||
132 | + // For now, a hardcoded state of ACTIVE (but not READY) | ||
133 | + // irrespective of the node ID. | ||
134 | + return ControllerNode.State.ACTIVE; | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + protected static final DeviceId D1_ID = deviceId("D1"); | ||
139 | + protected static final DeviceId D2_ID = deviceId("D2"); | ||
140 | + protected static final DeviceId D3_ID = deviceId("D3"); | ||
141 | + protected static final DeviceId D4_ID = deviceId("D4"); | ||
142 | + protected static final DeviceId D5_ID = deviceId("D5"); | ||
143 | + protected static final DeviceId D6_ID = deviceId("D6"); | ||
144 | + protected static final DeviceId D7_ID = deviceId("D7"); | ||
145 | + protected static final DeviceId D8_ID = deviceId("D8"); | ||
146 | + protected static final DeviceId D9_ID = deviceId("D9"); | ||
147 | + | ||
148 | + private static class MockMasterService extends MastershipServiceAdapter { | ||
149 | + @Override | ||
150 | + public Set<DeviceId> getDevicesOf(NodeId nodeId) { | ||
151 | + // For now, a hard coded set of two device IDs | ||
152 | + // irrespective of the node ID. | ||
153 | + return ImmutableSet.of(D1_ID, D2_ID); | ||
154 | + } | ||
155 | + } | ||
156 | + | ||
157 | +} |
... | @@ -16,28 +16,113 @@ | ... | @@ -16,28 +16,113 @@ |
16 | 16 | ||
17 | package org.onosproject.ui.impl.topo.model; | 17 | package org.onosproject.ui.impl.topo.model; |
18 | 18 | ||
19 | +import org.junit.Before; | ||
19 | import org.junit.Test; | 20 | import org.junit.Test; |
21 | +import org.onlab.packet.IpAddress; | ||
22 | +import org.onosproject.cluster.ControllerNode; | ||
23 | +import org.onosproject.cluster.DefaultControllerNode; | ||
24 | +import org.onosproject.event.Event; | ||
20 | import org.onosproject.event.EventDispatcher; | 25 | import org.onosproject.event.EventDispatcher; |
26 | +import org.onosproject.ui.impl.topo.model.UiModelEvent.Type; | ||
27 | +import org.onosproject.ui.model.topo.UiElement; | ||
21 | 28 | ||
22 | import static org.junit.Assert.assertEquals; | 29 | import static org.junit.Assert.assertEquals; |
30 | +import static org.junit.Assert.assertNotNull; | ||
31 | +import static org.onosproject.cluster.NodeId.nodeId; | ||
23 | 32 | ||
24 | /** | 33 | /** |
25 | * Unit tests for {@link ModelCache}. | 34 | * Unit tests for {@link ModelCache}. |
26 | */ | 35 | */ |
27 | -public class ModelCacheTest extends AbstractModelTest { | 36 | +public class ModelCacheTest extends AbstractTopoModelTest { |
28 | 37 | ||
29 | - private static final EventDispatcher DISPATCHER = event -> { | 38 | + private class TestEvDisp implements EventDispatcher { |
30 | - // Do we care? | 39 | + |
31 | - }; | 40 | + private Event<Type, UiElement> lastEvent = null; |
41 | + private int eventCount = 0; | ||
42 | + | ||
43 | + @Override | ||
44 | + public void post(Event event) { | ||
45 | + lastEvent = event; | ||
46 | + eventCount++; | ||
47 | +// print("Event dispatched: %s", event); | ||
48 | + } | ||
49 | + | ||
50 | + private void assertEventCount(int exp) { | ||
51 | + assertEquals("unex event count", exp, eventCount); | ||
52 | + } | ||
53 | + | ||
54 | + private void assertLast(Type expEventType, String expId) { | ||
55 | + assertNotNull("no last event", lastEvent); | ||
56 | + assertEquals("unex event type", expEventType, lastEvent.type()); | ||
57 | + assertEquals("unex element ID", expId, lastEvent.subject().idAsString()); | ||
58 | + } | ||
59 | + } | ||
60 | + | ||
61 | + private static IpAddress ip(String s) { | ||
62 | + return IpAddress.valueOf(s); | ||
63 | + } | ||
64 | + | ||
65 | + private static ControllerNode cnode(String id, String ip) { | ||
66 | + return new DefaultControllerNode(nodeId(id), ip(ip)); | ||
67 | + } | ||
68 | + | ||
69 | + private static final String C1 = "C1"; | ||
70 | + private static final String C2 = "C2"; | ||
71 | + private static final String C3 = "C3"; | ||
72 | + | ||
73 | + private static final ControllerNode NODE_1 = cnode(C1, "10.0.0.1"); | ||
74 | + private static final ControllerNode NODE_2 = cnode(C2, "10.0.0.2"); | ||
75 | + private static final ControllerNode NODE_3 = cnode(C3, "10.0.0.3"); | ||
76 | + | ||
77 | + | ||
78 | + private final TestEvDisp dispatcher = new TestEvDisp(); | ||
32 | 79 | ||
33 | private ModelCache cache; | 80 | private ModelCache cache; |
34 | 81 | ||
82 | + @Before | ||
83 | + public void setUp() { | ||
84 | + cache = new ModelCache(MOCK_SERVICES, dispatcher); | ||
85 | + } | ||
86 | + | ||
35 | @Test | 87 | @Test |
36 | public void basic() { | 88 | public void basic() { |
37 | - cache = new ModelCache(DISPATCHER); | 89 | + title("basic"); |
38 | print(cache); | 90 | print(cache); |
39 | assertEquals("unex # members", 0, cache.clusterMemberCount()); | 91 | assertEquals("unex # members", 0, cache.clusterMemberCount()); |
40 | assertEquals("unex # regions", 0, cache.regionCount()); | 92 | assertEquals("unex # regions", 0, cache.regionCount()); |
41 | } | 93 | } |
42 | 94 | ||
95 | + @Test | ||
96 | + public void addAndRemoveClusterMember() { | ||
97 | + title("addAndRemoveClusterMember"); | ||
98 | + print(cache); | ||
99 | + assertEquals("unex # members", 0, cache.clusterMemberCount()); | ||
100 | + dispatcher.assertEventCount(0); | ||
101 | + | ||
102 | + cache.addOrUpdateClusterMember(NODE_1); | ||
103 | + print(cache); | ||
104 | + assertEquals("unex # members", 1, cache.clusterMemberCount()); | ||
105 | + dispatcher.assertEventCount(1); | ||
106 | + dispatcher.assertLast(Type.CLUSTER_MEMBER_ADDED_OR_UPDATED, C1); | ||
107 | + | ||
108 | + cache.removeClusterMember(NODE_1); | ||
109 | + print(cache); | ||
110 | + assertEquals("unex # members", 0, cache.clusterMemberCount()); | ||
111 | + dispatcher.assertEventCount(2); | ||
112 | + dispatcher.assertLast(Type.CLUSTER_MEMBER_REMOVED, C1); | ||
113 | + } | ||
114 | + | ||
115 | + @Test | ||
116 | + public void createThreeNodeCluster() { | ||
117 | + title("createThreeNodeCluster"); | ||
118 | + cache.addOrUpdateClusterMember(NODE_1); | ||
119 | + dispatcher.assertLast(Type.CLUSTER_MEMBER_ADDED_OR_UPDATED, C1); | ||
120 | + cache.addOrUpdateClusterMember(NODE_2); | ||
121 | + dispatcher.assertLast(Type.CLUSTER_MEMBER_ADDED_OR_UPDATED, C2); | ||
122 | + cache.addOrUpdateClusterMember(NODE_3); | ||
123 | + dispatcher.assertLast(Type.CLUSTER_MEMBER_ADDED_OR_UPDATED, C3); | ||
124 | + dispatcher.assertEventCount(3); | ||
125 | + print(cache); | ||
126 | + } | ||
127 | + | ||
43 | } | 128 | } | ... | ... |
-
Please register or login to post a comment