Jian Li
Committed by Gerrit Code Review

[ONOS-4438] Add codecs for mastership REST API

Add codecs for RoleInfo, MastershipTerm and MastershipRole.

Change-Id: I1135c7fc0ed591446d6268229b54fda70391fdb9
...@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Deactivate;
23 import org.apache.felix.scr.annotations.Service; 23 import org.apache.felix.scr.annotations.Service;
24 import org.onlab.packet.Ethernet; 24 import org.onlab.packet.Ethernet;
25 import org.onosproject.cluster.ControllerNode; 25 import org.onosproject.cluster.ControllerNode;
26 +import org.onosproject.cluster.RoleInfo;
26 import org.onosproject.codec.CodecService; 27 import org.onosproject.codec.CodecService;
27 import org.onosproject.codec.JsonCodec; 28 import org.onosproject.codec.JsonCodec;
28 import org.onosproject.core.Application; 29 import org.onosproject.core.Application;
...@@ -31,12 +32,14 @@ import org.onosproject.incubator.net.virtual.VirtualDevice; ...@@ -31,12 +32,14 @@ import org.onosproject.incubator.net.virtual.VirtualDevice;
31 import org.onosproject.incubator.net.virtual.VirtualLink; 32 import org.onosproject.incubator.net.virtual.VirtualLink;
32 import org.onosproject.incubator.net.virtual.VirtualNetwork; 33 import org.onosproject.incubator.net.virtual.VirtualNetwork;
33 import org.onosproject.incubator.net.virtual.VirtualPort; 34 import org.onosproject.incubator.net.virtual.VirtualPort;
35 +import org.onosproject.mastership.MastershipTerm;
34 import org.onosproject.net.Annotations; 36 import org.onosproject.net.Annotations;
35 import org.onosproject.net.ConnectPoint; 37 import org.onosproject.net.ConnectPoint;
36 import org.onosproject.net.Device; 38 import org.onosproject.net.Device;
37 import org.onosproject.net.Host; 39 import org.onosproject.net.Host;
38 import org.onosproject.net.HostLocation; 40 import org.onosproject.net.HostLocation;
39 import org.onosproject.net.Link; 41 import org.onosproject.net.Link;
42 +import org.onosproject.net.MastershipRole;
40 import org.onosproject.net.Path; 43 import org.onosproject.net.Path;
41 import org.onosproject.net.Port; 44 import org.onosproject.net.Port;
42 import org.onosproject.net.device.PortStatistics; 45 import org.onosproject.net.device.PortStatistics;
...@@ -136,6 +139,9 @@ public class CodecManager implements CodecService { ...@@ -136,6 +139,9 @@ public class CodecManager implements CodecService {
136 registerCodec(VirtualDevice.class, new VirtualDeviceCodec()); 139 registerCodec(VirtualDevice.class, new VirtualDeviceCodec());
137 registerCodec(VirtualPort.class, new VirtualPortCodec()); 140 registerCodec(VirtualPort.class, new VirtualPortCodec());
138 registerCodec(VirtualLink.class, new VirtualLinkCodec()); 141 registerCodec(VirtualLink.class, new VirtualLinkCodec());
142 + registerCodec(MastershipTerm.class, new MastershipTermCodec());
143 + registerCodec(MastershipRole.class, new MastershipRoleCodec());
144 + registerCodec(RoleInfo.class, new RoleInfoCodec());
139 log.info("Started"); 145 log.info("Started");
140 } 146 }
141 147
......
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 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 +import org.onosproject.codec.CodecContext;
20 +import org.onosproject.codec.JsonCodec;
21 +import org.onosproject.net.MastershipRole;
22 +import org.slf4j.Logger;
23 +
24 +import static com.google.common.base.Preconditions.checkNotNull;
25 +import static org.onlab.util.Tools.nullIsIllegal;
26 +import static org.onosproject.net.MastershipRole.MASTER;
27 +import static org.onosproject.net.MastershipRole.NONE;
28 +import static org.onosproject.net.MastershipRole.STANDBY;
29 +import static org.slf4j.LoggerFactory.getLogger;
30 +
31 +/**
32 + * Codec for mastership role.
33 + */
34 +public final class MastershipRoleCodec extends JsonCodec<MastershipRole> {
35 + private final Logger log = getLogger(getClass());
36 +
37 + // JSON field names
38 + private static final String ROLE = "role";
39 +
40 + private static final String MISSING_MEMBER_MESSAGE = " member is required in MastershipRole";
41 +
42 + @Override
43 + public ObjectNode encode(MastershipRole mastershipRole, CodecContext context) {
44 + checkNotNull(mastershipRole, "MastershipRole cannot be null");
45 + ObjectNode result = context.mapper().createObjectNode()
46 + .put(ROLE, mastershipRole.name());
47 + return result;
48 + }
49 +
50 + @Override
51 + public MastershipRole decode(ObjectNode json, CodecContext context) {
52 + if (json == null || !json.isObject()) {
53 + return null;
54 + }
55 +
56 + String roleJson = nullIsIllegal(json.get(ROLE),
57 + ROLE + MISSING_MEMBER_MESSAGE).asText();
58 + MastershipRole mastershipRole;
59 + switch (roleJson) {
60 + case "MASTER":
61 + mastershipRole = MASTER;
62 + break;
63 + case "STANDBY":
64 + mastershipRole = STANDBY;
65 + break;
66 + case "NONE":
67 + mastershipRole = NONE;
68 + break;
69 + default:
70 + log.warn("The mastership role {} is not defined.", roleJson);
71 + return null;
72 + }
73 +
74 + return mastershipRole;
75 + }
76 +}
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 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 +import org.onosproject.cluster.NodeId;
20 +import org.onosproject.codec.CodecContext;
21 +import org.onosproject.codec.JsonCodec;
22 +import org.onosproject.mastership.MastershipTerm;
23 +
24 +import static com.google.common.base.Preconditions.checkNotNull;
25 +import static org.onlab.util.Tools.nullIsIllegal;
26 +
27 +/**
28 + * Codec for mastership term.
29 + */
30 +public class MastershipTermCodec extends JsonCodec<MastershipTerm> {
31 +
32 + // JSON field names
33 + private static final String MASTER = "master";
34 + private static final String TERM_NUMBER = "termNumber";
35 +
36 + private static final String MISSING_MEMBER_MESSAGE = " member is required in MastershipTerm";
37 +
38 + @Override
39 + public ObjectNode encode(MastershipTerm term, CodecContext context) {
40 + checkNotNull(term, "Mastership term cannot be null");
41 + ObjectNode result = context.mapper().createObjectNode()
42 + .put(MASTER, term.master().id())
43 + .put(TERM_NUMBER, term.termNumber());
44 +
45 + return result;
46 + }
47 +
48 + @Override
49 + public MastershipTerm decode(ObjectNode json, CodecContext context) {
50 + if (json == null || !json.isObject()) {
51 + return null;
52 + }
53 +
54 + // node identifier of master
55 + NodeId nodeId = NodeId.nodeId(nullIsIllegal(json.get(MASTER),
56 + MASTER + MISSING_MEMBER_MESSAGE).asText());
57 +
58 + // term number
59 + long termNumber = nullIsIllegal(json.get(TERM_NUMBER),
60 + TERM_NUMBER + MISSING_MEMBER_MESSAGE).asLong();
61 +
62 + return MastershipTerm.of(nodeId, termNumber);
63 + }
64 +}
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 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ArrayNode;
20 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 +import org.onosproject.cluster.NodeId;
22 +import org.onosproject.cluster.RoleInfo;
23 +import org.onosproject.codec.CodecContext;
24 +import org.onosproject.codec.JsonCodec;
25 +
26 +import java.util.ArrayList;
27 +import java.util.List;
28 +import java.util.stream.IntStream;
29 +
30 +import static com.google.common.base.Preconditions.checkNotNull;
31 +import static org.onlab.util.Tools.nullIsIllegal;
32 +
33 +/**
34 + * Codec for role info.
35 + */
36 +public final class RoleInfoCodec extends JsonCodec<RoleInfo> {
37 +
38 + // JSON field names
39 + private static final String MASTER = "master";
40 + private static final String BACKUPS = "backups";
41 +
42 + private static final String MISSING_MEMBER_MESSAGE = " member is required in MastershipTerm";
43 +
44 + @Override
45 + public ObjectNode encode(RoleInfo roleInfo, CodecContext context) {
46 + checkNotNull(roleInfo, "RoleInfo cannot be null");
47 +
48 + ObjectNode result = context.mapper().createObjectNode();
49 +
50 + if (roleInfo.master() != null) {
51 + result.put(MASTER, roleInfo.master().id());
52 + }
53 +
54 + ArrayNode backups = context.mapper().createArrayNode();
55 + roleInfo.backups().forEach(backup -> backups.add(backup.id()));
56 +
57 + if (roleInfo.backups().size() != 0) {
58 + result.set(BACKUPS, backups);
59 + }
60 +
61 + return result;
62 + }
63 +
64 + @Override
65 + public RoleInfo decode(ObjectNode json, CodecContext context) {
66 + if (json == null || !json.isObject()) {
67 + return null;
68 + }
69 +
70 + // parse node identifier of master
71 + NodeId nodeId = json.get(MASTER) == null ?
72 + null : NodeId.nodeId(json.get(MASTER).asText());
73 +
74 + // parse node identifier of backups
75 + List<NodeId> backups = new ArrayList<>();
76 +
77 + ArrayNode backupsJson = (ArrayNode) nullIsIllegal(json.get(BACKUPS),
78 + BACKUPS + MISSING_MEMBER_MESSAGE);
79 +
80 + IntStream.range(0, backupsJson.size()).forEach(i -> {
81 + JsonNode backupJson = nullIsIllegal(backupsJson.get(i),
82 + "Backup node id cannot be null");
83 + backups.add(NodeId.nodeId(backupJson.asText()));
84 + });
85 +
86 + return new RoleInfo(nodeId, backups);
87 + }
88 +}
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 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import org.hamcrest.Description;
21 +import org.hamcrest.TypeSafeDiagnosingMatcher;
22 +import org.junit.Before;
23 +import org.junit.Test;
24 +import org.onosproject.codec.JsonCodec;
25 +import org.onosproject.net.MastershipRole;
26 +
27 +import java.io.IOException;
28 +import java.io.InputStream;
29 +
30 +import static org.hamcrest.MatcherAssert.assertThat;
31 +import static org.hamcrest.Matchers.is;
32 +import static org.hamcrest.Matchers.notNullValue;
33 +import static org.onosproject.net.MastershipRole.MASTER;
34 +
35 +/**
36 + * Unit tests for mastership role codec.
37 + */
38 +public final class MastershipRoleCodecTest {
39 +
40 + MockCodecContext context;
41 + JsonCodec<MastershipRole> mastershipRoleCodec;
42 +
43 + /**
44 + * Sets up for each test. Creates a context and fetches the mastership role
45 + * codec.
46 + */
47 + @Before
48 + public void setUp() {
49 + context = new MockCodecContext();
50 + mastershipRoleCodec = context.codec(MastershipRole.class);
51 + assertThat(mastershipRoleCodec, notNullValue());
52 + }
53 +
54 + /**
55 + * Tests encoding of a mastership role object.
56 + */
57 + @Test
58 + public void testMastershipRoleEncode() {
59 + MastershipRole mastershipRole = MASTER;
60 + ObjectNode mastershipRoleJson = mastershipRoleCodec.encode(mastershipRole, context);
61 + assertThat(mastershipRoleJson, MastershipRoleJsonMatcher.matchesMastershipRole(mastershipRole));
62 + }
63 +
64 + /**
65 + * Tests decoding of mastership role JSON object.
66 + */
67 + @Test
68 + public void testMastershipRoleDecode() throws IOException {
69 + MastershipRole mastershipRole = getMastershipRole("MastershipRole.json");
70 +
71 + assertThat(mastershipRole, is(MASTER));
72 + }
73 +
74 + /**
75 + * Hamcrest matcher for mastership role.
76 + */
77 + private static final class MastershipRoleJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
78 +
79 + private final MastershipRole mastershipRole;
80 +
81 + private MastershipRoleJsonMatcher(MastershipRole mastershipRole) {
82 + this.mastershipRole = mastershipRole;
83 + }
84 +
85 + @Override
86 + protected boolean matchesSafely(JsonNode jsonNode, Description description) {
87 +
88 + // check mastership role
89 + String jsonRole = jsonNode.get("role").asText();
90 + String role = mastershipRole.name();
91 + if (!jsonRole.equals(role)) {
92 + description.appendText("mastership role was " + jsonRole);
93 + return false;
94 + }
95 +
96 + return true;
97 + }
98 +
99 + @Override
100 + public void describeTo(Description description) {
101 + description.appendText(mastershipRole.toString());
102 + }
103 +
104 + static MastershipRoleJsonMatcher matchesMastershipRole(MastershipRole mastershipRole) {
105 + return new MastershipRoleJsonMatcher(mastershipRole);
106 + }
107 + }
108 +
109 + /**
110 + * Reads in a mastership role from the given resource and decodes it.
111 + *
112 + * @param resourceName resource to use to read the JSON for the rule
113 + * @return decoded mastership term object
114 + * @throws IOException if processing the resource fails
115 + */
116 + private MastershipRole getMastershipRole(String resourceName) throws IOException {
117 + InputStream jsonStream = MastershipRoleCodecTest.class.getResourceAsStream(resourceName);
118 + JsonNode json = context.mapper().readTree(jsonStream);
119 + assertThat(json, notNullValue());
120 + MastershipRole mastershipRole = mastershipRoleCodec.decode((ObjectNode) json, context);
121 + assertThat(mastershipRole, notNullValue());
122 + return mastershipRole;
123 + }
124 +}
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 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import org.hamcrest.Description;
21 +import org.hamcrest.TypeSafeDiagnosingMatcher;
22 +import org.junit.Before;
23 +import org.junit.Test;
24 +import org.onosproject.cluster.NodeId;
25 +import org.onosproject.codec.JsonCodec;
26 +import org.onosproject.mastership.MastershipTerm;
27 +
28 +import java.io.IOException;
29 +import java.io.InputStream;
30 +
31 +import static org.hamcrest.MatcherAssert.assertThat;
32 +import static org.hamcrest.Matchers.is;
33 +import static org.hamcrest.Matchers.notNullValue;
34 +
35 +/**
36 + * Unit tests for mastership term codec.
37 + */
38 +public class MastershipTermCodecTest {
39 +
40 + MockCodecContext context;
41 + JsonCodec<MastershipTerm> mastershipTermCodec;
42 +
43 + /**
44 + * Sets up for each test. Creates a context and fetches the mastership term
45 + * codec.
46 + */
47 + @Before
48 + public void setUp() {
49 + context = new MockCodecContext();
50 + mastershipTermCodec = context.codec(MastershipTerm.class);
51 + assertThat(mastershipTermCodec, notNullValue());
52 + }
53 +
54 + /**
55 + * Tests encoding of a mastership term object.
56 + */
57 + @Test
58 + public void testMastershipTermEncode() {
59 + NodeId masterNodeId = NodeId.nodeId("1");
60 + long termNumber = 10;
61 +
62 + MastershipTerm mastershipTerm = MastershipTerm.of(masterNodeId, termNumber);
63 + ObjectNode mastershipTermJson = mastershipTermCodec.encode(mastershipTerm, context);
64 + assertThat(mastershipTermJson, MastershipTermJsonMatcher.matchesMastershipTerm(mastershipTerm));
65 + }
66 +
67 + /**
68 + * Tests decoding of mastership term JSON object.
69 + */
70 + @Test
71 + public void testMastershipTermDecode() throws IOException {
72 + MastershipTerm mastershipTerm = getMastershipTerm("MastershipTerm.json");
73 +
74 + assertThat(mastershipTerm.master().id(), is("1"));
75 + assertThat(mastershipTerm.termNumber(), is(10L));
76 + }
77 +
78 + /**
79 + * Hamcrest matcher for mastership term.
80 + */
81 + private static final class MastershipTermJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
82 +
83 + private final MastershipTerm mastershipTerm;
84 +
85 + private MastershipTermJsonMatcher(MastershipTerm mastershipTerm) {
86 + this.mastershipTerm = mastershipTerm;
87 + }
88 +
89 + @Override
90 + protected boolean matchesSafely(JsonNode jsonNode, Description description) {
91 +
92 + // check node identifier of master
93 + String jsonNodeId = jsonNode.get("master").asText();
94 + String nodeId = mastershipTerm.master().id();
95 + if (!jsonNodeId.equals(nodeId)) {
96 + description.appendText("master's node id was " + jsonNodeId);
97 + return false;
98 + }
99 +
100 + // check term number
101 + long jsonTermNumber = jsonNode.get("termNumber").asLong();
102 + long termNumber = mastershipTerm.termNumber();
103 + if (jsonTermNumber != termNumber) {
104 + description.appendText("term number was " + jsonTermNumber);
105 + return false;
106 + }
107 +
108 + return true;
109 + }
110 +
111 + @Override
112 + public void describeTo(Description description) {
113 + description.appendText(mastershipTerm.toString());
114 + }
115 +
116 + static MastershipTermJsonMatcher matchesMastershipTerm(MastershipTerm mastershipTerm) {
117 + return new MastershipTermJsonMatcher(mastershipTerm);
118 + }
119 + }
120 +
121 + /**
122 + * Reads in a mastership term from the given resource and decodes it.
123 + *
124 + * @param resourceName resource to use to read the JSON for the rule
125 + * @return decoded mastership term object
126 + * @throws IOException if processing the resource fails
127 + */
128 + private MastershipTerm getMastershipTerm(String resourceName) throws IOException {
129 + InputStream jsonStream = MastershipTermCodecTest.class.getResourceAsStream(resourceName);
130 + JsonNode json = context.mapper().readTree(jsonStream);
131 + assertThat(json, notNullValue());
132 + MastershipTerm mastershipTerm = mastershipTermCodec.decode((ObjectNode) json, context);
133 + assertThat(mastershipTerm, notNullValue());
134 + return mastershipTerm;
135 + }
136 +}
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 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import com.google.common.collect.ImmutableList;
21 +import org.apache.commons.lang3.StringUtils;
22 +import org.hamcrest.Description;
23 +import org.hamcrest.TypeSafeDiagnosingMatcher;
24 +import org.junit.Before;
25 +import org.junit.Test;
26 +import org.onosproject.cluster.NodeId;
27 +import org.onosproject.cluster.RoleInfo;
28 +import org.onosproject.codec.JsonCodec;
29 +
30 +import java.io.IOException;
31 +import java.io.InputStream;
32 +import java.util.List;
33 +
34 +import static org.hamcrest.MatcherAssert.assertThat;
35 +import static org.hamcrest.Matchers.is;
36 +import static org.hamcrest.Matchers.notNullValue;
37 +
38 +/**
39 + * Unit tests for role info codec.
40 + */
41 +public final class RoleInfoCodecTest {
42 +
43 + MockCodecContext context;
44 + JsonCodec<RoleInfo> roleInfoCodec;
45 +
46 + @Before
47 + public void setUp() {
48 + context = new MockCodecContext();
49 + roleInfoCodec = context.codec(RoleInfo.class);
50 + assertThat(roleInfoCodec, notNullValue());
51 + }
52 +
53 + /**
54 + * Tests encoding of a role info object.
55 + */
56 + @Test
57 + public void testRoleInfoEncode() {
58 + NodeId masterNodeId = NodeId.nodeId("1");
59 + NodeId backupNodeId1 = NodeId.nodeId("1");
60 + NodeId backupNodeId2 = NodeId.nodeId("2");
61 + NodeId backupNodeId3 = NodeId.nodeId("3");
62 + List<NodeId> backupNodeIds =
63 + ImmutableList.of(backupNodeId1, backupNodeId2, backupNodeId3);
64 +
65 + RoleInfo roleInfo = new RoleInfo(masterNodeId, backupNodeIds);
66 + ObjectNode roleInfoJson = roleInfoCodec.encode(roleInfo, context);
67 + assertThat(roleInfoJson, RoleInfoJsonMatcher.matchesRoleInfo(roleInfo));
68 + }
69 +
70 + /**
71 + * Tests decoding of a role info JSON object.
72 + */
73 + @Test
74 + public void testRoleInfoDecode() throws IOException {
75 + RoleInfo roleInfo = getRoleInfo("RoleInfo.json");
76 +
77 + assertThat(roleInfo.backups().size(), is(3));
78 +
79 + assertThat(roleInfo.master().id(), is("1"));
80 +
81 + List<NodeId> backups = roleInfo.backups();
82 + assertThat(backups.contains(NodeId.nodeId("2")), is(true));
83 + assertThat(backups.contains(NodeId.nodeId("3")), is(true));
84 + assertThat(backups.contains(NodeId.nodeId("4")), is(true));
85 + }
86 +
87 + /**
88 + * Hamcrest matcher for role info.
89 + */
90 + private static final class RoleInfoJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
91 +
92 + private final RoleInfo roleInfo;
93 +
94 + private RoleInfoJsonMatcher(RoleInfo roleInfo) {
95 + this.roleInfo = roleInfo;
96 + }
97 +
98 + @Override
99 + protected boolean matchesSafely(JsonNode jsonNode, Description description) {
100 +
101 + // check master node identifier
102 + String jsonNodeId = jsonNode.get("master") != null ? jsonNode.get("master").asText() : null;
103 + String nodeId = roleInfo.master().id();
104 + if (!StringUtils.equals(jsonNodeId, nodeId)) {
105 + description.appendText("master's node id was " + jsonNodeId);
106 + return false;
107 + }
108 +
109 + // check backup nodes size
110 + JsonNode jsonBackupNodeIds = jsonNode.get("backups");
111 + if (jsonBackupNodeIds.size() != roleInfo.backups().size()) {
112 + description.appendText("backup nodes size was " + jsonBackupNodeIds.size());
113 + return false;
114 + }
115 +
116 +
117 + // check backup nodes' identifier
118 + for (NodeId backupNodeId : roleInfo.backups()) {
119 + boolean backupFound = false;
120 + for (int idx = 0; idx < jsonBackupNodeIds.size(); idx++) {
121 + if (backupNodeId.id().equals(jsonBackupNodeIds.get(idx).asText())) {
122 + backupFound = true;
123 + break;
124 + }
125 + }
126 + if (!backupFound) {
127 + description.appendText("backup not found " + backupNodeId.id());
128 + return false;
129 + }
130 + }
131 +
132 + return true;
133 + }
134 +
135 + @Override
136 + public void describeTo(Description description) {
137 + description.appendText(roleInfo.toString());
138 + }
139 +
140 + /**
141 + * Factory to allocate a role info.
142 + *
143 + * @param roleInfo role info object we are looking for
144 + * @return matcher
145 + */
146 + static RoleInfoJsonMatcher matchesRoleInfo(RoleInfo roleInfo) {
147 + return new RoleInfoJsonMatcher(roleInfo);
148 + }
149 + }
150 +
151 + /**
152 + * Reads in a role info from the given resource and decodes it.
153 + *
154 + * @param resourceName resource to use to read the JSON for the rule
155 + * @return decoded roleInfo
156 + * @throws IOException if processing the resource fails
157 + */
158 + private RoleInfo getRoleInfo(String resourceName) throws IOException {
159 + InputStream jsonStream = RoleInfoCodecTest.class.getResourceAsStream(resourceName);
160 + JsonNode json = context.mapper().readTree(jsonStream);
161 + assertThat(json, notNullValue());
162 + RoleInfo roleInfo = roleInfoCodec.decode((ObjectNode) json, context);
163 + assertThat(roleInfo, notNullValue());
164 + return roleInfo;
165 + }
166 +}
1 +{
2 + "role": "MASTER"
3 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "master": "1",
3 + "termNumber": 10
4 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "master": "1",
3 + "backups": [
4 + "2",
5 + "3",
6 + "4"
7 + ]
8 +}
...\ No newline at end of file ...\ No newline at end of file