Ray Milkey
Committed by Gerrit Code Review

Add JSON to CLI commands

- Drivers
- Groups

Change-Id: Ib47dc75d9db839329e6cf8fc4439150848f604f5
......@@ -15,12 +15,16 @@
*/
package org.onosproject.cli.net;
import java.util.Set;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverAdminService;
import com.fasterxml.jackson.databind.node.ArrayNode;
/**
* Lists device drivers.
*/
......@@ -43,17 +47,35 @@ public class DriversListCommand extends AbstractShellCommand {
if (driverName != null) {
printDriver(service.getDriver(driverName));
} else {
service.getDrivers().forEach(this::printDriver);
if (outputJson()) {
json(service.getDrivers());
} else {
service.getDrivers().forEach(this::printDriver);
}
}
}
private void json(Driver driver) {
print("%s", jsonForEntity(driver, Driver.class));
}
private void json(Set<Driver> drivers) {
ArrayNode result = mapper().createArrayNode();
drivers.forEach(driver -> result.add(jsonForEntity(driver, Driver.class)));
print("%s", result.toString());
}
private void printDriver(Driver driver) {
Driver parent = driver.parent();
print(FMT, driver.name(), parent != null ? parent.name() : "none",
driver.manufacturer(), driver.hwVersion(), driver.swVersion());
driver.behaviours().forEach(b -> print(FMT_B, b.getCanonicalName(),
driver.implementation(b).getCanonicalName()));
driver.properties().forEach((k, v) -> print(FMT_P, k, v));
if (outputJson()) {
json(driver);
} else {
Driver parent = driver.parent();
print(FMT, driver.name(), parent != null ? parent.name() : "none",
driver.manufacturer(), driver.hwVersion(), driver.swVersion());
driver.behaviours().forEach(b -> print(FMT_B, b.getCanonicalName(),
driver.implementation(b).getCanonicalName()));
driver.properties().forEach((k, v) -> print(FMT_P, k, v));
}
}
}
......
......@@ -15,10 +15,9 @@
*/
package org.onosproject.cli.net;
import static com.google.common.collect.Lists.newArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
......@@ -34,6 +33,11 @@ import org.onosproject.net.group.Group.GroupState;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import static com.google.common.collect.Lists.newArrayList;
/**
* Lists all groups in the system.
*/
......@@ -54,6 +58,16 @@ public class GroupsListCommand extends AbstractShellCommand {
required = false, multiValued = false)
String state;
private JsonNode json(Map<Device, List<Group>> sortedGroups) {
ArrayNode result = mapper().createArrayNode();
sortedGroups.forEach((device, groups) ->
groups.forEach(group ->
result.add(jsonForEntity(group, Group.class))));
return result;
}
@Override
protected void execute() {
DeviceService deviceService = get(DeviceService.class);
......@@ -61,7 +75,11 @@ public class GroupsListCommand extends AbstractShellCommand {
SortedMap<Device, List<Group>> sortedGroups =
getSortedGroups(deviceService, groupService);
sortedGroups.forEach((device, groups) -> printGroups(device.id(), groups));
if (outputJson()) {
print("%s", json(sortedGroups));
} else {
sortedGroups.forEach((device, groups) -> printGroups(device.id(), groups));
}
}
/**
......
......@@ -33,11 +33,14 @@ import org.onosproject.net.HostLocation;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
import org.onosproject.net.Port;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.intent.ConnectivityIntent;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.HostToHostIntent;
......@@ -89,6 +92,9 @@ public class CodecManager implements CodecService {
registerCodec(Topology.class, new TopologyCodec());
registerCodec(TopologyCluster.class, new TopologyClusterCodec());
registerCodec(Path.class, new PathCodec());
registerCodec(Group.class, new GroupCodec());
registerCodec(Driver.class, new DriverCodec());
registerCodec(GroupBucket.class, new GroupBucketCodec());
log.info("Started");
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.driver.Driver;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* JSON codec for the Driver class.
*/
public final class DriverCodec extends JsonCodec<Driver> {
private static final String PARENT = "parent";
private static final String NAME = "name";
private static final String MANUFACTURER = "manufacturer";
private static final String HW_VERSION = "hwVersion";
private static final String SW_VERSION = "swVersion";
private static final String BEHAVIOURS = "behaviours";
private static final String BEHAVIORS_NAME = "name";
private static final String BEHAVIORS_IMPLEMENTATION_NAME = "implementationName";
private static final String PROPERTIES = "properties";
@Override
public ObjectNode encode(Driver driver, CodecContext context) {
checkNotNull(driver, "Driver cannot be null");
ObjectNode result = context.mapper().createObjectNode()
.put(NAME, driver.name())
.put(MANUFACTURER, driver.manufacturer())
.put(HW_VERSION, driver.hwVersion())
.put(SW_VERSION, driver.swVersion());
if (driver.parent() != null) {
result.put(PARENT, driver.parent().name());
}
ArrayNode behaviours = context.mapper().createArrayNode();
driver.behaviours().forEach(behaviour -> {
ObjectNode entry = context.mapper().createObjectNode()
.put(BEHAVIORS_NAME, behaviour.getCanonicalName())
.put(BEHAVIORS_IMPLEMENTATION_NAME,
driver.implementation(behaviour).getCanonicalName());
behaviours.add(entry);
});
result.set(BEHAVIOURS, behaviours);
ArrayNode properties = context.mapper().createArrayNode();
driver.properties().forEach((name, value) -> {
ObjectNode entry = context.mapper().createObjectNode()
.put("name", name)
.put("value", value);
properties.add(entry);
});
result.set(PROPERTIES, properties);
return result;
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.group.GroupBucket;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Group bucket JSON codec.
*/
public class GroupBucketCodec extends JsonCodec<GroupBucket> {
private static final String TYPE = "type";
private static final String TREATMENT = "treatment";
private static final String WEIGHT = "weight";
private static final String WATCH_PORT = "watchPort";
private static final String WATCH_GROUP = "watchGroup";
private static final String PACKETS = "packets";
private static final String BYTES = "bytes";
@Override
public ObjectNode encode(GroupBucket bucket, CodecContext context) {
checkNotNull(bucket, "Driver cannot be null");
ObjectNode result = context.mapper().createObjectNode()
.put(TYPE, bucket.type().toString())
.put(WEIGHT, bucket.weight())
.put(PACKETS, bucket.packets())
.put(BYTES, bucket.bytes());
if (bucket.watchPort() != null) {
result.put(WATCH_PORT, bucket.watchPort().toString());
}
if (bucket.watchGroup() != null) {
result.put(WATCH_GROUP, bucket.watchGroup().toString());
}
if (bucket.treatment() != null) {
result.set(TREATMENT, context.codec(TrafficTreatment.class).encode(bucket.treatment(), context));
}
return result;
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Group JSON codec.
*/
public final class GroupCodec extends JsonCodec<Group> {
// JSON field names
private static final String ID = "id";
private static final String STATE = "state";
private static final String LIFE = "life";
private static final String PACKETS = "packets";
private static final String BYTES = "bytes";
private static final String REFERENCE_COUNT = "referenceCount";
private static final String TYPE = "type";
private static final String DEVICE_ID = "deviceId";
private static final String APP_ID = "appId";
private static final String APP_COOKIE = "appCookie";
private static final String GIVEN_GROUP_ID = "givenGroupId";
private static final String BUCKETS = "buckets";
@Override
public ObjectNode encode(Group group, CodecContext context) {
checkNotNull(group, "Group cannot be null");
ObjectNode result = context.mapper().createObjectNode()
.put(ID, group.id().toString())
.put(STATE, group.state().toString())
.put(LIFE, group.life())
.put(PACKETS, group.packets())
.put(BYTES, group.bytes())
.put(REFERENCE_COUNT, group.referenceCount())
.put(TYPE, group.type().toString())
.put(DEVICE_ID, group.deviceId().toString());
if (group.appId() != null) {
result.put(APP_ID, group.appId().toString());
}
if (group.appCookie() != null) {
result.put(APP_COOKIE, group.appCookie().toString());
}
if (group.givenGroupId() != null) {
result.put(GIVEN_GROUP_ID, group.givenGroupId());
}
ArrayNode buckets = context.mapper().createArrayNode();
group.buckets().buckets().forEach(bucket -> {
ObjectNode bucketJson = context.codec(GroupBucket.class).encode(bucket, context);
buckets.add(bucketJson);
});
result.set(BUCKETS, buckets);
return result;
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import java.util.Map;
import org.junit.Test;
import org.onosproject.net.driver.Behaviour;
import org.onosproject.net.driver.DefaultDriver;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.TestBehaviour;
import org.onosproject.net.driver.TestBehaviourImpl;
import org.onosproject.net.driver.TestBehaviourTwo;
import org.onosproject.net.driver.TestBehaviourTwoImpl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableMap;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.onosproject.codec.impl.DriverJsonMatcher.matchesDriver;
/**
* Unit tests for the driver codec.
*/
public class DriverCodecTest {
@Test
public void codecTest() {
Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
ImmutableMap.of(TestBehaviour.class,
TestBehaviourImpl.class,
TestBehaviourTwo.class,
TestBehaviourTwoImpl.class);
Map<String, String> properties =
ImmutableMap.of("key1", "value1", "key2", "value2");
DefaultDriver parent = new DefaultDriver("parent", null, "Acme",
"HW1.2.3", "SW1.2.3",
behaviours,
properties);
DefaultDriver child = new DefaultDriver("child", parent, "Acme",
"HW1.2.3.1", "SW1.2.3.1",
behaviours,
properties);
MockCodecContext context = new MockCodecContext();
ObjectNode driverJson = context.codec(Driver.class).encode(child, context);
assertThat(driverJson, matchesDriver(child));
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import java.util.Map;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onosproject.net.driver.Driver;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Hamcrest matcher for drivers.
*/
public final class DriverJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
private final Driver driver;
private DriverJsonMatcher(Driver driver) {
this.driver = driver;
}
@Override
public boolean matchesSafely(JsonNode jsonDriver, Description description) {
// check id
String jsonDriverName = jsonDriver.get("name").asText();
String driverName = driver.name();
if (!jsonDriverName.equals(driverName)) {
description.appendText("name was " + jsonDriverName);
return false;
}
// check parent
String jsonParent = jsonDriver.get("parent").asText();
String parent = driver.parent().name();
if (!jsonParent.equals(parent)) {
description.appendText("parent was " + jsonParent);
return false;
}
// check manufacturer
String jsonManufacturer = jsonDriver.get("manufacturer").asText();
String manufacturer = driver.manufacturer();
if (!jsonManufacturer.equals(manufacturer)) {
description.appendText("manufacturer was " + jsonManufacturer);
return false;
}
// check HW version
String jsonHWVersion = jsonDriver.get("hwVersion").asText();
String hwVersion = driver.hwVersion();
if (!jsonHWVersion.equals(hwVersion)) {
description.appendText("HW version was " + jsonHWVersion);
return false;
}
// check SW version
String jsonSWVersion = jsonDriver.get("swVersion").asText();
String swVersion = driver.swVersion();
if (!jsonSWVersion.equals(swVersion)) {
description.appendText("SW version was " + jsonSWVersion);
return false;
}
// Check properties
JsonNode jsonProperties = jsonDriver.get("properties");
if (driver.properties().size() != jsonProperties.size()) {
description.appendText("properties map size was was " + jsonProperties.size());
return false;
}
for (Map.Entry<String, String> entry : driver.properties().entrySet()) {
boolean propertyFound = false;
for (int propertyIndex = 0; propertyIndex < jsonProperties.size(); propertyIndex++) {
String jsonName = jsonProperties.get(propertyIndex).get("name").asText();
String jsonValue = jsonProperties.get(propertyIndex).get("value").asText();
if (!jsonName.equals(entry.getKey()) ||
!jsonValue.equals(entry.getValue())) {
propertyFound = true;
break;
}
}
if (!propertyFound) {
description.appendText("property not found " + entry.getKey());
return false;
}
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(driver.toString());
}
/**
* Factory to allocate a driver matcher.
*
* @param driver driver object we are looking for
* @return matcher
*/
public static DriverJsonMatcher matchesDriver(Driver driver) {
return new DriverJsonMatcher(driver);
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onosproject.net.group.GroupBucket;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Hamcrest matcher for instructions.
*/
public final class GroupBucketJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
private final GroupBucket bucket;
private GroupBucketJsonMatcher(GroupBucket bucket) {
this.bucket = bucket;
}
/**
* Matches the contents of a group bucket.
*
* @param bucketJson JSON representation of bucket to match
* @param description Description object used for recording errors
* @return true if contents match, false otherwise
*/
@Override
public boolean matchesSafely(JsonNode bucketJson, Description description) {
// check type
final String jsonType = bucketJson.get("type").textValue();
if (!bucket.type().name().equals(jsonType)) {
description.appendText("type was " + jsonType);
return false;
}
final long jsonWeight = bucketJson.get("weight").longValue();
if (bucket.weight() != jsonWeight) {
description.appendText("weight was " + jsonWeight);
return false;
}
final long packetsJson = bucketJson.get("packets").asLong();
if (bucket.packets() != packetsJson) {
description.appendText("packets was " + packetsJson);
return false;
}
final long bytesJson = bucketJson.get("bytes").asLong();
if (bucket.bytes() != bytesJson) {
description.appendText("bytes was " + packetsJson);
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(bucket.toString());
}
/**
* Factory to allocate an bucket matcher.
*
* @param bucket bucket object we are looking for
* @return matcher
*/
public static GroupBucketJsonMatcher matchesGroupBucket(GroupBucket bucket) {
return new GroupBucketJsonMatcher(bucket);
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import org.junit.Test;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.net.NetTestTools;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.group.DefaultGroup;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.onosproject.codec.impl.GroupJsonMatcher.matchesGroup;
/**
* Group codec unit tests.
*/
public class GroupCodecTest {
@Test
public void codecTest() {
GroupBucket bucket1 = DefaultGroupBucket
.createSelectGroupBucket(DefaultTrafficTreatment.emptyTreatment());
GroupBucket bucket2 = DefaultGroupBucket
.createIndirectGroupBucket(DefaultTrafficTreatment.emptyTreatment());
GroupBuckets buckets = new GroupBuckets(ImmutableList.of(bucket1, bucket2));
DefaultGroup group = new DefaultGroup(
new DefaultGroupId(1),
NetTestTools.did("d1"),
GroupDescription.Type.INDIRECT,
buckets);
MockCodecContext context = new MockCodecContext();
GroupCodec codec = new GroupCodec();
ObjectNode groupJson = codec.encode(group, context);
assertThat(groupJson, matchesGroup(group));
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.codec.impl;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Hamcrest matcher for groups.
*/
public final class GroupJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
private final Group group;
private GroupJsonMatcher(Group group) {
this.group = group;
}
@Override
public boolean matchesSafely(JsonNode jsonGroup, Description description) {
// check id
String jsonGroupId = jsonGroup.get("id").asText();
String groupId = group.id().toString();
if (!jsonGroupId.equals(groupId)) {
description.appendText("group id was " + jsonGroupId);
return false;
}
// check state
String jsonState = jsonGroup.get("state").asText();
String state = group.state().toString();
if (!jsonState.equals(state)) {
description.appendText("state was " + jsonState);
return false;
}
// check life
long jsonLife = jsonGroup.get("life").asLong();
long life = group.life();
if (life != jsonLife) {
description.appendText("life was " + jsonLife);
return false;
}
// check bytes
long jsonBytes = jsonGroup.get("bytes").asLong();
long bytes = group.bytes();
if (bytes != jsonBytes) {
description.appendText("bytes was " + jsonBytes);
return false;
}
// check packets
long jsonPackets = jsonGroup.get("packets").asLong();
long packets = group.packets();
if (packets != jsonPackets) {
description.appendText("packets was " + jsonPackets);
return false;
}
// check size of bucket array
JsonNode jsonBuckets = jsonGroup.get("buckets");
if (jsonBuckets.size() != group.buckets().buckets().size()) {
description.appendText("buckets size was " + jsonBuckets.size());
return false;
}
// Check buckets
for (GroupBucket bucket : group.buckets().buckets()) {
boolean bucketFound = false;
for (int bucketIndex = 0; bucketIndex < jsonBuckets.size(); bucketIndex++) {
GroupBucketJsonMatcher bucketMatcher =
GroupBucketJsonMatcher.matchesGroupBucket(bucket);
if (bucketMatcher.matches(jsonBuckets.get(bucketIndex))) {
bucketFound = true;
break;
}
}
if (!bucketFound) {
description.appendText("bucket not found " + bucket.toString());
return false;
}
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(group.toString());
}
/**
* Factory to allocate a group matcher.
*
* @param group group object we are looking for
* @return matcher
*/
public static GroupJsonMatcher matchesGroup(Group group) {
return new GroupJsonMatcher(group);
}
}