/* * 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.cyclop.service.queryprotocoling.intern; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.inject.Inject; import org.cyclop.model.CqlQuery; import org.cyclop.model.CqlQueryType; import org.cyclop.model.QueryEntry; import org.cyclop.model.QueryHistory; import org.cyclop.model.UserIdentifier; import org.cyclop.model.exception.BeanValidationException; import org.cyclop.service.common.FileStorage; import org.cyclop.test.AbstractTestCase; import org.cyclop.test.ThreadTestScope; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.google.common.collect.ImmutableList; /** @author Maciej Miklas */ public class TestHistoryService extends AbstractTestCase { public static String CR = System.getProperty("line.separator"); @Inject private HistoryServiceImpl historyService; @Inject private AsyncFileStore<QueryHistory> asyncFileStore; private UserIdentifier user; @Inject private FileStorage storage; @Inject private ThreadTestScope threadTestScope; @After public void cleanUp() throws Exception { super.cleanUp(); threadTestScope.setSingleThread(false); } @Before public void setup() throws Exception { super.setup(); asyncFileStore.flush(); QueryHistory history = historyService.read(); assertNotNull(history); history.clear(); assertEquals(0, history.size()); user = historyService.getUser(); assertNotNull(user); assertNotNull(user.id); } @Test public void testCreateReadAndClear() throws Exception { QueryHistory history = historyService.read(); for (int i = 0; i < 600; i++) { historyService.addAndStore(new QueryEntry(new CqlQuery(CqlQueryType.SELECT, "select * " + CR + "from HistoryTest where " + CR + "id=" + i), 1000 + i)); QueryHistory historyQueue = asyncFileStore.getFromWriteQueue(user).get(); assertNotNull(historyQueue); // should be the same instance assertSame(history, historyQueue); } assertEquals(500, history.size()); asyncFileStore.flush(); assertFalse(asyncFileStore.getFromWriteQueue(user).isPresent()); assertSame(history, historyService.read()); QueryHistory readHist = storage.read(user, QueryHistory.class).get(); assertNotSame(history, readHist); for (int i = 100; i < 600; i++) { QueryEntry tofind = new QueryEntry(new CqlQuery(CqlQueryType.SELECT, "select * from HistoryTest where id=" + i), 2000 + i); assertTrue(tofind + " NOT FOUND IN: " + readHist, readHist.contains(tofind)); ImmutableList<QueryEntry> readList = readHist.copyAsList(); int index = readList.indexOf(tofind); assertTrue(index >= 0); QueryEntry read = readList.get(index); assertNotNull(read.executedOnUtc); assertEquals(1000 + i, read.runTime); } { history.clear(); assertEquals(0, history.size()); historyService.store(history); asyncFileStore.flush(); assertEquals(0, storage.read(user, QueryHistory.class).get().size()); } } @Test(expected = BeanValidationException.class) public void testAddAndStore_NullParams() { historyService.addAndStore(null); } @Test(expected = BeanValidationException.class) public void testAddAndStore_InvalidParams() { historyService.addAndStore(new QueryEntry(new CqlQuery(null, null), 1)); } @Test(expected = BeanValidationException.class) public void testStore_InvalidParams() { historyService.store(null); } @Test public void testMultiThreadForMultipleUsers() throws Exception { threadTestScope.setSingleThread(false); Set<QueryHistory> histories = executeMultiThreadTest(300); assertEquals(3, histories.size()); } @Test public void testMultiThreadForSingleUsers() throws Exception { threadTestScope.setSingleThread(true); Set<QueryHistory> histories = executeMultiThreadTest(100); assertEquals(1, histories.size()); } public Set<QueryHistory> executeMultiThreadTest(final int repeatInTest) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(3); final Set<QueryHistory> histories = Collections.synchronizedSet(new HashSet<QueryHistory>()); List<Callable<Void>> tasks = new ArrayList<>(3); final AtomicInteger executedCount = new AtomicInteger(0); for (int i = 0; i < 3; i++) { tasks.add(new Callable<Void>() { @Override public Void call() throws Exception { for (int i = 0; i < repeatInTest; i++) { QueryHistory history = historyService.read(); histories.add(history); QueryEntry histEntry = new QueryEntry(new CqlQuery(CqlQueryType.SELECT, "select * from MyTable2 where id=" + UUID.randomUUID()), 4000 + i); history.add(histEntry); verifyHistEntry(history, histEntry); historyService.store(history); if (i % 20 == 0) { asyncFileStore.flush(); } QueryHistory readHist = historyService.read(); verifyHistEntry(readHist, histEntry); executedCount.incrementAndGet(); assertEquals(0, storage.getLockRetryCount()); } return null; } void verifyHistEntry(QueryHistory history, QueryEntry histEntry) { assertNotNull(history); assertTrue("History (" + executedCount + "):" + histEntry + " not found in: " + history, history.contains(histEntry)); } }); } List<Future<Void>> results = executor.invokeAll(tasks); executor.shutdown(); executor.awaitTermination(5, TimeUnit.MINUTES); for (Future<Void> result : results) { result.get(); } assertEquals(3 * repeatInTest, executedCount.get()); return histories; } } /* */