From 9be1c8eb16a03c9189fb7a53e34a299650e32f1b Mon Sep 17 00:00:00 2001 From: Michael Vorburger Date: Wed, 12 Oct 2016 17:10:48 +0200 Subject: [PATCH] New test utility AssertDataObjects This adapts https://github.com/vorburger/xtendbeans to OpenDaylight. That library can be used as-is for "normal" Java objects, such as Flow beans, as seen e.g. in https://git.opendaylight.org/gerrit/#/c/42109/. This change make it possible to use that library to compare actual DataObject obtained from the DataBroker with expected objects in tests, as illustrated e.g. in https://git.opendaylight.org/gerrit/#/c/44000/ (Those objects have a number of peculiarities which need adaption, provided by the classes in this change.) One can use AssertDataObjects.assertEqualBeans(Object expected, Object actual) WITHOUT ever writing any Xtend code, and WITHOUT any code generation, and use this utility JUST to get a very readable text diff between two object trees; this will look like shown in this presentation screenshot: https://docs.google.com/presentation/d/1bnwj8CrFGo5KekONYSeIHySdkoXZiewJxkHcZjXnzkQ/edit#slide=id.g17d8ae4d92_0_150 It is ALSO possible, but not required, to use the text syntax shown (see linked screenshot) to declare the expected object by copy/paste of that syntax into an *.xtend source file (from which an Xtend Maven plugin code generates Java code), because that text "happens" (intentionally) to be valid Xtend. This last step is purely optional though, and while some downstream projects may adopt this to define expected objects in a readable syntax, others may not, and simply define their expected objects with normal Java code and Builders (or reading them from XML, or whatever) - yet can still use this this new utility - just for a great diff / comparison kind of view, only. This code has dependencies on yangtools, mdsal, plus a test model for its self test - and the external xtendbeans library (which should be considered like any of the 100s of other ext. deps. we have). Change-Id: I34aac96bd13b936d6fb76a484a512081c18e0b11 Signed-off-by: Michael Vorburger (cherry picked from commit 18170324fab2eb494c7d8721521a429802dd48f9) --- binding/mdsal-binding-test-utils/pom.xml | 109 +++++++++++++ .../binding/testutils/AssertDataObjects.java | 63 ++++++++ .../testutils/AugmentableExtension.java | 56 +++++++ .../testutils/XtendBuilderExtensions.java | 46 ++++++ .../testutils/XtendYangBeanGenerator.java | 145 ++++++++++++++++++ .../testutils/AssertDataObjectsTest.java | 108 +++++++++++++ .../testutils/AssertNonDataObjectsTest.java | 54 +++++++ .../testutils/AugmentableExtensionTest.java | 75 +++++++++ .../binding/testutils/ExampleYangObjects.java | 34 ++++ .../binding/testutils/ExpectedObjects.java | 75 +++++++++ binding/pom.xml | 1 + common/artifacts/pom.xml | 12 ++ 12 files changed, 778 insertions(+) create mode 100644 binding/mdsal-binding-test-utils/pom.xml create mode 100644 binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjects.java create mode 100644 binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtension.java create mode 100644 binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendBuilderExtensions.java create mode 100644 binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendYangBeanGenerator.java create mode 100644 binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjectsTest.java create mode 100644 binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertNonDataObjectsTest.java create mode 100644 binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtensionTest.java create mode 100644 binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExampleYangObjects.java create mode 100644 binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExpectedObjects.java diff --git a/binding/mdsal-binding-test-utils/pom.xml b/binding/mdsal-binding-test-utils/pom.xml new file mode 100644 index 0000000000..82c8d06476 --- /dev/null +++ b/binding/mdsal-binding-test-utils/pom.xml @@ -0,0 +1,109 @@ + + + + + 4.0.0 + + + org.opendaylight.odlparent + odlparent + 1.7.2-SNAPSHOT + + + + org.opendaylight.mdsal + mdsal-binding-test-utils + 2.1.2-SNAPSHOT + + + + + org.opendaylight.mdsal + mdsal-artifacts + ${project.version} + pom + import + + + + + + + + junit + junit + compile + + + ch.vorburger + xtendbeans + compile + 1.2.0 + + + org.opendaylight.mdsal + mdsal-binding-dom-adapter + + + org.opendaylight.mdsal + mdsal-binding-dom-adapter + test-jar + + + + org.opendaylight.mdsal + mdsal-dom-broker + + + + + org.opendaylight.mdsal + mdsal-binding-test-model + test + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + checkstyle.violationSeverity=error + + + + + + + ${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/ + + + + opendaylight-site + ${nexus.site.url}/${project.artifactId}/ + + + + diff --git a/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjects.java b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjects.java new file mode 100644 index 0000000000..ce17bbae03 --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjects.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import ch.vorburger.xtendbeans.AssertBeans; +import org.junit.ComparisonFailure; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Assertion utilities for YANG {@link DataObject}s. + * + *

This compares two {@link DataObject}s by creating a textual representation of them, + * and comparing them. If they are not equals, then the thrown ComparisonFailure provides + * for a very highly readable comparison due to a syntax which immediately makes the difference obvious. + * + *

The syntax used happens to be valid Xtend code, and as such could be directly copy/pasted + * into an *.xtend source file of an expected object definition. This is optional though; this + * utility can very well be used with any object, not necessarily created by Xtend source code. + * + *

This also works for any Java object that is not a {@link DataObject}, + * like the {@link AssertBeans} which this is based upon. + * + * @see AssertBeans for more background + * + * @author Michael Vorburger + */ +public final class AssertDataObjects { + + private static final XtendYangBeanGenerator GENERATOR = new XtendYangBeanGenerator(); + + private AssertDataObjects() { + } + + /** + * Assert that an actual YANG DataObject (DataContainer) is equals to an expected one. + * + *

The argument types are intentionally of type Object instead of YANG DataContainer or DataObject. + * This is important so that this can be directly used on e.g. a List or Map etc. of DataObjects. + * + * @param expected the expected object + * @param actual the actual object to check against expected + * + * @see AssertBeans#assertEqualBeans(Object, Object) + */ + public static void assertEqualBeans(Object expected, Object actual) throws ComparisonFailure { + String expectedText = GENERATOR.getExpression(expected); + assertEqualByText(expectedText, actual); + } + + // package local method used only in the self tests of this utility (not intended for usage by client code) + static void assertEqualByText(String expectedText, Object actual) throws ComparisonFailure { + String actualText = GENERATOR.getExpression(actual); + if (!expectedText.equals(actualText)) { + throw new ComparisonFailure("Expected and actual beans do not match", expectedText, actualText); + } + } + +} diff --git a/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtension.java b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtension.java new file mode 100644 index 0000000000..675ac68e4a --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtension.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.ImmutableClassToInstanceMap; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import org.eclipse.xtext.xbase.lib.util.ReflectExtensions; +import org.opendaylight.yangtools.binding.data.codec.util.AugmentationReader; +import org.opendaylight.yangtools.yang.binding.Augmentable; +import org.opendaylight.yangtools.yang.binding.Augmentation; + +/** + * Adds an {@link #getAugmentations(Augmentable)} method to {@link Augmentable}. + * + *

Note that the generated *Impl classes in the *Builder do not implement + * {@link AugmentationReader}, only the LazyDataObject (package local) does. + * + * @see Augmentable + * @see AugmentationReader + * + * @author Michael Vorburger + */ +//package-local: no need to expose this, consider it an implementation detail; public API is the AssertDataObjects +class AugmentableExtension { + + private static final ReflectExtensions REFLECT_EXTENSIONS = new ReflectExtensions(); + + public ClassToInstanceMap> getAugmentations(Augmentable augmentable) { + if (augmentable instanceof AugmentationReader) { + AugmentationReader augmentationReader = (AugmentationReader) augmentable; + return ImmutableClassToInstanceMap.copyOf(augmentationReader.getAugmentations(augmentable)); + } else if (Proxy.isProxyClass(augmentable.getClass())) { + InvocationHandler invocationHandler = Proxy.getInvocationHandler(augmentable); + // class LazyDataObject implements InvocationHandler, AugmentationReader + AugmentationReader augmentationReader = (AugmentationReader) invocationHandler; + return ImmutableClassToInstanceMap.copyOf(augmentationReader.getAugmentations(augmentable)); + } else { + try { + return ImmutableClassToInstanceMap.copyOf(REFLECT_EXTENSIONS.get(augmentable, "augmentation")); + } catch (ClassCastException | SecurityException | NoSuchFieldException | IllegalArgumentException + | IllegalAccessException e) { + throw new IllegalArgumentException("TODO Implement getAugmentations() for an Augmentable which " + + "is neither a (Proxy of an) AugmentationReader nor has an internal field named " + + "'augmentation': " + augmentable.getClass(), e); + } + } + } + +} diff --git a/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendBuilderExtensions.java b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendBuilderExtensions.java new file mode 100644 index 0000000000..0b43dcee1a --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendBuilderExtensions.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; +import org.opendaylight.yangtools.concepts.Builder; + +/** + * Xtend extension method for >> operator support for {@link Builder}s. + * + *

import static extension org.opendaylight.mdsal.binding.testutils
+ * .XtendBuilderExtensions.operator_doubleGreaterThan
+ * + *

allows to write (in an *.xtend, not *.java): + * + *

new InterfaceBuilder >> [
+ *          name = "hello, world"
+ *      ]
+ * + *

instead of: + * + *

(new InterfaceBuilder => [
+ *          name = "hello, world"
+ *      ]).build
+ * + *

See also org.eclipse.xtext.xbase.lib.ObjectExtensions.operator_doubleArrow for background. + * + * @author Michael Vorburger + */ +public final class XtendBuilderExtensions { + + private XtendBuilderExtensions() { } + + public static

> P operator_doubleGreaterThan( + final T object, final Procedure1 block) { + + block.apply(object); + return object.build(); + } + +} diff --git a/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendYangBeanGenerator.java b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendYangBeanGenerator.java new file mode 100644 index 0000000000..2f7f7aab67 --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/XtendYangBeanGenerator.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import ch.vorburger.xtendbeans.XtendBeanGenerator; +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.Iterables; +import java.util.Optional; +import org.opendaylight.yangtools.yang.binding.Augmentable; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * {@link XtendBeanGenerator} customized for YANG beans stored in MD SAL + * DataBroker. + * + *

This is required: (a) because YANG model DataObject beans (when read from a + * DataBroker) are funky java.lang.reflect.Proxy instances, and XtendBeanGenerator + * cannot find the Builder or the property getters for them without a bit of help, + * which this class provides; + * + *

(b) to integrate it with the {@link XtendBuilderExtensions} + * (for ">>" instead of "->" and no build() method calls); + * + *

(c) to integrate it with the {@link AugmentableExtension}. + * + * @see XtendBeanGenerator + * + * @author Michael Vorburger + */ +// package-local: no need to expose this, consider it an implementation detail; public API is the AssertDataObjects +class XtendYangBeanGenerator extends XtendBeanGenerator { + + private final AugmentableExtension augmentableExtension = new AugmentableExtension(); + + private boolean useBuilderExtensions(Object bean) { + return bean instanceof DataObject; + } + + @Override + public String getExpression(Object bean) { + final String beanText = super.getExpression(bean); + if (useBuilderExtensions(bean)) { + return new StringBuilder("import static extension ").append(XtendBuilderExtensions.class.getName()) + .append(".operator_doubleGreaterThan\n\n").append(beanText).toString(); + } else { + return beanText; + } + } + + @Override + protected boolean isUsingBuilder(Object bean, Class builderClass) { + if (useBuilderExtensions(bean)) { + return false; + } else { + return super.isUsingBuilder(bean, builderClass); + } + } + + @Override + protected String getOperator(Object bean, Class builderClass) { + if (useBuilderExtensions(bean)) { + return ">>"; + } else { + return super.getOperator(bean, builderClass); + } + } + + @Override + protected CharSequence getNewBeanExpression(Object bean) { + if (bean instanceof DataContainer) { + DataContainer dataContainerBean = (DataContainer) bean; + Class builderClass = getBuilderClassByAppendingBuilderToClassName( + dataContainerBean.getImplementedInterface()); + return super.getNewBeanExpression(dataContainerBean, builderClass); + } else { + return super.getNewBeanExpression(bean); + } + } + + @Override + protected String stringify(Class klass) { + return klass.getSimpleName(); + } + + @Override + protected Iterable filter(Iterable properties) { + // YANG keys duplicate existing other properties (there are getter/setter for both), so filter them + return Iterables.filter(properties, property -> !property.getName().equals("key")); + } + + private Optional>> getAugmentations(Object bean) { + if (bean instanceof Augmentable) { + Augmentable augmentable = (Augmentable) bean; + ClassToInstanceMap> augmentables = augmentableExtension.getAugmentations(augmentable); + if (!augmentables.isEmpty()) { + return Optional.of(augmentables); + } + } + return Optional.empty(); + } + + @Override + protected CharSequence getAdditionalInitializationExpression(Object bean, Class builderClass) { + Optional>> optional = getAugmentations(bean); + if (optional.isPresent()) { + StringBuilder sb = new StringBuilder(); + optional.get().forEach((klass, augmentation) -> { + sb.append("addAugmentation("); + sb.append(stringify(klass)); + sb.append(", "); + sb.append(getNewBeanExpression(augmentation)); + sb.append(")"); + }); + return sb; + } else { + return ""; + } + } + +/* + TODO activate this once YANG objects either have a setAugmentations(Map) + or implement a new TBD interface AugmentableBuilder with a method like: + > Builder? addAugmentation(Class augmentationType, E augmentation); + which an extension method could jump on. + + @Override + public Iterable getAdditionalSpecialProperties(Object bean, Class builderClass) { + Optional>> optional = getAugmentations(bean); + if (optional.isPresent()) { + Property augmentableProperty = new Property("augmentations", true, Map.class, () -> optional.get(), null); + return Collections.singleton(augmentableProperty); + } else { + return Collections.emptyList(); + } + } + */ + +} diff --git a/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjectsTest.java b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjectsTest.java new file mode 100644 index 0000000000..e446193d8e --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjectsTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL; + +import java.util.Map; +import org.junit.Test; +import org.opendaylight.mdsal.binding.api.ReadTransaction; +import org.opendaylight.mdsal.binding.api.WriteTransaction; +import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataBrokerTest; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Tests the {@link AssertDataObjects} utility. + * + * @author Michael Vorburger + */ +public class AssertDataObjectsTest extends AbstractDataBrokerTest { + + private static final String HEADER = "import static extension org.opendaylight.mdsal.binding.testutils." + + "XtendBuilderExtensions.operator_doubleGreaterThan\n\n"; + + @Test + public void testAssertDataObjectsWithTopLevelListKey() { + AssertDataObjects.assertEqualByText("new TopLevelListKey(\"test\")\n", new TopLevelListKey("test")); + } + + @Test + public void testAssertDataObjectsWithEmptyTop() { + AssertDataObjects.assertEqualByText(HEADER + "new TopBuilder\n", ExampleYangObjects.topEmpty().getValue()); + } + + @Test + public void testAssertDataObjectsWithComplexTopWithKey() { + AssertDataObjects.assertEqualByText(HEADER + "new TopBuilder >> [\n" + + " topLevelList = #[\n" + + " new TopLevelListBuilder >> [\n" + + " name = \"foo\"\n" + + " addAugmentation(TreeComplexUsesAugment, new TreeComplexUsesAugmentBuilder >> [\n" + + " containerWithUses = new ContainerWithUsesBuilder >> [\n" + + " leafFromGrouping = \"foo\"\n" + + " ]\n" + + " ])\n" + + " ]\n" + + " ]\n" + + "]", ExpectedObjects.top()); + } + + @Test + public void testAssertDataObjectsWithTopLevelList() { + AssertDataObjects.assertEqualBeans(ExpectedObjects.topLevelList(), + ExampleYangObjects.topLevelList().getValue()); + AssertDataObjects.assertEqualByText(HEADER + "new TopLevelListBuilder >> [\n" + + " name = \"foo\"\n" + + " addAugmentation(TreeComplexUsesAugment, new TreeComplexUsesAugmentBuilder >> [\n" + + " containerWithUses = new ContainerWithUsesBuilder >> [\n" + + " leafFromGrouping = \"foo\"\n" + + " ]\n" + + " ])\n" + + "]", ExampleYangObjects.topLevelList().getValue()); + } + + @Test + public void testAssertDataObjectsWithDataBroker() throws Exception { + WriteTransaction initialTx = getDataBroker().newWriteOnlyTransaction(); + put(initialTx, OPERATIONAL, ExampleYangObjects.topEmpty()); + put(initialTx, OPERATIONAL, ExampleYangObjects.topLevelList()); + initialTx.submit().checkedGet(); + + ReadTransaction readTx = getDataBroker().newReadOnlyTransaction(); + InstanceIdentifier id = InstanceIdentifier.create(Top.class); + Top actualTop = readTx.read(OPERATIONAL, id).checkedGet().get(); + + AssertDataObjects.assertEqualBeans(ExpectedObjects.top(), actualTop); + + String expectedTopText = "import static extension org.opendaylight.mdsal.binding.testutils." + + "XtendBuilderExtensions.operator_doubleGreaterThan\n\n" + + "new TopBuilder >> [\n" + + " topLevelList = #[\n" + + " new TopLevelListBuilder >> [\n" + + " name = \"foo\"\n" + + " addAugmentation(TreeComplexUsesAugment, new TreeComplexUsesAugmentBuilder >> [\n" + + " containerWithUses = new ContainerWithUsesBuilder >> [\n" + + " leafFromGrouping = \"foo\"\n" + + " ]\n" + + " ])\n" + + " ]\n" + + " ]\n" + + "]"; + AssertDataObjects.assertEqualByText(expectedTopText, actualTop); + } + + void put(WriteTransaction tx, LogicalDatastoreType store, + Map.Entry, T> obj) { + tx.put(OPERATIONAL, obj.getKey(), obj.getValue()); + } + +} diff --git a/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertNonDataObjectsTest.java b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertNonDataObjectsTest.java new file mode 100644 index 0000000000..341d910a40 --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertNonDataObjectsTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import ch.vorburger.xtendbeans.AssertBeans; +import org.junit.Test; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Tests that the {@link AssertDataObjects} utility also works for any Java + * object that is not a {@link DataObject}, like the {@link AssertBeans} which + * it's based on. There is absolutely no particular reason why it wouldn't, + * because {@link AssertDataObjects} is essentially just a customization of + * {@link AssertBeans} - this is just to make sure none of the base + * functionality gets broken in the customization. + * + * @author Michael Vorburger + */ +public class AssertNonDataObjectsTest { + + public static class SomeBean { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Test + public void testString() { + AssertDataObjects.assertEqualBeans("hello, world", "hello, world"); + } + + @Test + public void testSomeBean() { + SomeBean first = new SomeBean(); + first.setName("hello, world"); + + SomeBean second = new SomeBean(); + second.setName("hello, world"); + + AssertDataObjects.assertEqualBeans(first, second); + } + +} diff --git a/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtensionTest.java b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtensionTest.java new file mode 100644 index 0000000000..e335ced7c9 --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtensionTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL; + +import ch.vorburger.xtendbeans.AssertBeans; +import java.util.Map; +import org.junit.Test; +import org.opendaylight.mdsal.binding.api.ReadTransaction; +import org.opendaylight.mdsal.binding.api.WriteTransaction; +import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataBrokerTest; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Test for {@link AugmentableExtension}. + * + * @author Michael Vorburger + */ +public class AugmentableExtensionTest extends AbstractDataBrokerTest { + + private final AugmentableExtension augmentableExtension = new AugmentableExtension(); + + @Test + public void testAugmentableExtensionOnYangObjectByBuilder() { + TopLevelList topLevelList = ExampleYangObjects.topLevelList().getValue(); + Map>, Augmentation> augmentations = augmentableExtension + .getAugmentations(topLevelList); + AssertBeans.assertEqualByText("#{\n" + + " org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test" + + ".augment.rev140709.TreeComplexUsesAugment -> (new TreeComplexUsesAugmentBuilder => [\n" + + " containerWithUses = (new ContainerWithUsesBuilder => [\n" + + " leafFromGrouping = \"foo\"\n" + + " ]).build()\n" + + " ]).build()\n" + + "}", augmentations); + } + + @Test + public void testAugmentableExtensionWithDataBroker() throws Exception { + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + put(writeTx, OPERATIONAL, ExampleYangObjects.topLevelList()); + writeTx.submit().checkedGet(); + + ReadTransaction readTx = getDataBroker().newReadOnlyTransaction(); + InstanceIdentifier id = InstanceIdentifier.create(Top.class); + Top actualTop = readTx.read(OPERATIONAL, id).checkedGet().get(); + AssertBeans.assertEqualByText("#{\n}", augmentableExtension.getAugmentations(actualTop)); + + TopLevelList topLevelList = actualTop.getTopLevelList().get(0); + AssertDataObjects.assertEqualByText("#{\n" + + " TreeComplexUsesAugment -> new TreeComplexUsesAugmentBuilder >> [\n" + + " containerWithUses = new ContainerWithUsesBuilder >> [\n" + + " leafFromGrouping = \"foo\"\n" + + " ]\n" + + " ]\n" + + "}", augmentableExtension.getAugmentations(topLevelList)); + } + + void put(WriteTransaction tx, LogicalDatastoreType store, + Map.Entry, T> obj) { + tx.put(OPERATIONAL, obj.getKey(), obj.getValue()); + } + +} diff --git a/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExampleYangObjects.java b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExampleYangObjects.java new file mode 100644 index 0000000000..9e4402d9cc --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExampleYangObjects.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleImmutableEntry; +import org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.TopBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class ExampleYangObjects { + + public static AbstractMap.SimpleImmutableEntry, Top> topEmpty() { + return new SimpleImmutableEntry<>(InstanceIdentifier.create(Top.class), new TopBuilder().build()); + } + + public static AbstractMap.SimpleImmutableEntry, TopLevelList> topLevelList() { + TreeComplexUsesAugment fooAugment = new TreeComplexUsesAugmentBuilder() + .setContainerWithUses(new ContainerWithUsesBuilder().setLeafFromGrouping("foo").build()).build(); + return new SimpleImmutableEntry<>( + ListsBindingUtils.path(ListsBindingUtils.TOP_FOO_KEY), + ListsBindingUtils.topLevelList(ListsBindingUtils.TOP_FOO_KEY, fooAugment)); + } +} diff --git a/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExpectedObjects.java b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExpectedObjects.java new file mode 100644 index 0000000000..88bec30def --- /dev/null +++ b/binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/ExpectedObjects.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.testutils; + +import java.util.Collections; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.complex.from.grouping.ContainerWithUses; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.TopBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListKey; + +/** + * The object initialization code in this class was generated by AssertDataObjects. + * + * @see AssertDataObjects + * @see AssertDataObjectsTest + */ +public class ExpectedObjects { + + public static TopLevelList topLevelList() { + TopLevelListBuilder it = new TopLevelListBuilder(); + TopLevelListKey topLevelListKey = new TopLevelListKey("foo"); + it.setKey(topLevelListKey); + it.setName("foo"); + TreeComplexUsesAugmentBuilder treeComplexUsesAugmentBuilder = new TreeComplexUsesAugmentBuilder(); + ContainerWithUsesBuilder containerWithUsesBuilder = new ContainerWithUsesBuilder(); + containerWithUsesBuilder.setLeafFromGrouping("foo"); + ContainerWithUses containerWithUses = containerWithUsesBuilder.build(); + treeComplexUsesAugmentBuilder.setContainerWithUses(containerWithUses); + TreeComplexUsesAugment treeComplexUsesAugment = treeComplexUsesAugmentBuilder.build(); + it.addAugmentation(TreeComplexUsesAugment.class, treeComplexUsesAugment); + return it.build(); + } + + public static Top top() { + TopBuilder topBuilder = new TopBuilder(); + final Procedure1 _function = (TopBuilder it) -> { + TopLevelListBuilder topLevelListBuilder = new TopLevelListBuilder(); + final Procedure1 _function_1 = (TopLevelListBuilder it1) -> { + it1.setName("foo"); + TreeComplexUsesAugmentBuilder treeComplexUsesAugmentBuilder = new TreeComplexUsesAugmentBuilder(); + final Procedure1 _function_2 = (TreeComplexUsesAugmentBuilder it2) -> { + ContainerWithUsesBuilder containerWithUsesBuilder = new ContainerWithUsesBuilder(); + final Procedure1 _function_3 = (ContainerWithUsesBuilder it3) -> { + it3.setLeafFromGrouping("foo"); + }; + ContainerWithUses doubleGreaterThan = XtendBuilderExtensions + .operator_doubleGreaterThan( + containerWithUsesBuilder, _function_3); + it2.setContainerWithUses(doubleGreaterThan); + }; + TreeComplexUsesAugment doubleGreaterThan = XtendBuilderExtensions + .operator_doubleGreaterThan( + treeComplexUsesAugmentBuilder, _function_2); + it1.addAugmentation(TreeComplexUsesAugment.class, doubleGreaterThan); + }; + TopLevelList doubleGreaterThan = XtendBuilderExtensions + .operator_doubleGreaterThan(topLevelListBuilder, _function_1); + it.setTopLevelList(Collections + .unmodifiableList(CollectionLiterals.newArrayList(doubleGreaterThan))); + }; + return XtendBuilderExtensions.operator_doubleGreaterThan(topBuilder, _function); + } +} diff --git a/binding/pom.xml b/binding/pom.xml index 1544cbcca8..7063bd9c32 100644 --- a/binding/pom.xml +++ b/binding/pom.xml @@ -37,6 +37,7 @@ mdsal-binding-api mdsal-binding-util + mdsal-binding-test-utils mdsal-binding-dom-adapter diff --git a/common/artifacts/pom.xml b/common/artifacts/pom.xml index b9138a363b..c8551855fb 100644 --- a/common/artifacts/pom.xml +++ b/common/artifacts/pom.xml @@ -109,11 +109,23 @@ mdsal-binding-dom-adapter ${project.version} + + org.opendaylight.mdsal + mdsal-binding-dom-adapter + ${project.version} + test-jar + test + org.opendaylight.mdsal mdsal-binding-util ${project.version} + + org.opendaylight.mdsal + mdsal-binding-test-utils + ${project.version} + org.opendaylight.mdsal.model -- 2.36.6