package org.jooby.assets;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.isA;
import static org.junit.Assert.assertTrue;
import org.jooby.Env;
import org.jooby.Request;
import org.jooby.Response;
import org.jooby.Route;
import org.jooby.Route.Definition;
import org.jooby.Route.Filter;
import org.jooby.Router;
import org.jooby.handlers.AssetHandler;
import org.jooby.internal.assets.AssetHandlerWithCompiler;
import org.jooby.internal.assets.AssetVars;
import org.jooby.internal.assets.LiveCompiler;
import org.jooby.test.MockUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Binder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.multibindings.Multibinder;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValueFactory;
import javaslang.control.Try.CheckedRunnable;
@RunWith(PowerMockRunner.class)
@PrepareForTest({Assets.class, AssetCompiler.class, Multibinder.class, LiveCompiler.class })
public class AssetsTest {
@Test
public void configure() throws Exception {
Config conf = ConfigFactory.empty()
.withValue("application.path", ConfigValueFactory.fromAnyRef("/path"))
.withValue("assets.watch", ConfigValueFactory.fromAnyRef(false))
.withValue("assets.etag", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.lastModified", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.cdn", ConfigValueFactory.fromAnyRef(""))
.withValue("assets.cache.maxAge", ConfigValueFactory.fromAnyRef(-1));
new MockUnit(Env.class, Binder.class, Request.class, Response.class,
Route.Chain.class).expect(unit -> {
AssetCompiler compiler = unit.constructor(AssetCompiler.class)
.args(ClassLoader.class, Config.class)
.build(Assets.class.getClassLoader(), conf);
expect(compiler.patterns()).andReturn(Sets.newHashSet("/assets/**"));
unit.registerMock(AssetCompiler.class, compiler);
}).expect(unit -> {
Definition assetVars = unit.mock(Definition.class);
expect(assetVars.name("/assets/vars")).andReturn(assetVars);
Router routes = unit.mock(Router.class);
expect(routes.use(eq("*"), eq("*"), unit.capture(AssetVars.class))).andReturn(assetVars);
Definition assetHandlerWithCompiler = unit.mock(Definition.class);
expect(routes.get(eq("/assets/**"), isA(AssetHandlerWithCompiler.class)))
.andReturn(assetHandlerWithCompiler);
Env env = unit.get(Env.class);
expect(env.router()).andReturn(routes);
}).expect(unit -> {
Env env = unit.get(Env.class);
expect(env.name()).andReturn("dev");
}).expect(unit -> {
AssetCompiler compiler = unit.get(AssetCompiler.class);
expect(compiler.fileset()).andReturn(Sets.newHashSet("home"));
expect(compiler.styles("home")).andReturn(Lists.newArrayList("/home.css"));
expect(compiler.scripts("home")).andReturn(Lists.newArrayList("/home.js"));
Request req = unit.get(Request.class);
expect(req.set("home_css", Lists.newArrayList("/home.css"))).andReturn(req);
expect(req.set("home_styles", "<link href=\"/path/home.css\" rel=\"stylesheet\">\n"))
.andReturn(req);
expect(req.set("home_js", Lists.newArrayList("/home.js"))).andReturn(req);
expect(req.set("home_scripts", "<script src=\"/path/home.js\"></script>\n"))
.andReturn(req);
unit.get(Route.Chain.class).next(req, unit.get(Response.class));
}).run(unit -> {
new Assets()
.configure(unit.get(Env.class), conf, unit.get(Binder.class));
}, unit -> {
unit.captured(AssetVars.class).iterator().next().handle(unit.get(Request.class),
unit.get(Response.class), unit.get(Route.Chain.class));
});
}
@Test
public void configureWithWatch() throws Exception {
Config conf = ConfigFactory.empty()
.withValue("application.path", ConfigValueFactory.fromAnyRef("/"))
.withValue("assets.watch", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.etag", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.lastModified", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.cdn", ConfigValueFactory.fromAnyRef(""))
.withValue("assets.cache.maxAge", ConfigValueFactory.fromAnyRef(-1));
new MockUnit(Env.class, Binder.class, Request.class, Response.class,
Route.Chain.class).expect(unit -> {
AssetCompiler compiler = unit.constructor(AssetCompiler.class)
.args(ClassLoader.class, Config.class)
.build(Assets.class.getClassLoader(), conf);
expect(compiler.patterns()).andReturn(Sets.newHashSet("/assets/**"));
unit.registerMock(AssetCompiler.class, compiler);
}).expect(unit -> {
AssetCompiler compiler = unit.get(AssetCompiler.class);
Definition assetVars = unit.mock(Definition.class);
expect(assetVars.name("/assets/vars")).andReturn(assetVars);
Router routes = unit.mock(Router.class);
expect(routes.use(eq("*"), eq("*"), unit.capture(AssetVars.class))).andReturn(assetVars);
Definition assetHandlerWithCompiler = unit.mock(Definition.class);
expect(routes.get(eq("/assets/**"), isA(AssetHandlerWithCompiler.class)))
.andReturn(assetHandlerWithCompiler);
Definition liveCompilerRoute = unit.mock(Definition.class);
expect(liveCompilerRoute.name("/assets/compiler")).andReturn(liveCompilerRoute);
LiveCompiler liveCompiler = unit.constructor(LiveCompiler.class)
.args(Config.class, AssetCompiler.class)
.build(conf, compiler);
expect(routes.use(eq("*"), eq("*"), eq(liveCompiler))).andReturn(liveCompilerRoute);
Env env = unit.get(Env.class);
expect(env.router()).andReturn(routes);
}).expect(unit -> {
Env env = unit.get(Env.class);
expect(env.name()).andReturn("dev");
}).expect(unit -> {
Env env = unit.get(Env.class);
expect(env.onStart(isA(CheckedRunnable.class))).andReturn(env);
expect(env.onStop(isA(CheckedRunnable.class))).andReturn(env);
}).expect(unit -> {
AssetCompiler compiler = unit.get(AssetCompiler.class);
expect(compiler.fileset()).andReturn(Sets.newHashSet("home"));
expect(compiler.styles("home")).andReturn(Lists.newArrayList("/home.css"));
expect(compiler.scripts("home")).andReturn(Lists.newArrayList("/home.js"));
Request req = unit.get(Request.class);
expect(req.set("home_css", Lists.newArrayList("/home.css"))).andReturn(req);
expect(req.set("home_styles", "<link href=\"/home.css\" rel=\"stylesheet\">\n"))
.andReturn(req);
expect(req.set("home_js", Lists.newArrayList("/home.js"))).andReturn(req);
expect(req.set("home_scripts", "<script src=\"/home.js\"></script>\n")).andReturn(req);
unit.get(Route.Chain.class).next(req, unit.get(Response.class));
}).run(unit -> {
new Assets()
.configure(unit.get(Env.class), conf, unit.get(Binder.class));
}, unit -> {
unit.captured(AssetVars.class).iterator().next().handle(unit.get(Request.class),
unit.get(Response.class), unit.get(Route.Chain.class));
});
}
@Test
public void configureWithoutWatch() throws Exception {
Config conf = ConfigFactory.empty()
.withValue("application.path", ConfigValueFactory.fromAnyRef("/"))
.withValue("assets.watch", ConfigValueFactory.fromAnyRef(false))
.withValue("assets.etag", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.lastModified", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.cdn", ConfigValueFactory.fromAnyRef(""))
.withValue("assets.cache.maxAge", ConfigValueFactory.fromAnyRef(-1));
new MockUnit(Env.class, Binder.class, Request.class, Response.class,
Route.Chain.class).expect(unit -> {
AssetCompiler compiler = unit.constructor(AssetCompiler.class)
.args(ClassLoader.class, Config.class)
.build(Assets.class.getClassLoader(), conf);
expect(compiler.patterns()).andReturn(Sets.newHashSet("/assets/**"));
unit.registerMock(AssetCompiler.class, compiler);
}).expect(unit -> {
Definition assetVars = unit.mock(Definition.class);
expect(assetVars.name("/assets/vars")).andReturn(assetVars);
Router routes = unit.mock(Router.class);
expect(routes.use(eq("*"), eq("*"), unit.capture(AssetVars.class))).andReturn(assetVars);
Definition assetHandlerWithCompiler = unit.mock(Definition.class);
expect(routes.get(eq("/assets/**"), isA(AssetHandlerWithCompiler.class)))
.andReturn(assetHandlerWithCompiler);
Env env = unit.get(Env.class);
expect(env.router()).andReturn(routes);
}).expect(unit -> {
Env env = unit.get(Env.class);
expect(env.name()).andReturn("dev");
}).expect(unit -> {
AssetCompiler compiler = unit.get(AssetCompiler.class);
expect(compiler.fileset()).andReturn(Sets.newHashSet("home"));
expect(compiler.styles("home")).andReturn(Lists.newArrayList("/home.css"));
expect(compiler.scripts("home")).andReturn(Lists.newArrayList("/home.js"));
Request req = unit.get(Request.class);
expect(req.set("home_css", Lists.newArrayList("/home.css"))).andReturn(req);
expect(req.set("home_styles", "<link href=\"/home.css\" rel=\"stylesheet\">\n"))
.andReturn(req);
expect(req.set("home_js", Lists.newArrayList("/home.js"))).andReturn(req);
expect(req.set("home_scripts", "<script src=\"/home.js\"></script>\n")).andReturn(req);
unit.get(Route.Chain.class).next(req, unit.get(Response.class));
}).run(unit -> {
new Assets()
.configure(unit.get(Env.class), conf, unit.get(Binder.class));
}, unit -> {
unit.captured(AssetVars.class).iterator().next().handle(unit.get(Request.class),
unit.get(Response.class), unit.get(Route.Chain.class));
});
}
@Test
public void configuredist() throws Exception {
Config conf = ConfigFactory.empty()
.withValue("application.env", ConfigValueFactory.fromAnyRef("prod"))
.withValue("assets.etag", ConfigValueFactory.fromAnyRef(true))
.withValue("application.path", ConfigValueFactory.fromAnyRef("/"))
.withValue("assets.cdn", ConfigValueFactory.fromAnyRef(""))
.withValue("assets.cache.maxAge", ConfigValueFactory.fromAnyRef("365d"))
.withValue("assets.lastModified", ConfigValueFactory.fromAnyRef(true))
.withValue("assets.watch", ConfigValueFactory.fromAnyRef(false));
new MockUnit(Env.class, Config.class, Binder.class, Request.class, Response.class,
Route.Chain.class, AssetCompiler.class).expect(unit -> {
AssetCompiler compiler = unit.constructor(AssetCompiler.class)
.args(ClassLoader.class, Config.class)
.build(Assets.class.getClassLoader(), conf);
expect(compiler.patterns()).andReturn(Sets.newHashSet("/assets/**"));
unit.registerMock(AssetCompiler.class, compiler);
}).expect(unit -> {
Definition assetVars = unit.mock(Definition.class);
expect(assetVars.name("/assets/vars")).andReturn(assetVars);
Router routes = unit.mock(Router.class);
expect(routes.use(eq("*"), eq("*"), unit.capture(AssetVars.class))).andReturn(assetVars);
Definition assetHandlerWithCompiler = unit.mock(Definition.class);
expect(routes.get(eq("/assets/**"), isA(AssetHandler.class)))
.andReturn(assetHandlerWithCompiler);
Env env = unit.get(Env.class);
expect(env.router()).andReturn(routes);
}).expect(unit -> {
Env env = unit.get(Env.class);
expect(env.name()).andReturn("prod");
}).expect(unit -> {
AssetCompiler compiler = unit.get(AssetCompiler.class);
expect(compiler.fileset()).andReturn(Sets.newHashSet("home"));
expect(compiler.styles("home")).andReturn(Lists.newArrayList("/home.css"));
expect(compiler.scripts("home")).andReturn(Lists.newArrayList("/home.js"));
Request req = unit.get(Request.class);
expect(req.set("home_css", Lists.newArrayList("/home.css"))).andReturn(req);
expect(req.set("home_styles", "<link href=\"/home.css\" rel=\"stylesheet\">\n"))
.andReturn(req);
expect(req.set("home_js", Lists.newArrayList("/home.js"))).andReturn(req);
expect(req.set("home_scripts", "<script src=\"/home.js\"></script>\n")).andReturn(req);
unit.get(Route.Chain.class).next(req, unit.get(Response.class));
}).run(unit -> {
new Assets()
.configure(unit.get(Env.class), conf, unit.get(Binder.class));
}, unit -> {
unit.captured(AssetVars.class).iterator().next().handle(unit.get(Request.class),
unit.get(Response.class), unit.get(Route.Chain.class));
});
}
@SuppressWarnings("unchecked")
@Test(expected = RuntimeException.class)
public void configureFails() throws Exception {
Config conf = ConfigFactory.empty();
new MockUnit(Env.class, Config.class, Binder.class, Request.class, Response.class,
Route.Chain.class, AssetCompiler.class).expect(unit -> {
AssetCompiler compiler = unit.constructor(AssetCompiler.class)
.args(ClassLoader.class, Config.class)
.build(Assets.class.getClassLoader(), conf);
expect(compiler.patterns()).andThrow(new RuntimeException());
unit.registerMock(AssetCompiler.class, compiler);
}).expect(unit -> {
Binder binder = unit.get(Binder.class);
LinkedBindingBuilder<Definition> varsLBB = unit.mock(LinkedBindingBuilder.class);
varsLBB.toInstance(unit.capture(Route.Definition.class));
LinkedBindingBuilder<Definition> handlerLBB = unit.mock(LinkedBindingBuilder.class);
handlerLBB.toInstance(unit.capture(Route.Definition.class));
Multibinder<Definition> mb = unit.mock(Multibinder.class);
expect(mb.addBinding()).andReturn(varsLBB);
expect(mb.addBinding()).andReturn(handlerLBB);
unit.mockStatic(Multibinder.class);
expect(Multibinder.newSetBinder(binder, Route.Definition.class)).andReturn(mb);
}).expect(unit -> {
Env env = unit.get(Env.class);
expect(env.name()).andReturn("dev");
}).expect(unit -> {
AssetCompiler compiler = unit.get(AssetCompiler.class);
expect(compiler.fileset()).andReturn(Sets.newHashSet("home"));
expect(compiler.styles("home")).andReturn(Lists.newArrayList("/home.css"));
expect(compiler.scripts("home")).andReturn(Lists.newArrayList("/home.js"));
Request req = unit.get(Request.class);
expect(req.set("home_css", Lists.newArrayList("/home.css"))).andReturn(req);
expect(req.set("home_styles", "<link href=\"/home.css\" rel=\"stylesheet\">\n"))
.andReturn(req);
expect(req.set("home_js", Lists.newArrayList("/home.js"))).andReturn(req);
expect(req.set("home_scripts", "<script src=\"/home.js\"></script>\n")).andReturn(req);
unit.get(Route.Chain.class).next(req, unit.get(Response.class));
}).run(unit -> {
new Assets()
.configure(unit.get(Env.class), conf, unit.get(Binder.class));
}, unit -> {
Filter handler = unit.captured(Route.Definition.class).iterator().next().filter();
handler.handle(unit.get(Request.class), unit.get(Response.class),
unit.get(Route.Chain.class));
}, unit -> {
Filter handler = unit.captured(Route.Definition.class).get(1).filter();
assertTrue(handler instanceof AssetHandlerWithCompiler);
});
}
}