[574447] Avoid indexing when base index is turned off in local search

The local search result provider asked for the built search operations
to index all elements that are iterated over, however this is clearly
erroneous when the backend was initialized with the no-base option. This
change updates the indexing requirements with appropriate guard
conditions, and adds a test case that verifies the indexing being turned
off as necessary.

Change-Id: I2e35ff767a0838a5e430dd8da96245530552f2f5
Signed-off-by: Zoltan Ujhelyi <zoltan.ujhelyi@incquerylabs.com>
diff --git a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java
index 541f5d9..4715e1f 100644
--- a/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java
+++ b/query/plugins/org.eclipse.viatra.query.runtime.localsearch/src/org/eclipse/viatra/query/runtime/localsearch/matcher/integration/AbstractLocalSearchResultProvider.java
@@ -168,7 +168,10 @@
     public void prepare() {
         try {
             runtimeContext.coalesceTraversals(() -> {
-                indexInitializationBeforePlanning();
+                LocalSearchHints configuration = overrideDefaultHints(query);
+                if (configuration.isUseBase()) {
+                    indexInitializationBeforePlanning();
+                }
                 prepareDirectDependencies();
                 runtimeContext.executeAfterTraversal(AbstractLocalSearchResultProvider.this::preparePlansForExpectedAdornments);
                 return null;
@@ -187,7 +190,9 @@
             IPlanDescriptor plan = getOrCreatePlan(reference, backendContext, compiler, configuration, planProvider);
             // Index keys
             try {
-                indexKeys(plan.getIteratedKeys());
+                if (configuration.isUseBase()) {
+                    indexKeys(plan.getIteratedKeys());
+                }
             } catch (InvocationTargetException e) {
                 throw new QueryProcessingException(e.getMessage(), null, e.getMessage(), query, e);
             }
diff --git a/query/tests/org.eclipse.viatra.query.runtime.cps.tests/src/org/eclipse/viatra/query/runtime/cps/tests/AllCpsTests.xtend b/query/tests/org.eclipse.viatra.query.runtime.cps.tests/src/org/eclipse/viatra/query/runtime/cps/tests/AllCpsTests.xtend
index a063517..b51f52f 100644
--- a/query/tests/org.eclipse.viatra.query.runtime.cps.tests/src/org/eclipse/viatra/query/runtime/cps/tests/AllCpsTests.xtend
+++ b/query/tests/org.eclipse.viatra.query.runtime.cps.tests/src/org/eclipse/viatra/query/runtime/cps/tests/AllCpsTests.xtend
@@ -32,6 +32,7 @@
     ModelManipulationAvgAggregatorTest,
     ModelManipulationTrickyJoinTest,
     LocalSearchPlanCostOverflowTest,
+    LocalSearchBaseIndexerSettingsTest,
     LiteralValuesTest,
     DanglingTest,
     NonRecursiveReachabilityTest,
diff --git a/query/tests/org.eclipse.viatra.query.runtime.cps.tests/src/org/eclipse/viatra/query/runtime/cps/tests/LocalSearchBaseIndexerSettingsTest.java b/query/tests/org.eclipse.viatra.query.runtime.cps.tests/src/org/eclipse/viatra/query/runtime/cps/tests/LocalSearchBaseIndexerSettingsTest.java
new file mode 100644
index 0000000..b04b56a
--- /dev/null
+++ b/query/tests/org.eclipse.viatra.query.runtime.cps.tests/src/org/eclipse/viatra/query/runtime/cps/tests/LocalSearchBaseIndexerSettingsTest.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2014-2021 Zoltan Ujhelyi, IncQuery Labs Ltd.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.viatra.query.runtime.cps.tests;
+
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.viatra.examples.cps.cyberPhysicalSystem.CyberPhysicalSystemPackage;
+import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.base.api.IndexingLevel;
+import org.eclipse.viatra.query.runtime.base.api.NavigationHelper;
+import org.eclipse.viatra.query.runtime.cps.tests.queries.util.ApplicationInstancesOfApplicationTypeQuerySpecification;
+import org.eclipse.viatra.query.runtime.cps.tests.queries.util.ApplicationTypeWithHostedInstancesQuerySpecification;
+import org.eclipse.viatra.query.runtime.emf.EMFScope;
+import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchHints;
+import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
+import org.eclipse.viatra.query.testing.core.ModelLoadHelper;
+import org.eclipse.viatra.query.testing.core.PatternBasedMatchSetModelProvider;
+import org.eclipse.viatra.query.testing.core.api.ViatraQueryTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LocalSearchBaseIndexerSettingsTest {
+    private final String snapshot = "org.eclipse.viatra.query.runtime.cps.tests/models/snapshots/test.snapshot";
+    private final ModelLoadHelper modelLoader = new ModelLoadHelper();
+
+    @Test
+    public void baseIndexerDisabledTestSimpleQuery() {
+        final QueryEvaluationHint hints = LocalSearchHints.getDefaultNoBase().build();
+        ResourceSet rs = new ResourceSetImpl();
+        final AdvancedViatraQueryEngine engine = AdvancedViatraQueryEngine.createUnmanagedEngine(new EMFScope(rs));
+        
+        ViatraQueryTest.test(ApplicationInstancesOfApplicationTypeQuerySpecification.instance())
+            .on(new EMFScope(rs))
+            .withSnapshotMatches(modelLoader.loadExpectedResultsFromUri(rs, snapshot))
+            .with(new PatternBasedMatchSetModelProvider(engine, hints))
+            .assertEquals(); 
+        
+        // Check that nothing is indexed here
+        final NavigationHelper index = EMFScope.extractUnderlyingEMFIndex(engine);
+        Assert.assertEquals(IndexingLevel.NONE,
+                index.getIndexingLevel(CyberPhysicalSystemPackage.Literals.APPLICATION_TYPE));
+        Assert.assertEquals(IndexingLevel.NONE,
+                index.getIndexingLevel(CyberPhysicalSystemPackage.Literals.APPLICATION_INSTANCE));
+        Assert.assertEquals(IndexingLevel.NONE,
+                index.getIndexingLevel(CyberPhysicalSystemPackage.Literals.APPLICATION_TYPE__INSTANCES));
+        engine.dispose();
+    }
+    
+    @Test
+    public void baseIndexerDisabledTestComplexQuery() {
+        final QueryEvaluationHint hints = LocalSearchHints.getDefaultNoBase().build();
+        ResourceSet rs = new ResourceSetImpl();
+        final AdvancedViatraQueryEngine engine = AdvancedViatraQueryEngine.createUnmanagedEngine(new EMFScope(rs));
+        
+        ViatraQueryTest.test(ApplicationTypeWithHostedInstancesQuerySpecification.instance())
+        .on(new EMFScope(rs))
+        .withSnapshotMatches(modelLoader.loadExpectedResultsFromUri(rs, snapshot))
+        .with(new PatternBasedMatchSetModelProvider(engine, hints))
+        .assertEquals(); 
+        
+        // Check that nothing is indexed here
+        final NavigationHelper index = EMFScope.extractUnderlyingEMFIndex(engine);
+        Assert.assertEquals(IndexingLevel.NONE,
+                index.getIndexingLevel(CyberPhysicalSystemPackage.Literals.APPLICATION_TYPE));
+        Assert.assertEquals(IndexingLevel.NONE,
+                index.getIndexingLevel(CyberPhysicalSystemPackage.Literals.APPLICATION_INSTANCE));
+        Assert.assertEquals(IndexingLevel.NONE,
+                index.getIndexingLevel(CyberPhysicalSystemPackage.Literals.APPLICATION_TYPE__INSTANCES));
+        engine.dispose();
+    }
+}
diff --git a/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/PatternBasedMatchSetModelProvider.java b/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/PatternBasedMatchSetModelProvider.java
index 28135e1..456804d 100644
--- a/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/PatternBasedMatchSetModelProvider.java
+++ b/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/PatternBasedMatchSetModelProvider.java
@@ -31,6 +31,14 @@
         this(hint, new SnapshotHelper());
     }
     
+    /**
+     * @since 2.6
+     */
+    public PatternBasedMatchSetModelProvider(AdvancedViatraQueryEngine engine, QueryEvaluationHint hint) {
+        this(hint, new SnapshotHelper());
+        this.engine = engine;
+    }
+    
     /** 
      * @deprecated 
      * Use @link #PatternMatchSetModelProvider(QueryEvaluationHint, SnapshotHelper) instead
diff --git a/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/api/ViatraQueryTest.xtend b/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/api/ViatraQueryTest.xtend
index 6b0c974..6ccb01c 100644
--- a/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/api/ViatraQueryTest.xtend
+++ b/query/tests/org.eclipse.viatra.query.testing.core/src/org/eclipse/viatra/query/testing/core/api/ViatraQueryTest.xtend
@@ -37,6 +37,7 @@
 import org.eclipse.viatra.query.testing.core.internal.AnalyzedPatternBasedMatchSetModelProvider
 import org.eclipse.viatra.query.testing.core.internal.DefaultMatchRecordEquivalence
 import org.eclipse.viatra.query.testing.snapshot.QuerySnapshot
+import org.eclipse.viatra.query.testing.core.PatternBasedMatchSetModelProvider
 
 /**
  * This class defines an API to easily construct test cases. The base conception is to provide
@@ -197,13 +198,21 @@
      * Adds a pattern-based match result set evaluated using the given hints.
      */
     def with(QueryEvaluationHint hint) {
-        
         val modelProvider = new AnalyzedPatternBasedMatchSetModelProvider(hint, testCase.snapshotHelper, analyzers);
         testCase.addMatchSetModelProvider(modelProvider)
         this
     }
     
     /**
+     * Adds a custom pattern-based match set provider to be evaluated.
+     * @since 2.6
+     */
+    def with(PatternBasedMatchSetModelProvider modelProvider) {
+        testCase.addMatchSetModelProvider(modelProvider)
+        this
+    }
+    
+    /**
      * Adds a pattern-based match result set evaluated using the given query backend.
      */
     def with(IQueryBackendFactory queryBackendFactory) {