diff options
Diffstat (limited to 'application')
17 files changed, 605 insertions, 589 deletions
diff --git a/application/pom.xml b/application/pom.xml index db298451a8b..ac9ba96cb27 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,6 +20,10 @@ <version>${project.version}</version> </dependency> <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-library</artifactId> + </dependency> + <dependency> <groupId>com.yahoo.vespa</groupId> <artifactId>config-provisioning</artifactId> <version>${project.version}</version> @@ -72,6 +76,11 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.scala-lang.modules</groupId> + <artifactId>scala-xml_${scala.major-version}</artifactId> + <scope>test</scope> + </dependency> <!-- All dependencies that should be visible in test classpath, but not compile classpath, for user projects must be added in compile scope here. @@ -158,6 +167,19 @@ </configuration> </plugin> <plugin> + <groupId>net.alchim31.maven</groupId> + <artifactId>scala-maven-plugin</artifactId> + <executions> + <execution> + <id>scala-test-compile</id> + <phase>process-test-resources</phase> + <goals> + <goal>testCompile</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> diff --git a/application/src/test/java/com/yahoo/application/ApplicationBuilderTest.java b/application/src/test/java/com/yahoo/application/ApplicationBuilderTest.java deleted file mode 100644 index 62b5fc9e1a8..00000000000 --- a/application/src/test/java/com/yahoo/application/ApplicationBuilderTest.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application; - -import com.yahoo.io.IOUtils; -import org.junit.Test; - -import java.nio.file.Files; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * @author Tony Vaagenes - * @author ovirtanen - */ -public class ApplicationBuilderTest { - @Test - public void query_profile_types_can_be_added() throws Exception { - withApplicationBuilder(builder -> { - builder.queryProfileType("MyProfileType", "<query-profile-type id=\"MyProfileType\">" + // - "<field name=\"age\" type=\"integer\" />" + // - "<field name=\"profession\" type=\"string\" />" + // - "<field name=\"user\" type=\"query-profile:MyUserProfile\" />" + // - "</query-profile-type>"); - - assertTrue(Files.exists(builder.getPath().resolve("search/query-profiles/types/MyProfileType.xml"))); - }); - } - - @Test - public void query_profile_can_be_added() throws Exception { - withApplicationBuilder(builder -> { - builder.queryProfile("MyProfile", "<query-profile id=\"MyProfile\">" + // - "<field name=\"message\">Hello world!</field>" + // - "</query-profile>"); - - assertTrue(Files.exists(builder.getPath().resolve("search/query-profiles/MyProfile.xml"))); - }); - } - - @Test - public void rank_expression_can_be_added() throws Exception { - withApplicationBuilder(builder -> { - builder.rankExpression("myExpression", "content"); - assertTrue(Files.exists(builder.getPath().resolve("searchdefinitions/myExpression.expression"))); - }); - } - - @Test - public void builder_cannot_be_reused() throws Exception { - try { - ApplicationBuilder builder = new ApplicationBuilder(); - builder.servicesXml("<jdisc version=\"1.0\" />"); - builder.build(); - - builder.servicesXml(""); - fail("Expected exception."); - } catch (RuntimeException e) { - assertThat(e.getMessage(), containsString("build method")); - } - - } - - private interface TestCase { - public void accept(ApplicationBuilder ab) throws Exception; - } - - public void withApplicationBuilder(TestCase f) throws Exception { - ApplicationBuilder builder = new ApplicationBuilder(); - try { - f.accept(builder); - } finally { - IOUtils.recursiveDeleteDir(builder.getPath().toFile()); - } - } -} diff --git a/application/src/test/java/com/yahoo/application/container/JDiscContainerSearchTest.java b/application/src/test/java/com/yahoo/application/container/JDiscContainerSearchTest.java deleted file mode 100644 index b94b4a67c67..00000000000 --- a/application/src/test/java/com/yahoo/application/container/JDiscContainerSearchTest.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container; - -import com.yahoo.application.Networking; -import com.yahoo.application.container.searchers.AddHitSearcher; -import com.yahoo.component.ComponentSpecification; -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -/** - * @author gjoranv - * @author ovirtanen - */ -public class JDiscContainerSearchTest { - @Test - public void processing_and_rendering_works() throws Exception { - final String searcherId = AddHitSearcher.class.getName(); - - try (JDisc container = containerWithSearch(searcherId)) { - byte[] rendered = container.search().processAndRender(ComponentSpecification.fromString("mychain"), - ComponentSpecification.fromString("DefaultRenderer"), new Query("")); - String renderedAsString = new String(rendered, "utf-8"); - assertThat(renderedAsString, containsString(searcherId)); - } - } - - @Test - public void searching_works() throws Exception { - final String searcherId = AddHitSearcher.class.getName(); - - try (JDisc container = containerWithSearch(searcherId)) { - Search searching = container.search(); - Result result = searching.process(ComponentSpecification.fromString("mychain"), new Query("")); - String hitTitle = result.hits().get(0).getField("title").toString(); - assertThat(hitTitle, is(searcherId)); - } - } - - public JDisc containerWithSearch(String searcherId) { - return JDisc.fromServicesXml("<container version=\"1.0\">" + // - "<search>" + // - "<chain id=\"mychain\">" + // - "<searcher id=\"" + searcherId + "\"/>" + // - "</chain>" + // - "</search>" + // - "</container>", Networking.disable); - } - - @Test(expected = UnsupportedOperationException.class) - public void retrieving_search_from_container_without_search_is_illegal() throws Exception { - try (JDisc container = JDisc.fromServicesXml("<container version=\"1.0\" />", Networking.disable)) { - container.search(); // throws - } - } -} diff --git a/application/src/test/java/com/yahoo/application/container/JDiscTest.java b/application/src/test/java/com/yahoo/application/container/JDiscTest.java deleted file mode 100644 index 3526708c84a..00000000000 --- a/application/src/test/java/com/yahoo/application/container/JDiscTest.java +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container; - -import com.yahoo.application.Application; -import com.yahoo.application.ApplicationBuilder; -import com.yahoo.application.Networking; -import com.yahoo.application.container.handler.Request; -import com.yahoo.application.container.handler.Response; -import com.yahoo.application.container.handlers.TestHandler; -import com.yahoo.component.ComponentSpecification; -import com.yahoo.container.Container; -import com.yahoo.jdisc.http.server.jetty.JettyHttpServer; -import com.yahoo.jdisc.service.ServerProvider; -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import org.junit.Ignore; -import org.junit.Test; - -import java.nio.charset.CharacterCodingException; -import java.nio.file.FileSystems; - -import static com.yahoo.application.container.JDisc.fromServicesXml; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -/** - * @author Tony Vaagenes - * @author gjoranv - * @author ovirtanen - */ -public class JDiscTest { - @Test - public void jdisc_can_be_used_as_top_level_element() throws Exception { - try (JDisc container = fromServicesXml("<jdisc version=\"1.0\">" + // - "<search />" + // - "</jdisc>", Networking.disable)) { - assertNotNull(container.search()); - } - } - - @Test - public void jdisc_id_can_be_set() throws Exception { - try (JDisc container = fromServicesXml("<jdisc version=\"1.0\" id=\"my-service-id\">" + // - "<search />" + // - "</jdisc>", Networking.disable)) { - assertNotNull(container.search()); - } - } - - @Test - public void jdisc_can_be_embedded_in_services_tag() throws Exception { - try (JDisc container = fromServicesXml("<services>" + // - "<jdisc version=\"1.0\" id=\"my-service-id\">" + // - "<search />" + // - "</jdisc>" + // - "</services>", Networking.disable)) { - assertNotNull(container.search()); - } - } - - @Test - @SuppressWarnings("try") // container is unused inside the try block - public void multiple_jdisc_elements_gives_exception() { - try (JDisc container = fromServicesXml("<services>" + // - "<jdisc version=\"1.0\" id=\"id1\" />" + // - "<jdisc version=\"1.0\" />" + // - "<container version=\"1.0\"/>" + // - "</services>", Networking.disable)) { - fail("expected exception"); - } catch (Exception e) { - assertThat(e.getMessage(), containsString("container id='', jdisc id='id1', jdisc id=''")); - } - } - - @Test - public void handleRequest_yields_response_from_correct_request_handler() throws Exception { - final String handlerClass = TestHandler.class.getName(); - try (JDisc container = fromServicesXml("<container version=\"1.0\">" + // - "<handler id=\"test-handler\" class=\"" + handlerClass + "\">" + // - "<binding>http://*/TestHandler</binding>" + // - "</handler>" + // - "</container>", Networking.disable)) { - Response response = container.handleRequest(new Request("http://foo/TestHandler")); - try { - assertThat(response.getBodyAsString(), is(TestHandler.RESPONSE)); - } catch (CharacterCodingException e) { - throw new RuntimeException(e); - } - } - } - - @Test - public void load_searcher_from_bundle() throws Exception { - try (JDisc container = JDisc.fromPath(FileSystems.getDefault().getPath("src/test/app-packages/searcher-app"), - Networking.disable)) { - Result result = container.search().process(ComponentSpecification.fromString("default"), - new Query("?query=ignored")); - assertThat(result.hits().get(0).getField("title").toString(), is("Heal the World!")); - } - } - - @Test - public void document_types_can_be_accessed() throws Exception { - try (Application application = new ApplicationBuilder().documentType("example", EXAMPLE_DOCUMENT) - .servicesXml(CONTAINER_WITH_DOCUMENT_PROCESSING).build()) { - JDisc container = application.getJDisc("jdisc"); - DocumentProcessing processing = container.documentProcessing(); - assertThat(processing.getDocumentTypes().keySet(), hasItem("example")); - } - } - - @Test - public void annotation_types_can_be_accessed() throws Exception { - try (Application application = new ApplicationBuilder().documentType("example", "search example {\n" + // - " " + EXAMPLE_DOCUMENT + "\n" + // - " annotation exampleAnnotation {}\n" + // - "}\n").// - servicesXml(CONTAINER_WITH_DOCUMENT_PROCESSING).build()) { - JDisc container = application.getJDisc("jdisc"); - DocumentProcessing processing = container.documentProcessing(); - assertThat(processing.getAnnotationTypes().keySet(), hasItem("exampleAnnotation")); - } - } - - @Ignore // Enable this when static state has been removed. - @Test - public void multiple_containers_can_be_run_in_parallel() throws Exception { - try (JDisc jdisc1 = jdiscWithHttp(); JDisc jdisc2 = jdiscWithHttp()) { - sendRequest(jdisc1); - sendRequest(jdisc2); - } - } - - private void sendRequest(JDisc jdisc) throws CharacterCodingException { - Response response = jdisc.handleRequest(new Request("http://foo/TestHandler")); - assertThat(response.getBodyAsString(), is(TestHandler.RESPONSE)); - } - - public static final String CONTAINER_WITH_DOCUMENT_PROCESSING = // - "<jdisc version=\"1.0\">" + // - "<http />" + // - "<document-processing />" + // - "</jdisc>"; - - public static final String EXAMPLE_DOCUMENT = // - "document example {\n" + // - "\n" + // - " field title type string {\n" + // - " indexing: summary | index # How this field should be indexed\n" + // - " weight: 75 # Ranking importancy of this field, used by the built in nativeRank feature\n" + // - " header\n" + // - " }\n" + // - "}\n"; - - protected JDisc jdiscWithHttp() { - final String handlerId = TestHandler.class.getName(); - final String xml = // - "<jdisc version=\"1.0\">" + // - "<handler id=" + handlerId + " />" + // - "<http>\n" + // - "<server id=\"main\" port=\"9999\" />\n" + // - "</http>\n" + // - "</jdisc>"; - return JDisc.fromServicesXml(xml, Networking.disable); - } - - public static int getListenPort() { - for (ServerProvider server : Container.get().getServerProviderRegistry().allComponents()) { - if (null != server && server instanceof JettyHttpServer) { - return ((JettyHttpServer) server).getListenPort(); - } - } - throw new RuntimeException("No http server found"); - } -} diff --git a/application/src/test/java/com/yahoo/application/container/handlers/TestHandler.java b/application/src/test/java/com/yahoo/application/container/handlers/TestHandler.java deleted file mode 100644 index 6da8783cf86..00000000000 --- a/application/src/test/java/com/yahoo/application/container/handlers/TestHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container.handlers; - -import com.yahoo.jdisc.handler.AbstractRequestHandler; -import com.yahoo.jdisc.handler.ContentChannel; -import com.yahoo.jdisc.handler.FastContentWriter; -import com.yahoo.jdisc.handler.ResponseDispatch; -import com.yahoo.jdisc.handler.ResponseHandler; - -/** - * @author gjoranv - * @author ovirtanen - */ -public class TestHandler extends AbstractRequestHandler { - public static final String RESPONSE = "Hello, World!"; - - public ContentChannel handleRequest(com.yahoo.jdisc.Request request, ResponseHandler handler) { - FastContentWriter writer = ResponseDispatch.newInstance(com.yahoo.jdisc.Response.Status.OK) - .connectFastWriter(handler); - writer.write(RESPONSE); - writer.close(); - return null; - } - -} diff --git a/application/src/test/java/com/yahoo/application/container/jersey/JerseyTest.java b/application/src/test/java/com/yahoo/application/container/jersey/JerseyTest.java deleted file mode 100644 index e85bd6ba4d9..00000000000 --- a/application/src/test/java/com/yahoo/application/container/jersey/JerseyTest.java +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container.jersey; - -import com.yahoo.application.Networking; -import com.yahoo.application.container.JDisc; -import com.yahoo.application.container.JDiscTest; -import com.yahoo.application.container.jersey.resources.TestResource; -import com.yahoo.application.container.jersey.resources.nestedpackage1.NestedTestResource1; -import com.yahoo.application.container.jersey.resources.nestedpackage2.NestedTestResource2; -import com.yahoo.container.test.jars.jersey.resources.TestResourceBase; -import com.yahoo.osgi.maven.ProjectBundleClassPaths; -import com.yahoo.osgi.maven.ProjectBundleClassPaths.BundleClasspathMapping; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.util.EntityUtils; -import org.junit.Test; - -import javax.ws.rs.core.UriBuilder; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static java.util.Collections.emptyList; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * @author Tony Vaagenes - * @author ovirtanen - */ -public class JerseyTest { - private final Path testJar = Paths.get("target/test-jars/jersey-resources.jar"); - private final String testClassesDirectory = "target/test-classes"; - private final String bundleSymbolicName = "myBundle"; - - private static final Set<Class<? extends TestResourceBase>> classPathResources; - private static final Set<Class<? extends TestResourceBase>> jarFileResources; - - static { - classPathResources = new HashSet<>(); - classPathResources.add(TestResource.class); - classPathResources.add(NestedTestResource1.class); - classPathResources.add(NestedTestResource2.class); - - jarFileResources = new HashSet<>(); - jarFileResources.add(com.yahoo.container.test.jars.jersey.resources.TestResource.class); - jarFileResources.add(com.yahoo.container.test.jars.jersey.resources.nestedpackage1.NestedTestResource1.class); - jarFileResources.add(com.yahoo.container.test.jars.jersey.resources.nestedpackage2.NestedTestResource2.class); - } - - @Test - public void jersey_resources_on_classpath_can_be_invoked_from_application() throws Exception { - saveMainBundleClassPathMappings(testClassesDirectory); - - with_jersey_resources(emptyList(), httpGetter -> assertResourcesResponds(classPathResources, httpGetter)); - } - - @Test - public void jersey_resources_in_provided_dependencies_can_be_invoked_from_application() throws Exception { - BundleClasspathMapping providedDependency = new BundleClasspathMapping(bundleSymbolicName, - Arrays.asList(testClassesDirectory)); - - save(new ProjectBundleClassPaths(new BundleClasspathMapping("main", emptyList()), - Arrays.asList(providedDependency))); - with_jersey_resources(emptyList(), httpGetter -> assertResourcesResponds(classPathResources, httpGetter)); - } - - @Test - public void jersey_resource_on_classpath_can_be_filtered_using_packages() throws Exception { - saveMainBundleClassPathMappings(testClassesDirectory); - - with_jersey_resources(Arrays.asList("com.yahoo.application.container.jersey.resources", - "com.yahoo.application.container.jersey.resources.nestedpackage1"), httpGetter -> { - Class<NestedTestResource2> nestedResource2 = NestedTestResource2.class; - assertDoesNotRespond(nestedResource2, httpGetter); - assertResourcesResponds(copySetExcept(classPathResources, nestedResource2), httpGetter); - }); - } - - @Test - public void jersey_resource_in_jar_can_be_invoked_from_application() throws Exception { - saveMainBundleJarClassPathMappings(testJar); - - with_jersey_resources(emptyList(), httpGetter -> assertResourcesResponds(jarFileResources, httpGetter)); - } - - @Test - public void jersey_resource_in_jar_can_be_filtered_using_packages() throws Exception { - saveMainBundleJarClassPathMappings(testJar); - - with_jersey_resources(Arrays.asList("com.yahoo.container.test.jars.jersey.resources", - "com.yahoo.container.test.jars.jersey.resources.nestedpackage1"), httpGetter -> { - Class<com.yahoo.container.test.jars.jersey.resources.nestedpackage2.NestedTestResource2> nestedResource2 = com.yahoo.container.test.jars.jersey.resources.nestedpackage2.NestedTestResource2.class; - - assertDoesNotRespond(nestedResource2, httpGetter); - assertResourcesResponds(copySetExcept(jarFileResources, nestedResource2), httpGetter); - }); - } - - private static <T> Set<T> copySetExcept(Set<T> in, T except) { - Set<T> ret = new HashSet<>(in); - ret.remove(except); - return ret; - } - - private interface ThrowingConsumer<T> { - public void accept(T arg) throws Exception; - } - - private interface HttpGetter { - public HttpResponse get(String path) throws Exception; - } - - @SuppressWarnings("try") // jdisc unused inside try-with-resources - private void with_jersey_resources(List<String> packagesToScan, ThrowingConsumer<HttpGetter> f) throws Exception { - StringBuffer packageElements = new StringBuffer(); - for (String p : packagesToScan) { - packageElements.append("<package>"); - packageElements.append(p); - packageElements.append("</package>"); - } - - try (JDisc jdisc = JDisc.fromServicesXml( - "<services>" + // - "<jdisc version=\"1.0\" id=\"default\" jetty=\"true\">" + // - "<rest-api path=\"rest-api\" jersey2=\"true\">" + // - "<components bundle=\"" + bundleSymbolicName + "\">" + // - packageElements + // - "</components>" + // - "</rest-api>" + // - "<http>" + // - "<server id=\"mainServer\" port=\"0\" />" + // - "</http>" + // - "</jdisc>" + // - "</services>", // - Networking.enable)) { - final int port = JDiscTest.getListenPort(); - f.accept(path -> { - String p = path.startsWith("/") ? path.substring(1) : path; - CloseableHttpClient client = HttpClientBuilder.create().build(); - return client.execute(new HttpGet("http://localhost:" + port + "/rest-api/" + p)); - }); - } - } - - public void assertResourcesResponds(Collection<Class<? extends TestResourceBase>> resourceClasses, - HttpGetter httpGetter) throws Exception { - for (Class<? extends TestResourceBase> resource : resourceClasses) { - HttpResponse response = httpGetter.get(path(resource)); - assertThat("Failed sending response to " + resource, response.getStatusLine().getStatusCode(), is(200)); - - String content = IOUtils.toString(response.getEntity().getContent()); - assertThat(content, is(TestResourceBase.content(resource))); - } - } - - public void assertDoesNotRespond(Class<? extends TestResourceBase> resourceClass, HttpGetter httpGetter) - throws Exception { - HttpResponse response = httpGetter.get(path(resourceClass)); - assertThat(response.getStatusLine().getStatusCode(), is(404)); - EntityUtils.consume(response.getEntity()); - } - - public void saveMainBundleJarClassPathMappings(Path jarFile) throws Exception { - assertTrue("Couldn't find file " + jarFile + ", please remember to run mvn process-test-resources first.", - Files.isRegularFile(jarFile)); - saveMainBundleClassPathMappings(jarFile.toAbsolutePath().toString()); - } - - public void saveMainBundleClassPathMappings(String classPathElement) throws Exception { - BundleClasspathMapping mainBundleClassPathMappings = new BundleClasspathMapping(bundleSymbolicName, - Arrays.asList(classPathElement)); - save(new ProjectBundleClassPaths(mainBundleClassPathMappings, emptyList())); - } - - public void save(ProjectBundleClassPaths projectBundleClassPaths) throws Exception { - Path path = Paths.get(testClassesDirectory).resolve(ProjectBundleClassPaths.CLASSPATH_MAPPINGS_FILENAME); - ProjectBundleClassPaths.save(path, projectBundleClassPaths); - } - - public String path(Class<?> resourceClass) { - return UriBuilder.fromResource(resourceClass).build().toString(); - } -} diff --git a/application/src/test/java/com/yahoo/application/container/jersey/resources/TestResource.java b/application/src/test/java/com/yahoo/application/container/jersey/resources/TestResource.java deleted file mode 100644 index b3c21ae4f99..00000000000 --- a/application/src/test/java/com/yahoo/application/container/jersey/resources/TestResource.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container.jersey.resources; - -import com.yahoo.container.test.jars.jersey.resources.TestResourceBase; - -import javax.ws.rs.Path; - -/** - * @author Tony Vaagenes - * @author ovirtanen - */ -@Path("/test-resource") -public class TestResource extends TestResourceBase { -} diff --git a/application/src/test/java/com/yahoo/application/container/searchers/AddHitSearcher.java b/application/src/test/java/com/yahoo/application/container/searchers/AddHitSearcher.java deleted file mode 100644 index 274c37bcfc1..00000000000 --- a/application/src/test/java/com/yahoo/application/container/searchers/AddHitSearcher.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container.searchers; - -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.result.Hit; -import com.yahoo.search.searchchain.Execution; - -public class AddHitSearcher extends Searcher { - @Override - public Result search(Query query, Execution execution) { - Result result = execution.search(query); - result.hits().add(getDummyHit()); - - return result; - } - - private Hit getDummyHit() { - Hit hit = new Hit("dummy"); - hit.setField("title", getId().getName()); - return hit; - } -} diff --git a/application/src/test/scala/com/yahoo/application/ApplicationBuilderTest.scala b/application/src/test/scala/com/yahoo/application/ApplicationBuilderTest.scala new file mode 100644 index 00000000000..255810b959b --- /dev/null +++ b/application/src/test/scala/com/yahoo/application/ApplicationBuilderTest.scala @@ -0,0 +1,74 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application + +import container.JDiscTest._ +import java.nio.file.Files +import org.junit.Assert.{assertTrue, assertThat, fail} +import org.junit.Test +import com.yahoo.io.IOUtils +import org.hamcrest.CoreMatchers.containsString + +/** + * @author tonytv + */ + class ApplicationBuilderTest { + @Test + def query_profile_types_can_be_added() { + withApplicationBuilder { builder => + builder.queryProfileType("MyProfileType", + <query-profile-type id="MyProfileType"> + <field name="age" type="integer" /> + <field name="profession" type="string" /> + <field name="user" type="query-profile:MyUserProfile" /> + </query-profile-type>) + + assertTrue(Files.exists(builder.getPath.resolve("search/query-profiles/types/MyProfileType.xml"))) + } + } + + + @Test + def query_profile_can_be_added() { + withApplicationBuilder { builder => + builder.queryProfile("MyProfile", + <query-profile id="MyProfile"> + <field name="message">Hello world!</field> + </query-profile>) + + assertTrue(Files.exists(builder.getPath.resolve("search/query-profiles/MyProfile.xml"))) + } + } + + @Test + def rank_expression_can_be_added() { + withApplicationBuilder { builder => + builder.rankExpression("myExpression", "content") + assertTrue(Files.exists(builder.getPath.resolve("searchdefinitions/myExpression.expression"))) + } + } + + @Test + def builder_cannot_be_reused() { + val builder = new ApplicationBuilder + builder.servicesXml(<jdisc version="1.0" />) + + using(builder.build()) { builder => } + + try { + builder.servicesXml("") + fail("Expected exception.") + } catch { + case e: RuntimeException => assertThat(e.getMessage, containsString("build method")) + } + + } + + def withApplicationBuilder(f: ApplicationBuilder => Unit) { + val builder = new ApplicationBuilder() + try { + f(builder) + } finally { + IOUtils.recursiveDeleteDir(builder.getPath.toFile) + } + } +} diff --git a/application/src/test/scala/com/yahoo/application/container/JDiscContainerSearchTest.scala b/application/src/test/scala/com/yahoo/application/container/JDiscContainerSearchTest.scala new file mode 100644 index 00000000000..9d7e8ea26ab --- /dev/null +++ b/application/src/test/scala/com/yahoo/application/container/JDiscContainerSearchTest.scala @@ -0,0 +1,69 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container + +import org.junit.Test +import searchers.AddHitSearcher +import com.yahoo.component.ComponentSpecification +import com.yahoo.search.Query +import org.junit.Assert._ +import org.hamcrest.CoreMatchers._ +import org.hamcrest.Matchers.containsString; +import JDiscTest.{fromServicesXml, using} + + +/** + * + * @author gjoranv + * @since 5.1.15 + */ +class JDiscContainerSearchTest { + + @Test + def processing_and_rendering_works() { + val searcherId = classOf[AddHitSearcher].getName + + using(containerWithSearch(searcherId)) + { container => + val rendered = container.search.processAndRender(ComponentSpecification.fromString("mychain"), + ComponentSpecification.fromString("DefaultRenderer"), new Query("")) + val renderedAsString = new String(rendered, "utf-8") + assertThat(renderedAsString, containsString(searcherId)) + } + } + + @Test + def searching_works() { + val searcherId = classOf[AddHitSearcher].getName + + using(containerWithSearch(searcherId)) + { container => + val searching = container.search + val result = searching.process(ComponentSpecification.fromString("mychain"), new Query("")) + + val hitTitle = result.hits().get(0).getField("title").asInstanceOf[String] + assertThat(hitTitle, is(searcherId)) + } + } + + def containerWithSearch(searcherId: String) = { + fromServicesXml( + <container version="1.0"> + <search> + <chain id="mychain"> + <searcher id={searcherId}/> + </chain> + </search> + </container>) + } + + @Test(expected = classOf[UnsupportedOperationException]) + def retrieving_search_from_container_without_search_is_illegal() { + using(JDiscTest.fromServicesXml( + <container version="1.0" /> + )) + { container => + container.search // throws + } + } + +} diff --git a/application/src/test/scala/com/yahoo/application/container/JDiscTest.scala b/application/src/test/scala/com/yahoo/application/container/JDiscTest.scala new file mode 100644 index 00000000000..727a77ee119 --- /dev/null +++ b/application/src/test/scala/com/yahoo/application/container/JDiscTest.scala @@ -0,0 +1,198 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container + +import com.yahoo.container.Container +import com.yahoo.jdisc.http.server.jetty.JettyHttpServer + +import scala.language.implicitConversions +import handler.Request +import org.junit.{Ignore, Test} +import org.junit.Assert.{assertThat, assertNotNull, fail} +import org.hamcrest.CoreMatchers.{is, containsString, hasItem} +import java.nio.file.FileSystems +import com.yahoo.search.Query +import com.yahoo.component.ComponentSpecification +import handlers.TestHandler +import xml.{Node, Elem} +import JDiscTest._ +import com.yahoo.application.{Networking, ApplicationBuilder} + +import scala.collection.convert.wrapAsScala._ + + +/** + * @author tonytv + * @author gjoranv + */ +class JDiscTest { + @Test + def jdisc_can_be_used_as_top_level_element() { + using(fromServicesXml( + <jdisc version="1.0"> + <search /> + </jdisc>)) + { container => + assertNotNull(container.search()) + } + } + + @Test + def jdisc_id_can_be_set() { + using(fromServicesXml( + <jdisc version="1.0" id="my-service-id"> + <search /> + </jdisc>)) + { container => + assertNotNull(container.search()) + } + } + + @Test + def jdisc_can_be_embedded_in_services_tag() { + using(fromServicesXml( + <services> + <jdisc version="1.0" id="my-service-id"> + <search /> + </jdisc> + </services>)) + { container => + assertNotNull(container.search()) + } + } + + @Test + def multiple_jdisc_elements_gives_exception() { + try { + using(fromServicesXml( + <services> + <jdisc version="1.0" id="id1" /> + <jdisc version="1.0" /> + <container version="1.0"/> + </services>)) + { container => fail("expected exception")} + } catch { + case e: Exception => assertThat(e.getMessage, containsString("container id='', jdisc id='id1', jdisc id=''")) + } + } + + @Test + def handleRequest_yields_response_from_correct_request_handler() { + using(fromServicesXml( + <container version="1.0"> + <handler id="test-handler" class={classOf[TestHandler].getName}> + <binding>http://*/TestHandler</binding> + </handler> + </container>)) + { container => + val response = container.handleRequest(new Request("http://foo/TestHandler")) + assertThat(response.getBodyAsString, is(TestHandler.RESPONSE)) + } + } + + @Test + def load_searcher_from_bundle() { + using(JDisc.fromPath(FileSystems.getDefault.getPath("src/test/app-packages/searcher-app"), Networking.disable)) + { container => + val result = container.search.process(ComponentSpecification.fromString("default"),new Query("?query=ignored")) + assertThat(result.hits().get(0).getField("title").toString, is("Heal the World!")) + } + } + + @Test + def document_types_can_be_accessed() { + using(new ApplicationBuilder().documentType("example", exampleDocument). + servicesXml(containerWithDocumentProcessing). + build()) + { application => + val container = application.getJDisc("jdisc") + val processing = container.documentProcessing() + assertThat(processing.getDocumentTypes.keySet(), hasItem("example")) + } + } + + @Test + def annotation_types_can_be_accessed() { + using(new ApplicationBuilder().documentType("example", + s""" + |search example { + | ${exampleDocument} + | annotation exampleAnnotation {} + |} + """.stripMargin). + servicesXml(containerWithDocumentProcessing). + build()) + { application => + val container = application.getJDisc("jdisc") + val processing = container.documentProcessing() + assertThat(processing.getAnnotationTypes.keySet(), hasItem("exampleAnnotation")) + } + } + + @Ignore //Enable this when static state has been removed. + @Test + def multiple_containers_can_be_run_in_parallel() { + def sendRequest(jdisc: JDisc) { + val response = jdisc.handleRequest(new Request("http://foo/TestHandler")) + assertThat(response.getBodyAsString, is(TestHandler.RESPONSE)) + } + + using(jdiscWithHttp()) { jdisc1 => + using(jdiscWithHttp()) { jdisc2 => + sendRequest(jdisc1) + sendRequest(jdisc2) + } + } + } +} + +object JDiscTest { + + def fromServicesXml(elem: Elem, networking: Networking = Networking.disable) = + JDisc.fromServicesXml(elem.toString(), networking) + + def using[T <: AutoCloseable, U](t: T)(f: T => U ) = { + try { + f(t) + } finally { + t.close() + } + } + + implicit def xmlToString(xml: Node): String = xml.toString() + + val containerWithDocumentProcessing = + <jdisc version="1.0"> + <http /> + <document-processing /> + </jdisc> + + val exampleDocument = + """ + |document example { + | + | field title type string { + | indexing: summary | index # How this field should be indexed + | weight: 75 # Ranking importancy of this field, used by the built in nativeRank feature + | header + | } + |} + """.stripMargin + + + def jdiscWithHttp() = { + fromServicesXml( + <jdisc version="1.0"> + <handler id={classOf[TestHandler].getName} /> + <http> + <server id="main" port="9999" /> + </http> + </jdisc>) + } + + def getListenPort: Int = + Container.get.getServerProviderRegistry.allComponents().collectFirst { + case server: JettyHttpServer => server.getListenPort + } getOrElse { + throw new RuntimeException("No http server found") + } +} diff --git a/application/src/test/scala/com/yahoo/application/container/handlers/TestHandler.scala b/application/src/test/scala/com/yahoo/application/container/handlers/TestHandler.scala new file mode 100644 index 00000000000..067ba3f31f1 --- /dev/null +++ b/application/src/test/scala/com/yahoo/application/container/handlers/TestHandler.scala @@ -0,0 +1,23 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container.handlers + +import com.yahoo.jdisc.handler.{ResponseDispatch, ResponseHandler, AbstractRequestHandler} +import TestHandler._ + +/** + * @author gjoranv + * @since 5.1.15 + */ + +class TestHandler extends AbstractRequestHandler { + def handleRequest(request:JDiscRequest, handler: ResponseHandler) = { + val writer = ResponseDispatch.newInstance(com.yahoo.jdisc.Response.Status.OK).connectFastWriter(handler) + writer.write(RESPONSE) + writer.close() + null + } +} +object TestHandler { + val RESPONSE = "Hello, World!" + type JDiscRequest = com.yahoo.jdisc.Request +} diff --git a/application/src/test/scala/com/yahoo/application/container/jersey/JerseyTest.scala b/application/src/test/scala/com/yahoo/application/container/jersey/JerseyTest.scala new file mode 100644 index 00000000000..2aee68f254a --- /dev/null +++ b/application/src/test/scala/com/yahoo/application/container/jersey/JerseyTest.scala @@ -0,0 +1,172 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container.jersey + +import java.nio.file.{Files, Path, Paths} +import javax.ws.rs.core.UriBuilder + +import com.yahoo.application.Networking +import com.yahoo.application.container.JDiscTest._ +import com.yahoo.container.test.jars.jersey.resources.TestResourceBase +import com.yahoo.container.test.jars.jersey.{resources => jarResources} +import com.yahoo.osgi.maven.ProjectBundleClassPaths +import com.yahoo.osgi.maven.ProjectBundleClassPaths.BundleClasspathMapping +import org.apache.http.HttpResponse +import org.apache.http.client.methods.HttpGet +import org.apache.http.impl.client.HttpClientBuilder +import org.apache.http.util.EntityUtils +import org.hamcrest.CoreMatchers.is +import org.junit.Assert._ +import org.junit.Test + +import scala.collection.JavaConverters._ +import scala.io.Source + +/** + * @author tonytv + */ +class JerseyTest { + type TestResourceClass = Class[_ <: TestResourceBase] + + val testJar = Paths.get("target/test-jars/jersey-resources.jar") + val testClassesDirectory = "target/test-classes" + val bundleSymbolicName = "myBundle" + + val classPathResources = Set( + classOf[resources.TestResource], + classOf[resources.nestedpackage1.NestedTestResource1], + classOf[resources.nestedpackage2.NestedTestResource2]) + + val jarFileResources = Set( + classOf[jarResources.TestResource], + classOf[com.yahoo.container.test.jars.jersey.resources.nestedpackage1.NestedTestResource1], + classOf[com.yahoo.container.test.jars.jersey.resources.nestedpackage2.NestedTestResource2]) + + @Test + def jersey_resources_on_classpath_can_be_invoked_from_application(): Unit = { + saveMainBundleClassPathMappings(testClassesDirectory) + + with_jersey_resources() { httpGetter => + assertResourcesResponds(classPathResources, httpGetter) + } + } + + @Test + def jersey_resources_in_provided_dependencies_can_be_invoked_from_application(): Unit = { + val providedDependency = new BundleClasspathMapping(bundleSymbolicName, List(testClassesDirectory).asJava) + + save(new ProjectBundleClassPaths( + new BundleClasspathMapping("main", List().asJava), + List(providedDependency).asJava)) + + with_jersey_resources() { httpGetter => + assertResourcesResponds(classPathResources, httpGetter) + } + } + + @Test + def jersey_resource_on_classpath_can_be_filtered_using_packages(): Unit = { + saveMainBundleClassPathMappings(testClassesDirectory) + + with_jersey_resources( + packagesToScan = List( + "com.yahoo.application.container.jersey.resources", + "com.yahoo.application.container.jersey.resources.nestedpackage1")) + { httpGetter => + val nestedResource2 = classOf[resources.nestedpackage2.NestedTestResource2] + + assertDoesNotRespond(nestedResource2, httpGetter) + assertResourcesResponds(classPathResources - nestedResource2, httpGetter) + } + } + + @Test + def jersey_resource_in_jar_can_be_invoked_from_application(): Unit = { + saveMainBundleJarClassPathMappings(testJar) + + with_jersey_resources() { httpGetter => + assertResourcesResponds(jarFileResources, httpGetter) + } + } + + @Test + def jersey_resource_in_jar_can_be_filtered_using_packages(): Unit = { + saveMainBundleJarClassPathMappings(testJar) + + with_jersey_resources( + packagesToScan = List( + "com.yahoo.container.test.jars.jersey.resources", + "com.yahoo.container.test.jars.jersey.resources.nestedpackage1")) + { httpGetter => + val nestedResource2 = classOf[com.yahoo.container.test.jars.jersey.resources.nestedpackage2.NestedTestResource2] + + assertDoesNotRespond(nestedResource2, httpGetter) + assertResourcesResponds(jarFileResources - nestedResource2, httpGetter) + } + } + + def with_jersey_resources(packagesToScan: List[String] = List())( f: HttpGetter => Unit): Unit = { + val packageElements = packagesToScan.map { p => <package>{p}</package>} + + using(fromServicesXml( + <services> + <jdisc version="1.0" id="default" jetty="true"> + <rest-api path="rest-api" jersey2="true"> + <components bundle={bundleSymbolicName}> + { packageElements } + </components> + </rest-api> + <http> + <server id="mainServer" port="0" /> + </http> + </jdisc> + </services>, + Networking.enable)) { jdisc => + + + def httpGetter(path: HttpPath) = { + val client = HttpClientBuilder.create().build() + client.execute(new HttpGet(s"http://localhost:$getListenPort/rest-api/${path.stripPrefix("/")}")) + } + + f(httpGetter) + } + } + + def assertResourcesResponds(resourceClasses: Traversable[TestResourceClass], httpGetter: HttpGetter): Unit = { + for (resource <- resourceClasses) { + val response = httpGetter(path(resource)) + assertThat(s"Failed sending response to $resource", response.getStatusLine.getStatusCode, is(200)) + + val content = Source.fromInputStream(response.getEntity.getContent).mkString + assertThat(content, is(TestResourceBase.content(resource))) + } + } + + def assertDoesNotRespond(resourceClass: TestResourceClass, httpGetter: HttpGetter): Unit = { + val response = httpGetter(path(resourceClass)) + assertThat(response.getStatusLine.getStatusCode, is(404)) + EntityUtils.consume(response.getEntity) + } + + def saveMainBundleJarClassPathMappings(jarFile: Path): Unit = { + assertTrue(s"Couldn't find file $jarFile, please remember to run mvn process-test-resources first.", Files.isRegularFile(jarFile)) + saveMainBundleClassPathMappings(jarFile.toAbsolutePath.toString) + } + + def saveMainBundleClassPathMappings(classPathElement: String): Unit = { + val mainBundleClassPathMappings = new BundleClasspathMapping(bundleSymbolicName, List(classPathElement).asJava) + save(new ProjectBundleClassPaths(mainBundleClassPathMappings, List().asJava)) + } + + def save(projectBundleClassPaths: ProjectBundleClassPaths): Unit = { + val path = Paths.get(testClassesDirectory).resolve(ProjectBundleClassPaths.CLASSPATH_MAPPINGS_FILENAME) + ProjectBundleClassPaths.save(path, projectBundleClassPaths) + } + + def path(resourceClass: TestResourceClass) = { + UriBuilder.fromResource(resourceClass).build().toString + } + + type HttpPath = String + type HttpGetter = HttpPath => HttpResponse +} diff --git a/application/src/test/scala/com/yahoo/application/container/jersey/resources/TestResource.scala b/application/src/test/scala/com/yahoo/application/container/jersey/resources/TestResource.scala new file mode 100644 index 00000000000..5dc16102d8e --- /dev/null +++ b/application/src/test/scala/com/yahoo/application/container/jersey/resources/TestResource.scala @@ -0,0 +1,12 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container.jersey.resources + +import javax.ws.rs.Path +import com.yahoo.container.test.jars.jersey.resources.TestResourceBase + + +/** + * @author tonytv + */ +@Path("/test-resource") +class TestResource extends TestResourceBase diff --git a/application/src/test/java/com/yahoo/application/container/jersey/resources/nestedpackage1/NestedTestResource1.java b/application/src/test/scala/com/yahoo/application/container/jersey/resources/nestedpackage1/NestedTestResource1.scala index 6fc03c034c0..c50d7cd6f57 100644 --- a/application/src/test/java/com/yahoo/application/container/jersey/resources/nestedpackage1/NestedTestResource1.java +++ b/application/src/test/scala/com/yahoo/application/container/jersey/resources/nestedpackage1/NestedTestResource1.scala @@ -1,14 +1,12 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container.jersey.resources.nestedpackage1; +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container.jersey.resources.nestedpackage1 -import com.yahoo.container.test.jars.jersey.resources.TestResourceBase; +import javax.ws.rs.Path -import javax.ws.rs.Path; +import com.yahoo.container.test.jars.jersey.resources.TestResourceBase /** - * @author Tony Vaagenes - * @author ovirtanen + * @author tonytv */ @Path("/nested-test-resource1") -public class NestedTestResource1 extends TestResourceBase { -} +class NestedTestResource1 extends TestResourceBase diff --git a/application/src/test/java/com/yahoo/application/container/jersey/resources/nestedpackage2/NestedTestResource2.java b/application/src/test/scala/com/yahoo/application/container/jersey/resources/nestedpackage2/NestedTestResource2.scala index a592b072f6e..50f0054b6ec 100644 --- a/application/src/test/java/com/yahoo/application/container/jersey/resources/nestedpackage2/NestedTestResource2.java +++ b/application/src/test/scala/com/yahoo/application/container/jersey/resources/nestedpackage2/NestedTestResource2.scala @@ -1,14 +1,12 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.application.container.jersey.resources.nestedpackage2; +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container.jersey.resources.nestedpackage2 -import com.yahoo.container.test.jars.jersey.resources.TestResourceBase; +import javax.ws.rs.Path -import javax.ws.rs.Path; +import com.yahoo.container.test.jars.jersey.resources.TestResourceBase /** - * @author Tony Vaagenes - * @author ovirtanen + * @author tonytv */ @Path("/nested-test-resource2") -public class NestedTestResource2 extends TestResourceBase { -} +class NestedTestResource2 extends TestResourceBase diff --git a/application/src/test/scala/com/yahoo/application/container/searchers/AddHitSearcher.scala b/application/src/test/scala/com/yahoo/application/container/searchers/AddHitSearcher.scala new file mode 100644 index 00000000000..e3a6cd031bc --- /dev/null +++ b/application/src/test/scala/com/yahoo/application/container/searchers/AddHitSearcher.scala @@ -0,0 +1,23 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.application.container.searchers + +import com.yahoo.search.{Searcher, Result, Query} +import com.yahoo.search.searchchain.Execution +import com.yahoo.search.result.Hit + + +class AddHitSearcher extends Searcher { + + override def search(query: Query, execution: Execution) : Result = { + val result = execution.search(query) + result.hits().add(dummyHit) + + result + } + + private def dummyHit = { + val hit = new Hit("dummy") + hit.setField("title", getId.getName) + hit + } +} |