AssertDataObjects with LOG of diff 09/48009/3
authorMichael Vorburger <vorburger@redhat.com>
Fri, 4 Nov 2016 18:03:23 +0000 (19:03 +0100)
committerMichael Vorburger <vorburger@redhat.com>
Mon, 7 Nov 2016 11:06:25 +0000 (12:06 +0100)
When running failing tests in CI on build (or simply local mvn CLI),
then the ComparisonFailure for large expected/actual objects, such as
flows, is very difficult to make sense of.

In the IDE one doesn't have this problem, because the JUnit view of IDEs
will interpret an ComparisonFailure and show a very clear side-by-side
comparison of expected VS actual.

This change introduces a LOG, in case of AssertDataObjects failure,
which prints a diff for the ComparisonFailure, which will make analysing
AssertDataObjects based test failures much easier on CI build.

Change-Id: I666fbceeb794f7b810a11c2efa8e33a51afc1b2d
Signed-off-by: Michael Vorburger <vorburger@redhat.com>
.gitignore
binding/mdsal-binding-test-utils/pom.xml
binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AssertDataObjects.java
binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/AugmentableExtension.java
binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/DiffUtil.java [new file with mode: 0644]
binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/AssertNonDataObjectsTest.java

index a55ebfa32674c9feaa448fb46100ca9e3c3fa954..be8e60ec965d547e6f66f49147869c2a0adf9432 100644 (file)
@@ -22,3 +22,4 @@ yang-gen-sal
 target
 .DS_Store
 META-INF
+.fbExcludeFilterFile
index 3b5db7f84a7b285e18eefd5f6d969c073b4343ac..e108a761456001427b27576e9b705e5d5dcc1a97 100644 (file)
       <scope>compile</scope>
       <version>1.2.0</version>
     </dependency>
+    <dependency>
+      <groupId>com.googlecode.java-diff-utils</groupId>
+      <artifactId>diffutils</artifactId>
+      <version>1.3.0</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.mdsal</groupId>
       <artifactId>mdsal-binding-dom-adapter</artifactId>
       <artifactId>mdsal-binding-test-model</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.truth</groupId>
+      <artifactId>truth</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
           <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>findbugs-maven-plugin</artifactId>
+        <configuration>
+          <failOnError>true</failOnError>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
index ce17bbae03b071d1741c90dd42e331421be1a5f6..0a5b0465d84905f0f55d7947cfda9263da51d74f 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.mdsal.binding.testutils;
 import ch.vorburger.xtendbeans.AssertBeans;
 import org.junit.ComparisonFailure;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Assertion utilities for YANG {@link DataObject}s.
@@ -31,6 +33,8 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
  */
 public final class AssertDataObjects {
 
+    private static final Logger LOG = LoggerFactory.getLogger(AssertDataObjects.class);
+
     private static final XtendYangBeanGenerator GENERATOR = new XtendYangBeanGenerator();
 
     private AssertDataObjects() {
@@ -56,6 +60,8 @@ public final class AssertDataObjects {
     static void assertEqualByText(String expectedText, Object actual) throws ComparisonFailure {
         String actualText = GENERATOR.getExpression(actual);
         if (!expectedText.equals(actualText)) {
+            String diff = DiffUtil.diff(expectedText, actualText);
+            LOG.warn("diff for ComparisonFailure about to be thrown:\n{}", diff);
             throw new ComparisonFailure("Expected and actual beans do not match", expectedText, actualText);
         }
     }
index 675ac68e4a07235b7db0c96d708cc8a36b17ebe5..f93e2df46de609ebec8d297e01a53f083dc89dfc 100644 (file)
@@ -27,7 +27,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentation;
  *
  * @author Michael Vorburger
  */
-//package-local: no need to expose this, consider it an implementation detail; public API is the AssertDataObjects
+// 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();
diff --git a/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/DiffUtil.java b/binding/mdsal-binding-test-utils/src/main/java/org/opendaylight/mdsal/binding/testutils/DiffUtil.java
new file mode 100644 (file)
index 0000000..3c0d048
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.base.Joiner;
+import com.google.common.base.Splitter;
+import difflib.DiffUtils;
+import difflib.Patch;
+import java.util.List;
+
+/**
+ * Utility to create diff of text.
+ *
+ * @author Michael Vorburger
+ */
+// package-local: no need to expose this, consider it an implementation detail; public API is the AssertDataObjects
+final class DiffUtil {
+
+    // Configuration which we could tune as we use this more
+    private static final int MAX_DIFFS = 1;
+    private static final int CONTEXT_LINES = 3; // number of lines of context output around each difference
+
+    private static final Splitter SPLITTER = Splitter.on(System.getProperty("line.separator"));
+    private static final Joiner JOINER = Joiner.on(System.getProperty("line.separator"));
+
+    public static String diff(String expectedText, String actualText) {
+        List<String> originalLines = SPLITTER.splitToList(expectedText);
+        List<String> revisedLines = SPLITTER.splitToList(actualText);
+        Patch<String> patch = DiffUtils.diff(originalLines, revisedLines);
+        List<String> diff = DiffUtils.generateUnifiedDiff("expected", "actual", originalLines, patch, CONTEXT_LINES);
+
+        String header = "";
+        int deltas = patch.getDeltas().size();
+        if (deltas > MAX_DIFFS) {
+            header = String.format("(Too many differences (%d); only showing first %d)%n", deltas, MAX_DIFFS);
+            diff = diff.subList(0, MAX_DIFFS);
+        }
+        return header + JOINER.join(diff);
+    }
+
+    private DiffUtil() { }
+
+}
index 341d910a4015d1b5d5858b58d369f672e5993093..8f6f7badba61ca573c8d099ce26b266e51c55cb1 100644 (file)
@@ -7,7 +7,10 @@
  */
 package org.opendaylight.mdsal.binding.testutils;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import ch.vorburger.xtendbeans.AssertBeans;
+import org.junit.ComparisonFailure;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 
@@ -51,4 +54,19 @@ public class AssertNonDataObjectsTest {
         AssertDataObjects.assertEqualBeans(first, second);
     }
 
+    @Test
+    public void testSomeBeanMismatch() {
+        SomeBean expected = new SomeBean();
+        expected.setName("hello, world 1");
+
+        SomeBean actual = new SomeBean();
+        actual.setName("hello, world 2");
+
+        try {
+            AssertDataObjects.assertEqualBeans(expected, actual);
+        } catch (ComparisonFailure e) {
+            assertThat(e.getExpected()).contains("hello, world 1");
+            assertThat(e.getActual()).contains("hello, world 2");
+        }
+    }
 }