content: /**
   * 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
   * <p>
   * http://www.apache.org/licenses/LICENSE-2.0
   * <p>
   * 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.atlas.repository.graphdb.janus;
  
  import com.google.common.collect.Collections2;
  import org.apache.atlas.repository.graphdb.AtlasGraph;
  import org.apache.atlas.repository.graphdb.AtlasGraphQuery;
  import org.apache.atlas.repository.graphdb.AtlasGraphQuery.ComparisionOperator;
  import org.apache.atlas.repository.graphdb.AtlasVertex;
  import org.testng.annotations.Test;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.List;
  
  import static org.testng.AssertJUnit.assertEquals;
  import static org.testng.AssertJUnit.assertTrue;
  
  /**
   * Tests for AtlasJanusGraphQuery.
   */
  @Test
  public class GraphQueryTest extends AbstractGraphDatabaseTest {
      @Test
      public <V, E> void testQueryThatCannotRunInMemory() {
          AtlasGraph<V, E>  graph = getGraph();
          AtlasVertex<V, E> v1    = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
  
          AtlasVertex<V, E> v2 = createVertex(graph);
  
          v2.setProperty("name", "Fred");
  
          AtlasVertex<V, E> v3 = createVertex(graph);
  
          v3.setProperty("size15", "15");
  
          graph.commit();
  
          AtlasVertex<V, E> v4 = createVertex(graph);
  
          v4.setProperty("name", "Fred");
          v4.setProperty("size15", "15");
  
          AtlasGraphQuery<?, ?> q = graph.query();
  
          q.has("name", ComparisionOperator.NOT_EQUAL, "George");
          q.has("size15", "15");
  
          graph.commit();
  
          pause(); //pause to let the index get updated
  
          // Janusgraph 0.5.3 introduced changes to NOT-EQUAL operator
          // https://github.com/JanusGraph/janusgraph/issues/2205
          // Earlier behavior doesn't check if property exists, so all vertices without this property was also returned in 'neq'.
          // Now 'neq' checks if property exists and property is not-equal to property value
          assertQueryMatches(q, v1, v4);
      }
  
      @Test
      public void testCombinationOfAndsAndOrs() {
          AtlasJanusGraph graph = getAtlasJanusGraph();
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
          v1.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v2 = createVertex(graph);
  
          v2.setProperty("name", "George");
          v2.setProperty("size15", "16");
          v2.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v3 = createVertex(graph);
  
          v3.setProperty("name", "Jane");
          v3.setProperty("size15", "17");
          v3.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v4 = createVertex(graph);
  
          v4.setProperty("name", "Bob");
          v4.setProperty("size15", "18");
          v4.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v5 = createVertex(graph);
  
          v5.setProperty("name", "Julia");
          v5.setProperty("size15", "19");
          v5.setProperty("typeName", "Manager");
  
          AtlasGraphQuery q = getGraphQuery();
  
          q.has("typeName", "Person");
          //initially match
          AtlasGraphQuery inner1a = q.createChildQuery();
          AtlasGraphQuery inner1b = q.createChildQuery();
  
          inner1a.has("name", "Fred");
          inner1b.has("name", "Jane");
          q.or(toList(inner1a, inner1b));
  
          AtlasGraphQuery inner2a = q.createChildQuery();
          AtlasGraphQuery inner2b = q.createChildQuery();
          AtlasGraphQuery inner2c = q.createChildQuery();
  
          inner2a.has("size15", "18");
          inner2b.has("size15", "15");
          inner2c.has("size15", "16");
          q.or(toList(inner2a, inner2b, inner2c));
  
          assertQueryMatches(q, v1);
          graph.commit();
          pause(); //let the index update
          assertQueryMatches(q, v1);
      }
  
      @Test
      public void testWithinStep() {
          AtlasJanusGraph graph = getAtlasJanusGraph();
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
          v1.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v2 = createVertex(graph);
  
          v2.setProperty("name", "George");
          v2.setProperty("size15", "16");
          v2.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v3 = createVertex(graph);
  
          v3.setProperty("name", "Jane");
          v3.setProperty("size15", "17");
          v3.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v4 = createVertex(graph);
  
          v4.setProperty("name", "Bob");
          v4.setProperty("size15", "18");
          v4.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v5 = createVertex(graph);
  
          v5.setProperty("name", "Julia");
          v5.setProperty("size15", "19");
          v5.setProperty("typeName", "Manager");
  
          AtlasGraphQuery q = getGraphQuery();
  
          q.has("typeName", "Person");
          //initially match
          q.in("name", toList("Fred", "Jane"));
          q.in("size15", toList("18", "15", "16"));
  
          assertQueryMatches(q, v1);
          graph.commit();
          pause(); //let the index update
          assertQueryMatches(q, v1);
      }
  
      @Test
      public void testWithinStepWhereGraphIsStale() {
          AtlasJanusGraph graph = getAtlasJanusGraph();
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
          v1.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v2 = createVertex(graph);
  
          v2.setProperty("name", "George");
          v2.setProperty("size15", "16");
          v2.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v3 = createVertex(graph);
  
          v3.setProperty("name", "Jane");
          v3.setProperty("size15", "17");
          v3.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v4 = createVertex(graph);
  
          v4.setProperty("name", "Bob");
          v4.setProperty("size15", "18");
          v4.setProperty("typeName", "Person");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v5 = createVertex(graph);
  
          v5.setProperty("name", "Julia");
          v5.setProperty("size15", "19");
          v5.setProperty("typeName", "Manager");
  
          AtlasGraphQuery q = getGraphQuery();
  
          q.has("typeName", "Person");
          //initially match
          q.in("name", toList("Fred", "Jane"));
  
          graph.commit();
          pause(); //let the index update
          assertQueryMatches(q, v1, v3);
          //make v3 no longer match the query.  Within step should filter out the vertex since it no longer matches.
          v3.setProperty("name", "Janet");
          assertQueryMatches(q, v1);
      }
  
      @Test
      public void testSimpleOrQuery() {
          AtlasJanusGraph graph = getAtlasJanusGraph();
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v2 = createVertex(graph);
  
          v2.setProperty("name", "Fred");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v3 = createVertex(graph);
  
          v3.setProperty("size15", "15");
  
          graph.commit();
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v4 = createVertex(graph);
  
          v4.setProperty("name", "Fred");
          v4.setProperty("size15", "15");
  
          AtlasVertex<AtlasJanusVertex, AtlasJanusEdge> v5 = createVertex(graph);
  
          v5.setProperty("name", "George");
          v5.setProperty("size15", "16");
  
          AtlasGraphQuery q      = graph.query();
          AtlasGraphQuery inner1 = q.createChildQuery().has("name", "Fred");
          AtlasGraphQuery inner2 = q.createChildQuery().has("size15", "15");
  
          q.or(toList(inner1, inner2));
          assertQueryMatches(q, v1, v2, v3, v4);
          graph.commit();
          pause(); //pause to let the indexer get updated (this fails frequently without a pause)
          assertQueryMatches(q, v1, v2, v3, v4);
      }
  
      @Test
      public <V, E> void testQueryMatchesAddedVertices() {
          AtlasGraph<V, E> graph = getGraph();
  
          AtlasVertex<V, E> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
  
          AtlasVertex<V, E> v2 = createVertex(graph);
  
          v2.setProperty("name", "Fred");
  
          AtlasVertex<V, E> v3 = createVertex(graph);
  
          v3.setProperty("size15", "15");
  
          graph.commit();
  
          AtlasVertex<V, E> v4 = createVertex(graph);
  
          v4.setProperty("name", "Fred");
          v4.setProperty("size15", "15");
  
          AtlasGraphQuery q = getGraphQuery();
  
          q.has("name", "Fred");
          q.has("size15", "15");
  
          assertQueryMatches(q, v1, v4);
          graph.commit();
          assertQueryMatches(q, v1, v4);
      }
  
      @Test
      public <V, E> void testQueryDoesNotMatchRemovedVertices() {
          AtlasGraph<V, E> graph = getGraph();
  
          AtlasVertex<V, E> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
  
          AtlasVertex<V, E> v2 = createVertex(graph);
  
          v2.setProperty("name", "Fred");
  
          AtlasVertex<V, E> v3 = createVertex(graph);
  
          v3.setProperty("size15", "15");
  
          AtlasVertex<V, E> v4 = createVertex(graph);
  
          v4.setProperty("name", "Fred");
          v4.setProperty("size15", "15");
  
          graph.commit();
  
          graph.removeVertex(v1);
  
          AtlasGraphQuery q = getGraphQuery();
  
          q.has("name", "Fred");
          q.has("size15", "15");
  
          assertQueryMatches(q, v4);
          graph.commit();
  
          assertQueryMatches(q, v4);
      }
  
      @Test
      public <V, E> void testQueryDoesNotMatchUncommittedAddedAndRemovedVertices() {
          AtlasGraph<V, E> graph = getGraph();
  
          AtlasVertex<V, E> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
  
          AtlasVertex<V, E> v2 = createVertex(graph);
  
          v2.setProperty("name", "Fred");
  
          AtlasVertex<V, E> v3 = createVertex(graph);
  
          v3.setProperty("size15", "15");
  
          AtlasVertex<V, E> v4 = createVertex(graph);
  
          v4.setProperty("name", "Fred");
          v4.setProperty("size15", "15");
  
          AtlasGraphQuery q = getGraphQuery();
  
          q.has("name", "Fred");
          q.has("size15", "15");
  
          assertQueryMatches(q, v1, v4);
  
          graph.removeVertex(v1);
  
          assertQueryMatches(q, v4);
          graph.commit();
  
          assertQueryMatches(q, v4);
      }
  
      @Test
      public <V, E> void testQueryResultsReflectPropertyAdd() {
          AtlasGraph<V, E> graph = getGraph();
  
          AtlasVertex<V, E> v1 = createVertex(graph);
  
          v1.setProperty("name", "Fred");
          v1.setProperty("size15", "15");
          v1.addProperty(TRAIT_NAMES, "trait1");
          v1.addProperty(TRAIT_NAMES, "trait2");
  
          AtlasVertex<V, E> v2 = createVertex(graph);
  
          v2.setProperty("name", "Fred");
          v2.addProperty(TRAIT_NAMES, "trait1");
  
          AtlasVertex<V, E> v3 = createVertex(graph);
  
          v3.setProperty("size15", "15");
          v3.addProperty(TRAIT_NAMES, "trait2");
  
          AtlasGraphQuery query = getGraphQuery();
  
          query.has("name", "Fred");
          query.has(TRAIT_NAMES, "trait1");
          query.has("size15", "15");
  
          assertQueryMatches(query, v1);
          //make v3 match the query
          v3.setProperty("name", "Fred");
          v3.addProperty(TRAIT_NAMES, "trait1");
          assertQueryMatches(query, v1, v3);
          v3.removeProperty(TRAIT_NAMES);
          assertQueryMatches(query, v1);
          v3.addProperty(TRAIT_NAMES, "trait2");
          assertQueryMatches(query, v1);
          v1.removeProperty(TRAIT_NAMES);
          assertQueryMatches(query);
          graph.commit();
          assertQueryMatches(query);
      }
  
      private static <T> List<T> toList(Iterable<T> itr) {
          List<T> result = new ArrayList<>();
  
          for (T object : itr) {
              result.add(object);
          }
  
          return result;
      }
  
      private <V, E> void assertQueryMatches(AtlasGraphQuery expr, AtlasVertex<V, E>... expectedResults) {
          //getGraph().commit();
          Collection<AtlasVertex<AtlasJanusVertex, AtlasJanusEdge>> temp = toList(expr.vertices());
  
          //filter out vertices from previous test executions
          Collection<AtlasVertex<AtlasJanusVertex, AtlasJanusEdge>> result = Collections2.filter(temp, input -> newVertices.contains(input));
  
          String errorMessage = "Expected/found result sizes differ.  Expected: " + Arrays.asList(expectedResults) + ", found: " + result;
  
          assertEquals(errorMessage, expectedResults.length, result.size());
  
          for (AtlasVertex<V, E> v : expectedResults) {
              assertTrue(result.contains(v));
          }
      }
  
      private static List<Object> toList(Object... objects) {
          return Arrays.asList(objects);
      }
  
      private AtlasGraphQuery<AtlasJanusVertex, AtlasJanusEdge> getGraphQuery() {
          return getAtlasJanusGraph().query();
      }
  
      private void pause() {
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              //ignore
          }
      }
  }
  