|
@@ -0,0 +1,153 @@
|
|
|
+/**
|
|
|
+ * 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.ambari.server.api.query;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+import javax.persistence.EntityManager;
|
|
|
+import javax.persistence.criteria.CriteriaQuery;
|
|
|
+import javax.persistence.criteria.Order;
|
|
|
+import javax.persistence.criteria.Root;
|
|
|
+import javax.persistence.metamodel.SingularAttribute;
|
|
|
+
|
|
|
+import org.apache.ambari.server.controller.internal.AlertHistoryResourceProvider;
|
|
|
+import org.apache.ambari.server.controller.internal.SortRequestImpl;
|
|
|
+import org.apache.ambari.server.controller.spi.Predicate;
|
|
|
+import org.apache.ambari.server.controller.spi.SortRequest;
|
|
|
+import org.apache.ambari.server.controller.spi.SortRequestProperty;
|
|
|
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
|
|
|
+import org.apache.ambari.server.controller.utilities.PredicateHelper;
|
|
|
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
|
|
|
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
|
|
|
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
|
|
|
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity_;
|
|
|
+import org.junit.Before;
|
|
|
+import org.junit.Test;
|
|
|
+
|
|
|
+import com.google.inject.Guice;
|
|
|
+import com.google.inject.Injector;
|
|
|
+
|
|
|
+import junit.framework.Assert;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Tests the {@link JpaSortBuilder}.
|
|
|
+ */
|
|
|
+public class JpaSortBuilderTest {
|
|
|
+
|
|
|
+ private Injector m_injector;
|
|
|
+
|
|
|
+ @Before
|
|
|
+ public void before() {
|
|
|
+ m_injector = Guice.createInjector(new InMemoryDefaultTestModule());
|
|
|
+ m_injector.getInstance(GuiceJpaInitializer.class);
|
|
|
+ m_injector.injectMembers(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Tests that adding a sort does not create another {@link Root} in the
|
|
|
+ * {@link CriteriaQuery}. A duplicate root will cause a cartesian product
|
|
|
+ * similar to:
|
|
|
+ *
|
|
|
+ * <pre>
|
|
|
+ * SELECT t0.alert_id,
|
|
|
+ * t0.alert_instance,
|
|
|
+ * t0.alert_label,
|
|
|
+ * t0.alert_state,
|
|
|
+ * t0.alert_text,
|
|
|
+ * t0.alert_timestamp,
|
|
|
+ * t0.cluster_id,
|
|
|
+ * t0.component_name,
|
|
|
+ * t0.host_name,
|
|
|
+ * t0.service_name,
|
|
|
+ * t0.alert_definition_id
|
|
|
+ * FROM alert_history t0,
|
|
|
+ * alert_history t2,
|
|
|
+ * alert_definition t1
|
|
|
+ * WHERE ( ( t1.definition_name = ? )
|
|
|
+ * AND ( t1.definition_id = t2.alert_definition_id ) )
|
|
|
+ * ORDER BY t0.alert_timestamp DESC
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ * where the root for {@code alert_history} is added twice.
|
|
|
+ *
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testSortDoesNotAddExtraRootPaths() throws Exception {
|
|
|
+ // create a sort request against the entity directly
|
|
|
+ List<SortRequestProperty> sortRequestProperties = new ArrayList<>();
|
|
|
+
|
|
|
+ sortRequestProperties.add(
|
|
|
+ new SortRequestProperty(AlertHistoryResourceProvider.ALERT_HISTORY_TIMESTAMP,
|
|
|
+ org.apache.ambari.server.controller.spi.SortRequest.Order.ASC));
|
|
|
+
|
|
|
+ SortRequest sortRequest = new SortRequestImpl(sortRequestProperties);
|
|
|
+
|
|
|
+ // create a complex, cross-entity predicate
|
|
|
+ Predicate predicate = new PredicateBuilder().property(
|
|
|
+ AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_NAME).equals("foo").toPredicate();
|
|
|
+
|
|
|
+ MockAlertHistoryredicateVisitor visitor = new MockAlertHistoryredicateVisitor();
|
|
|
+ PredicateHelper.visit(predicate, visitor);
|
|
|
+
|
|
|
+ JpaSortBuilder<AlertHistoryEntity> sortBuilder = new JpaSortBuilder<AlertHistoryEntity>();
|
|
|
+ List<Order> sortOrders = sortBuilder.buildSortOrders(sortRequest, visitor);
|
|
|
+
|
|
|
+ Assert.assertEquals(sortOrders.size(), 1);
|
|
|
+
|
|
|
+ // verify the CriteriaQuery has the correct roots
|
|
|
+ // it should have one for the main query predicate
|
|
|
+ CriteriaQuery<AlertHistoryEntity> query = visitor.getCriteriaQuery();
|
|
|
+ Set<Root<?>> roots = query.getRoots();
|
|
|
+ Assert.assertEquals(1, roots.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The {@link HistoryPredicateVisitor} is used to convert an Ambari
|
|
|
+ * {@link Predicate} into a JPA {@link javax.persistence.criteria.Predicate}.
|
|
|
+ */
|
|
|
+ private final class MockAlertHistoryredicateVisitor
|
|
|
+ extends JpaPredicateVisitor<AlertHistoryEntity> {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constructor.
|
|
|
+ *
|
|
|
+ */
|
|
|
+ public MockAlertHistoryredicateVisitor() {
|
|
|
+ super(m_injector.getInstance(EntityManager.class), AlertHistoryEntity.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * {@inheritDoc}
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Class<AlertHistoryEntity> getEntityClass() {
|
|
|
+ return AlertHistoryEntity.class;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * {@inheritDoc}
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<? extends SingularAttribute<?, ?>> getPredicateMapping(String propertyId) {
|
|
|
+ return AlertHistoryEntity_.getPredicateMapping().get(propertyId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|