This is an automated email from the ASF dual-hosted git repository.

leventov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 72496d3  #7858 Throwing UnsupportedOperationException from 
ImmutableDrui… (#7933)
72496d3 is described below

commit 72496d371290850cbc2acee8be82cce17fa3480e
Author: Sashidhar Thallam <[email protected]>
AuthorDate: Fri Jul 19 01:05:19 2019 +0530

    #7858 Throwing UnsupportedOperationException from ImmutableDrui… (#7933)
    
    * #7858 Throwing UnsupportedOperationException from 
ImmutableDruidDataSource's equals() and hashCode() methods.
    
    * 1. Turning ImmutableDruidDataSource into a data container. 2. Adding a 
Util method to be used in tests for checking equality of 
ImmutableDruidDataSource objects.
    
    * Removing unused method
    
    * Fixing assert equals
    
    * Fixing assert equals in TestUtils.java
    
    * Adding java doc comments, Using ExpectedException in tests
    
    * Fixing test cases
    
    * Fixed expected exception message in tests
    
    * fixed line width
    
    * line width fix
    
    * code style fixes
    
    * code indentation fixes
    
    * fixing method name
---
 .../druid/client/ImmutableDruidDataSource.java     | 48 ++++++++---
 .../druid/client/ImmutableDruidDataSourceTest.java | 84 ++++++++++++++-----
 .../druid/server/http/DataSourcesResourceTest.java | 15 ++--
 .../utils/ImmutableDruidDataSourceTestUtils.java   | 94 ++++++++++++++++++++++
 4 files changed, 204 insertions(+), 37 deletions(-)

diff --git 
a/server/src/main/java/org/apache/druid/client/ImmutableDruidDataSource.java 
b/server/src/main/java/org/apache/druid/client/ImmutableDruidDataSource.java
index 7ce3fd6..d92f90f 100644
--- a/server/src/main/java/org/apache/druid/client/ImmutableDruidDataSource.java
+++ b/server/src/main/java/org/apache/druid/client/ImmutableDruidDataSource.java
@@ -22,6 +22,7 @@ package org.apache.druid.client;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSortedMap;
@@ -30,10 +31,10 @@ import org.apache.druid.timeline.SegmentId;
 
 import java.util.Collection;
 import java.util.Map;
-import java.util.Objects;
 
 /**
- * An immutable collection of metadata of segments ({@link DataSegment} 
objects), belonging to a particular data source.
+ * An immutable collection of metadata of segments ({@link DataSegment} 
objects), belonging to a particular data
+ * source.
  *
  * @see DruidDataSource - a mutable counterpart of this class
  */
@@ -120,11 +121,42 @@ public class ImmutableDruidDataSource
            + "'}";
   }
 
+  /**
+   * ImmutableDruidDataSource should be considered a container, not a data 
class. The idea is the same as behind
+   * prohibiting/limiting equals() (and therefore usage as HashSet/HashMap 
keys) of DataSegment: see
+   * https://github.com/apache/incubator-druid/issues/6358. When somebody 
wants to deduplicate ImmutableDruidDataSource
+   * objects, they would need to put them into a Map<String, 
ImmutableDruidDataSource> and resolve conflicts by name
+   * manually.
+   *
+   * See https://github.com/apache/incubator-druid/issues/7858
+   */
   @Override
   public boolean equals(Object o)
   {
-    // Note: this method is not well-defined. It should instead just throw 
UnsupportedOperationsException.
-    // See https://github.com/apache/incubator-druid/issues/7858.
+    throw new UnsupportedOperationException("ImmutableDruidDataSource 
shouldn't be used as the key in containers");
+  }
+
+  /**
+   * ImmutableDruidDataSource should be considered a container, not a data 
class. The idea is the same as behind
+   * prohibiting/limiting hashCode() (and therefore usage as HashSet/HashMap 
keys) of DataSegment: see
+   * https://github.com/apache/incubator-druid/issues/6358. When somebody 
wants to deduplicate ImmutableDruidDataSource
+   * objects, they would need to put them into a Map<String, 
ImmutableDruidDataSource> and resolve conflicts by name
+   * manually.
+   *
+   * See https://github.com/apache/incubator-druid/issues/7858
+   */
+  @Override
+  public int hashCode()
+  {
+    throw new UnsupportedOperationException("ImmutableDruidDataSource 
shouldn't be used as the key in containers");
+  }
+
+  /**
+   * This method should only be used in tests.
+   */
+  @VisibleForTesting
+  public boolean equalsForTesting(Object o)
+  {
     if (this == o) {
       return true;
     }
@@ -144,12 +176,4 @@ public class ImmutableDruidDataSource
 
     return this.idToSegments.equals(that.idToSegments);
   }
-
-  @Override
-  public int hashCode()
-  {
-    // Note: this method is not well-defined. It should instead just throw 
UnsupportedOperationsException.
-    // See https://github.com/apache/incubator-druid/issues/7858.
-    return Objects.hash(name, properties);
-  }
 }
diff --git 
a/server/src/test/java/org/apache/druid/client/ImmutableDruidDataSourceTest.java
 
b/server/src/test/java/org/apache/druid/client/ImmutableDruidDataSourceTest.java
index 4514113..bf3d47f 100644
--- 
a/server/src/test/java/org/apache/druid/client/ImmutableDruidDataSourceTest.java
+++ 
b/server/src/test/java/org/apache/druid/client/ImmutableDruidDataSourceTest.java
@@ -26,39 +26,85 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSortedMap;
 import org.apache.druid.jackson.DefaultObjectMapper;
 import org.apache.druid.java.util.common.Intervals;
+import org.apache.druid.test.utils.ImmutableDruidDataSourceTestUtils;
 import org.apache.druid.timeline.DataSegment;
 import org.apache.druid.timeline.DataSegment.PruneLoadSpecHolder;
-import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import java.io.IOException;
 
 public class ImmutableDruidDataSourceTest
 {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
   @Test
   public void testSerde() throws IOException
   {
-    final DataSegment segment = new DataSegment(
-        "test",
-        Intervals.of("2017/2018"),
-        "version",
-        null,
-        ImmutableList.of("dim1", "dim2"),
-        ImmutableList.of("met1", "met2"),
-        null,
-        1,
-        100L,
-        PruneLoadSpecHolder.DEFAULT
-    );
-    final ImmutableDruidDataSource dataSource = new ImmutableDruidDataSource(
-        "test",
-        ImmutableMap.of("prop1", "val1", "prop2", "val2"),
-        ImmutableSortedMap.of(segment.getId(), segment)
-    );
+    final DataSegment segment = getTestSegment();
+    final ImmutableDruidDataSource dataSource = 
getImmutableDruidDataSource(segment);
 
     final ObjectMapper objectMapper = new DefaultObjectMapper()
         .setInjectableValues(new Std().addValue(PruneLoadSpecHolder.class, 
PruneLoadSpecHolder.DEFAULT));
     final String json = objectMapper.writeValueAsString(dataSource);
-    Assert.assertEquals(dataSource, objectMapper.readValue(json, 
ImmutableDruidDataSource.class));
+
+    ImmutableDruidDataSourceTestUtils.assertEquals(dataSource, 
objectMapper.readValue(json,
+        ImmutableDruidDataSource.class));
+  }
+
+  @Test
+  public void testEqualsMethodThrowsUnsupportedOperationException()
+  {
+    expectedException.expect(UnsupportedOperationException.class);
+    expectedException.expectMessage("ImmutableDruidDataSource shouldn't be 
used as the key in containers");
+
+    final DataSegment segment1 = getTestSegment();
+
+    final ImmutableDruidDataSource dataSource1 = 
getImmutableDruidDataSource(segment1);
+
+    final DataSegment segment2 = getTestSegment();
+
+    final ImmutableDruidDataSource dataSource2 = 
getImmutableDruidDataSource(segment2);
+
+    dataSource1.equals(dataSource2);
+  }
+
+  private ImmutableDruidDataSource getImmutableDruidDataSource(DataSegment 
segment1)
+  {
+    return new ImmutableDruidDataSource(
+      "test",
+      ImmutableMap.of("prop1", "val1", "prop2", "val2"),
+      ImmutableSortedMap.of(segment1.getId(), segment1)
+    );
+  }
+
+  private DataSegment getTestSegment()
+  {
+    return new DataSegment(
+      "test",
+      Intervals.of("2017/2018"),
+      "version",
+      null,
+      ImmutableList.of("dim1", "dim2"),
+      ImmutableList.of("met1", "met2"),
+      null,
+      1,
+      100L,
+      PruneLoadSpecHolder.DEFAULT
+    );
+  }
+
+  @Test
+  public void testHashCodeMethodThrowsUnsupportedOperationException()
+  {
+    expectedException.expect(UnsupportedOperationException.class);
+    expectedException.expectMessage("ImmutableDruidDataSource shouldn't be 
used as the key in containers");
+    final DataSegment segment = getTestSegment();
+    final ImmutableDruidDataSource dataSource = 
getImmutableDruidDataSource(segment);
+
+    dataSource.hashCode();
   }
 }
diff --git 
a/server/src/test/java/org/apache/druid/server/http/DataSourcesResourceTest.java
 
b/server/src/test/java/org/apache/druid/server/http/DataSourcesResourceTest.java
index cb463fd..e200e70 100644
--- 
a/server/src/test/java/org/apache/druid/server/http/DataSourcesResourceTest.java
+++ 
b/server/src/test/java/org/apache/druid/server/http/DataSourcesResourceTest.java
@@ -50,6 +50,7 @@ import org.apache.druid.server.security.AuthenticationResult;
 import org.apache.druid.server.security.Authorizer;
 import org.apache.druid.server.security.AuthorizerMapper;
 import org.apache.druid.server.security.Resource;
+import org.apache.druid.test.utils.ImmutableDruidDataSourceTestUtils;
 import org.apache.druid.timeline.DataSegment;
 import org.apache.druid.timeline.SegmentId;
 import org.apache.druid.timeline.TimelineObjectHolder;
@@ -68,7 +69,6 @@ import javax.ws.rs.core.Response;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -179,9 +179,9 @@ public class DataSourcesResourceTest
     Set<ImmutableDruidDataSource> result = (Set<ImmutableDruidDataSource>) 
response.getEntity();
     Assert.assertEquals(200, response.getStatus());
     Assert.assertEquals(2, result.size());
-    Assert.assertEquals(
-        
listDataSources.stream().map(DruidDataSource::toImmutableDruidDataSource).collect(Collectors.toSet()),
-        new HashSet<>(result)
+    ImmutableDruidDataSourceTestUtils.assertEquals(
+        
listDataSources.stream().map(DruidDataSource::toImmutableDruidDataSource).collect(Collectors.toList()),
+        new ArrayList<>(result)
     );
 
     response = dataSourcesResource.getQueryableDataSources(null, null, 
request);
@@ -254,7 +254,10 @@ public class DataSourcesResourceTest
 
     Assert.assertEquals(200, response.getStatus());
     Assert.assertEquals(1, result.size());
-    Assert.assertEquals(listDataSources.get(0).toImmutableDruidDataSource(), 
Iterables.getOnlyElement(result));
+    ImmutableDruidDataSourceTestUtils.assertEquals(
+        listDataSources.get(0).toImmutableDruidDataSource(),
+        Iterables.getOnlyElement(result)
+    );
 
     response = dataSourcesResource.getQueryableDataSources(null, null, 
request);
     List<String> result1 = (List<String>) response.getEntity();
@@ -312,7 +315,7 @@ public class DataSourcesResourceTest
     Response response = dataSourcesResource.getDataSource("datasource1", 
"full");
     ImmutableDruidDataSource result = (ImmutableDruidDataSource) 
response.getEntity();
     Assert.assertEquals(200, response.getStatus());
-    Assert.assertEquals(dataSource1.toImmutableDruidDataSource(), result);
+    
ImmutableDruidDataSourceTestUtils.assertEquals(dataSource1.toImmutableDruidDataSource(),
 result);
     EasyMock.verify(inventoryView, server);
   }
 
diff --git 
a/server/src/test/java/org/apache/druid/test/utils/ImmutableDruidDataSourceTestUtils.java
 
b/server/src/test/java/org/apache/druid/test/utils/ImmutableDruidDataSourceTestUtils.java
new file mode 100644
index 0000000..80036de
--- /dev/null
+++ 
b/server/src/test/java/org/apache/druid/test/utils/ImmutableDruidDataSourceTestUtils.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.druid.test.utils;
+
+import org.apache.druid.client.ImmutableDruidDataSource;
+import org.junit.Assert;
+
+import javax.annotation.Nullable;
+import java.util.List;
+
+public class ImmutableDruidDataSourceTestUtils
+{
+
+  /**
+   * This method is to check equality of {@link ImmutableDruidDataSource} 
objects to be called from test code.
+   * @param expected expected object
+   * @param actual actual object
+   */
+  public static void assertEquals(ImmutableDruidDataSource expected, 
ImmutableDruidDataSource actual)
+  {
+    if (checkEquals(expected, actual)) {
+      return;
+    } else {
+      throw new AssertionError("Expected and actual objects are not equal as 
per ImmutableDruidDataSource's " +
+        "equalsForTesting() method");
+    }
+  }
+
+  private static boolean checkEquals(
+      @Nullable ImmutableDruidDataSource expected,
+      @Nullable ImmutableDruidDataSource actual
+  )
+  {
+    if (expected == null) {
+      return actual == null;
+    }
+
+    return expected.equalsForTesting(actual);
+  }
+
+  /**
+   * This method is to check the equality of a list of {@link 
ImmutableDruidDataSource} objects to be called from
+   * test code
+   * @param expected expected list
+   * @param actual actual list
+   * @return
+   */
+  public static boolean assertEquals(List<ImmutableDruidDataSource> expected, 
List<ImmutableDruidDataSource> actual)
+  {
+    if (expected == null) {
+      return actual == null;
+    }
+
+    Assert.assertEquals("expected and actual ImmutableDruidDataSource lists 
should be of equal size",
+        expected.size(), actual.size());
+
+    for (ImmutableDruidDataSource e : expected) {
+      if (!contains(e, actual)) {
+        throw new AssertionError("Expected and actual objects are not equal as 
per " +
+          "ImmutableDruidDataSource's equalsForTesting()" + " method");
+      }
+    }
+    return true;
+  }
+
+  private static boolean contains(ImmutableDruidDataSource expected, 
List<ImmutableDruidDataSource> actualList)
+  {
+    // Iterate over actual list to see if the element expected is present, if 
not return false
+    for (ImmutableDruidDataSource ds : actualList) {
+      if (ds.equalsForTesting(expected)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to