/**
* 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.lens.server.query.retry;
import static org.apache.lens.server.api.LensConfConstants.DRIVER_TYPES_AND_CLASSES;
import static org.apache.lens.server.api.LensConfConstants.QUERY_RETRY_POLICY_CLASSES;
import static org.apache.lens.server.api.LensServerAPITestUtil.getLensConf;
import static org.apache.lens.server.api.util.LensUtil.getHashMap;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import org.apache.lens.api.LensSessionHandle;
import org.apache.lens.api.query.FailedAttempt;
import org.apache.lens.api.query.LensQuery;
import org.apache.lens.api.query.QueryHandle;
import org.apache.lens.server.LensJerseyTest;
import org.apache.lens.server.LensServices;
import org.apache.lens.server.api.error.LensException;
import org.apache.lens.server.api.query.QueryContext;
import org.apache.lens.server.api.query.QueryExecutionService;
import org.apache.lens.server.api.session.SessionService;
import org.apache.lens.server.common.RestAPITestUtil;
import org.apache.lens.server.query.QueryExecutionServiceImpl;
import org.apache.lens.server.query.TestQueryService;
import org.glassfish.jersey.test.TestProperties;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
@Test(groups = "post-restart", dependsOnGroups = "restart-test")
public class QueryRetryTest extends LensJerseyTest {
private LensSessionHandle session;
private QueryExecutionServiceImpl getQueryService() {
return LensServices.get().getService(QueryExecutionService.NAME);
}
@Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
return new TestQueryService.QueryServiceTestApp();
}
private SessionService getSessionService() {
return LensServices.get().getService(SessionService.NAME);
}
private LensSessionHandle getSession() throws LensException {
return getSessionService().openSession("foo", "bar", null, null);
}
@BeforeTest
public void setUp() throws Exception {
super.setUp();
}
@BeforeClass
public void setUpClass() throws Exception {
restartLensServer(getServerConf(), false);
session = getSession();
}
@AfterClass
public void cleanupClass() throws Exception {
getSessionService().closeSession(session);
restartLensServer();
}
@Override
public Map<String, String> getServerConfOverWrites() {
return getHashMap(DRIVER_TYPES_AND_CLASSES, "retry:org.apache.lens.server.query.retry.MockDriverForRetries",
QUERY_RETRY_POLICY_CLASSES, TestServerRetryPolicyDecider.class.getName());
}
@Test
public void testSingleRetrySameDriver() throws LensException, InterruptedException {
QueryHandle handle = getQueryService().executeAsync(session, "select 1",
getLensConf("driver.retry/single_failure.cost", "1", "driver.retry/double_failure.cost", "2"),
"random query");
QueryContext ctx = getQueryService().getQueryContext(handle);
while (!ctx.getStatus().finished()) {
ctx = getQueryService().getQueryContext(handle);
Thread.sleep(1000);
}
assertEquals(ctx.getFailedAttempts().size(), 1);
FailedAttempt failedAttempt = ctx.getFailedAttempts().get(0);
assertEquals(failedAttempt.getDriverName(), "retry/single_failure");
assertEquals(ctx.getSelectedDriver().getFullyQualifiedName(), "retry/single_failure");
assertTrue(failedAttempt.getDriverFinishTime() > failedAttempt.getDriverStartTime());
assertTrue(ctx.getDriverStatus().getDriverStartTime() > failedAttempt.getDriverFinishTime());
}
@Test
public void testRetryOnDifferentDriver() throws LensException, InterruptedException {
QueryHandle handle = getQueryService().executeAsync(session, "select 1",
getLensConf("driver.retry/single_failure.cost", "2", "driver.retry/double_failure.cost", "1"),
"random query");
QueryContext ctx = getQueryService().getQueryContext(handle);
while (!ctx.getStatus().finished()) {
ctx = getQueryService().getQueryContext(handle);
Thread.sleep(1000);
}
assertEquals(ctx.getFailedAttempts().size(), 2);
FailedAttempt attempt1 = ctx.getFailedAttempts().get(0);
FailedAttempt attempt2 = ctx.getFailedAttempts().get(1);
// two retries on double_failure
assertEquals(attempt1.getDriverName(), "retry/double_failure");
assertEquals(attempt2.getDriverName(), "retry/double_failure");
// first retry failed on single_failure since the driver checks total retries before failing.
// If there weren't any attempts before this one, then this attempt would fail, but since there
// have already been 2 attempts and 2 > 1, this attempt passed.
assertEquals(ctx.getSelectedDriver().getFullyQualifiedName(), "retry/single_failure");
assertTrue(attempt2.getDriverStartTime() > attempt1.getDriverFinishTime());
assertTrue(ctx.getDriverStatus().getDriverStartTime() > attempt2.getDriverFinishTime());
// test rest api
LensQuery lensQuery = RestAPITestUtil.getLensQuery(target(), session, handle, MediaType.APPLICATION_XML_TYPE);
assertEquals(lensQuery.getFailedAttempts(), ctx.getFailedAttempts());
}
@Test
public void testFailureAfterRetry() throws LensException, InterruptedException {
QueryHandle handle = getQueryService().executeAsync(session, "select 1",
getLensConf("driver.retry/double_failure.cost", "1"),
"random query");
QueryContext ctx = getQueryService().getQueryContext(handle);
while (!ctx.getStatus().finished()) {
ctx = getQueryService().getQueryContext(handle);
Thread.sleep(1000);
}
assertTrue(ctx.getStatus().failed());
assertEquals(ctx.getFailedAttempts().size(), 1);
FailedAttempt attempt1 = ctx.getFailedAttempts().get(0);
assertEquals(attempt1.getDriverName(), "retry/double_failure");
assertEquals(ctx.getSelectedDriver().getFullyQualifiedName(), "retry/double_failure");
assertTrue(ctx.getStatus().failed());
}
@Test
public void testDelayedLaunch() throws LensException, InterruptedException {
QueryHandle handle = getQueryService().executeAsync(session, "select 1",
getLensConf("driver.retry/double_failure.cost", "1",
"driver.retry/double_failure.error.message", "fibonacci.500"),
"random query");
QueryContext ctx = getQueryService().getQueryContext(handle);
while (!ctx.getStatus().finished()) {
ctx = getQueryService().getQueryContext(handle);
Thread.sleep(1000);
}
assertTrue(ctx.getStatus().successful());
assertEquals(ctx.getFailedAttempts().size(), 2);
FailedAttempt attempt1 = ctx.getFailedAttempts().get(0);
FailedAttempt attempt2 = ctx.getFailedAttempts().get(1);
assertTrue(attempt2.getDriverStartTime() - attempt1.getDriverFinishTime() >= 500);
assertTrue(ctx.getDriverStatus().getDriverStartTime() - attempt2.getDriverFinishTime() >= 1000);
}
@Test
public void testRestartWhileRetry() throws LensException, InterruptedException {
QueryHandle handle = getQueryService().executeAsync(session, "select 1",
getLensConf("driver.retry/double_failure.cost", "1",
"driver.retry/double_failure.error.message", "fibonacci.5000"),
"random query");
QueryContext ctx = getQueryService().getQueryContext(handle);
while (ctx.getFailedAttempts().size() == 0) {
ctx = getQueryService().getQueryContext(handle);
Thread.sleep(1000);
}
restartLensServer(getServerConf(), false);
ctx = getQueryService().getQueryContext(handle);
while (!ctx.getStatus().finished()) {
ctx = getQueryService().getQueryContext(handle);
Thread.sleep(1000);
}
assertTrue(ctx.getStatus().successful());
assertEquals(ctx.getFailedAttempts().size(), 2);
FailedAttempt attempt1 = ctx.getFailedAttempts().get(0);
FailedAttempt attempt2 = ctx.getFailedAttempts().get(1);
assertTrue(attempt2.getDriverStartTime() - attempt1.getDriverFinishTime() >= 5000);
assertTrue(ctx.getDriverStatus().getDriverStartTime() - attempt2.getDriverFinishTime() >= 10000);
}
}