/**
* 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.shindig.gadgets.preload;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import org.apache.shindig.common.testing.TestExecutorService;
import org.apache.shindig.gadgets.Gadget;
import org.junit.Test;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
/**
* Tests for FuturePreloaderService.
*/
public class ConcurrentPreloaderServiceTest {
private static final String PRELOAD_STRING_KEY = "key a";
private static final String PRELOAD_NUMERIC_KEY = "key b";
private static final String PRELOAD_MAP_KEY = "key c";
private static final String PRELOAD_STRING_VALUE = "Some random string";
private static final Integer PRELOAD_NUMERIC_VALUE = 5;
private static final Map<String, String> PRELOAD_MAP_VALUE
= ImmutableMap.of("foo", "bar", "baz", "blah");
private final TestPreloader preloader = new TestPreloader();
@Test
public void preloadSingleService() throws Exception {
preloader.tasks.add(new TestPreloadCallable(
new DataPreload(PRELOAD_STRING_KEY, PRELOAD_STRING_VALUE)));
PreloaderService service = new ConcurrentPreloaderService(new TestExecutorService(),
preloader);
Collection<PreloadedData> preloads = service.preload((Gadget) null);
Collection<Object> preloaded = getAll(preloads);
assertEquals(ImmutableMap.of(PRELOAD_STRING_KEY, PRELOAD_STRING_VALUE),
preloaded.iterator().next());
}
/** Load all the data out of a preloads object */
private Collection<Object> getAll(Collection<PreloadedData> preloads) throws PreloadException {
List<Object> list = Lists.newArrayList();
for (PreloadedData preloadCallable : preloads) {
list.addAll(preloadCallable.toJson());
}
return list;
}
@Test
public void preloadMultipleServices() throws PreloadException {
preloader.tasks.add(new TestPreloadCallable(
new DataPreload(PRELOAD_STRING_KEY, PRELOAD_STRING_VALUE)));
preloader.tasks.add(new TestPreloadCallable(
new DataPreload(PRELOAD_NUMERIC_KEY, PRELOAD_NUMERIC_VALUE)));
preloader.tasks.add(new TestPreloadCallable(
new DataPreload(PRELOAD_MAP_KEY, PRELOAD_MAP_VALUE)));
PreloaderService service = new ConcurrentPreloaderService(new TestExecutorService(),
preloader);
Collection<PreloadedData> preloads =
service.preload((Gadget) null);
Collection<Object> preloaded = getAll(preloads);
assertEquals(ImmutableList.<Object>of(
ImmutableMap.of(PRELOAD_STRING_KEY, PRELOAD_STRING_VALUE),
ImmutableMap.of(PRELOAD_NUMERIC_KEY, PRELOAD_NUMERIC_VALUE),
ImmutableMap.of(PRELOAD_MAP_KEY, PRELOAD_MAP_VALUE)), preloaded);
}
@Test
public void multiplePreloadsFiresJustOneInCurrentThread() throws Exception {
TestPreloadCallable first =
new TestPreloadCallable(new DataPreload(PRELOAD_STRING_KEY, PRELOAD_STRING_VALUE));
TestPreloadCallable second =
new TestPreloadCallable(new DataPreload(PRELOAD_NUMERIC_KEY, PRELOAD_MAP_VALUE));
TestPreloadCallable third =
new TestPreloadCallable(new DataPreload(PRELOAD_MAP_KEY, PRELOAD_NUMERIC_VALUE));
preloader.tasks.add(first);
preloader.tasks.add(second);
preloader.tasks.add(third);
PreloaderService service = new ConcurrentPreloaderService(Executors.newFixedThreadPool(5),
preloader);
service.preload((Gadget) null);
TestPreloadCallable ranInSameThread = null;
for (TestPreloadCallable preloadCallable: Lists.newArrayList(first, second, third)) {
if (preloadCallable.executedThread == Thread.currentThread()) {
if (ranInSameThread != null) {
fail("More than one request ran in the current thread.");
}
ranInSameThread = preloadCallable;
}
}
assertNotNull("No preloads executed in the current thread. ", ranInSameThread);
}
@Test
public void singlePreloadExecutesInCurrentThread() throws Exception {
TestPreloadCallable callable =
new TestPreloadCallable(new DataPreload(PRELOAD_STRING_KEY, PRELOAD_STRING_VALUE));
preloader.tasks.add(callable);
PreloaderService service = new ConcurrentPreloaderService(Executors.newCachedThreadPool(),
preloader);
service.preload((Gadget) null);
assertSame("Single request not run in current thread",
Thread.currentThread(), callable.executedThread);
}
private static class TestPreloader implements Preloader {
protected final Collection<Callable<PreloadedData>> tasks = Lists.newArrayList();
protected TestPreloader() {
}
public Collection<Callable<PreloadedData>> createPreloadTasks(
Gadget gadget) {
return tasks;
}
}
private static class TestPreloadCallable implements Callable<PreloadedData> {
private final PreloadedData preload;
public Thread executedThread;
public TestPreloadCallable(PreloadedData preload) {
this.preload = preload;
}
public PreloadedData call() throws Exception {
executedThread = Thread.currentThread();
if (preload == null) {
throw new PreloadException("No preload for this test.");
}
return preload;
}
}
private static class DataPreload implements PreloadedData {
private final String key;
private final Object data;
public DataPreload(String key, Object data) {
this.key = key;
this.data = data;
}
public Collection<Object> toJson() {
return ImmutableList.of((Object) ImmutableMap.of(key, data));
}
}
}