diff --git a/appengine/search/.gitignore b/appengine/search/.gitignore new file mode 100644 index 00000000000..471339729ae --- /dev/null +++ b/appengine/search/.gitignore @@ -0,0 +1,7 @@ +# Eclipse files +.project +.classpath +.settings + +# Target folders +target/ diff --git a/appengine/search/README.md b/appengine/search/README.md new file mode 100644 index 00000000000..34121fac71e --- /dev/null +++ b/appengine/search/README.md @@ -0,0 +1,20 @@ +# Google App Engine Standard Environment Search API Sample + +This sample demonstrates how to use App Engine Search API. + +See the [Google App Engine Search API documentation][search-api-docs] for more +detailed instructions. + +[search-api-docs]: https://cloud.google.com/appengine/docs/java/search/ + +## Setup +1. Update the `` tag in `src/main/webapp/WEB-INF/appengine-web.xml` + with your project name. +1. Update the `` tag in `src/main/webapp/WEB-INF/appengine-web.xml` + with your version name. + +## Running locally + $ mvn appengine:devserver + +## Deploying + $ mvn appengine:update \ No newline at end of file diff --git a/appengine/search/google-checks.xml b/appengine/search/google-checks.xml new file mode 100644 index 00000000000..730c9148710 --- /dev/null +++ b/appengine/search/google-checks.xml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/appengine/search/pom.xml b/appengine/search/pom.xml new file mode 100644 index 00000000000..7d701bf5f67 --- /dev/null +++ b/appengine/search/pom.xml @@ -0,0 +1,117 @@ + + + 4.0.0 + war + 1.0-SNAPSHOT + com.example.appengine + appengine-search + + com.google.cloud + doc-samples + 1.0.0 + ../.. + + + + com.google.appengine + appengine-api-1.0-sdk + ${appengine.sdk.version} + + + javax.servlet + servlet-api + 2.5 + jar + provided + + + + + junit + junit + 4.10 + test + + + org.mockito + mockito-all + 1.10.19 + test + + + com.google.appengine + appengine-testing + ${appengine.sdk.version} + test + + + com.google.appengine + appengine-api-stubs + ${appengine.sdk.version} + test + + + com.google.appengine + appengine-tools-sdk + ${appengine.sdk.version} + test + + + com.google.truth + truth + 0.28 + test + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.17 + + google-checks.xml + true + true + true + true + suppressions.xml + + + check + + + + org.apache.maven.plugins + 3.3 + maven-compiler-plugin + + 1.7 + 1.7 + + + + + com.google.appengine + appengine-maven-plugin + ${appengine.sdk.version} + + + + diff --git a/appengine/search/src/main/java/com/example/appengine/search/DeleteServlet.java b/appengine/search/src/main/java/com/example/appengine/search/DeleteServlet.java new file mode 100644 index 00000000000..6b25a22638e --- /dev/null +++ b/appengine/search/src/main/java/com/example/appengine/search/DeleteServlet.java @@ -0,0 +1,94 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed 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 com.example.appengine.search; + +// @formatter:off +// [START delete_import] +import com.google.appengine.api.search.Document; +import com.google.appengine.api.search.GetRequest; +import com.google.appengine.api.search.GetResponse; +// [END delete_import] + +//CHECKSTYLE:OFF +import com.google.appengine.api.search.Field; +import com.google.appengine.api.search.Index; +import com.google.appengine.api.search.IndexSpec; +import com.google.appengine.api.search.SearchServiceFactory; +// @formatter:on +//CHECKSTYLE:ON + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Code snippet for deleting documents from an Index. + */ +@SuppressWarnings("serial") +public class DeleteServlet extends HttpServlet { + private static final Logger LOG = Logger.getLogger(DeleteServlet.class.getSimpleName()); + + private static final String SEARCH_INDEX = "searchIndexForDelete"; + + private Index getIndex() { + IndexSpec indexSpec = IndexSpec.newBuilder().setName(SEARCH_INDEX).build(); + Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec); + return index; + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws IOException { + // Put one document to avoid an error + Document document = Document.newBuilder() + .addField(Field.newBuilder().setName("f").setText("v")) + .build(); + try { + Utils.indexADocument(SEARCH_INDEX, document); + } catch (InterruptedException e) { + // ignore + } + // [START delete_documents] + try { + // looping because getRange by default returns up to 100 documents at a time + while (true) { + List docIds = new ArrayList<>(); + // Return a set of doc_ids. + GetRequest request = GetRequest.newBuilder().setReturningIdsOnly(true).build(); + GetResponse response = getIndex().getRange(request); + if (response.getResults().isEmpty()) { + break; + } + for (Document doc : response) { + docIds.add(doc.getId()); + } + getIndex().delete(docIds); + } + } catch (RuntimeException e) { + LOG.log(Level.SEVERE, "Failed to delete documents", e); + } + // [END delete_documents] + PrintWriter out = resp.getWriter(); + out.println("Deleted documents."); + } +} diff --git a/appengine/search/src/main/java/com/example/appengine/search/DocumentServlet.java b/appengine/search/src/main/java/com/example/appengine/search/DocumentServlet.java new file mode 100644 index 00000000000..9f53aeb3c3f --- /dev/null +++ b/appengine/search/src/main/java/com/example/appengine/search/DocumentServlet.java @@ -0,0 +1,83 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed 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 com.example.appengine.search; + +// [START document_import] +import com.google.appengine.api.search.Document; +import com.google.appengine.api.search.Field; +import com.google.appengine.api.users.User; +import com.google.appengine.api.users.UserServiceFactory; +// [END document_import] + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * A servlet for creating Search API Document. + */ +@SuppressWarnings("serial") +public class DocumentServlet extends HttpServlet { + + /** + * Code snippet for creating a Document. + * @return Document Created document. + */ + public Document createDocument() { + // [START create_document] + User currentUser = UserServiceFactory.getUserService().getCurrentUser(); + String userEmail = currentUser == null ? "" : currentUser.getEmail(); + String userDomain = currentUser == null ? "" : currentUser.getAuthDomain(); + String myDocId = "PA6-5000"; + Document doc = Document.newBuilder() + // Setting the document identifer is optional. + // If omitted, the search service will create an identifier. + .setId(myDocId) + .addField(Field.newBuilder().setName("content").setText("the rain in spain")) + .addField(Field.newBuilder().setName("email").setText(userEmail)) + .addField(Field.newBuilder().setName("domain").setAtom(userDomain)) + .addField(Field.newBuilder().setName("published").setDate(new Date())) + .build(); + // [END create_document] + return doc; + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws IOException { + PrintWriter out = resp.getWriter(); + Document document = Document.newBuilder() + .addField(Field.newBuilder().setName("coverLetter").setText("CoverLetter")) + .addField(Field.newBuilder().setName("resume").setHTML("")) + .addField(Field.newBuilder().setName("fullName").setAtom("Foo Bar")) + .addField(Field.newBuilder().setName("submissionDate").setDate(new Date())) + .build(); + // [START access_document] + String coverLetter = document.getOnlyField("coverLetter").getText(); + String resume = document.getOnlyField("resume").getHTML(); + String fullName = document.getOnlyField("fullName").getAtom(); + Date submissionDate = document.getOnlyField("submissionDate").getDate(); + // [END access_document] + out.println("coverLetter: " + coverLetter); + out.println("resume: " + resume); + out.println("fullName: " + fullName); + out.println("submissionDate: " + submissionDate.toString()); + } +} diff --git a/appengine/search/src/main/java/com/example/appengine/search/IndexServlet.java b/appengine/search/src/main/java/com/example/appengine/search/IndexServlet.java new file mode 100644 index 00000000000..85e53b5bfb4 --- /dev/null +++ b/appengine/search/src/main/java/com/example/appengine/search/IndexServlet.java @@ -0,0 +1,75 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed 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 com.example.appengine.search; + +// @formatter:off +import com.google.appengine.api.search.Document; +import com.google.appengine.api.search.Field; +import com.google.appengine.api.search.Index; +import com.google.appengine.api.search.IndexSpec; +import com.google.appengine.api.search.SearchServiceFactory; + +//CHECKSTYLE:OFF +// [START get_document_import] +import com.google.appengine.api.search.GetRequest; +import com.google.appengine.api.search.GetResponse; +// [END get_document_import] +// @formatter:on +//CHECKSTYLE:ON + +import java.io.IOException; +import java.io.PrintWriter; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/** + * Code snippet for getting a document from Index. + */ +@SuppressWarnings("serial") +public class IndexServlet extends HttpServlet { + + private static final String INDEX = "testIndex"; + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + PrintWriter out = resp.getWriter(); + Document document = Document.newBuilder() + .setId("AZ125") + .addField(Field.newBuilder().setName("myField").setText("myValue")).build(); + try { + Utils.indexADocument(INDEX, document); + } catch (InterruptedException e) { + out.println("Interrupted"); + return; + } + out.println("Indexed a new document."); + // [START get_document] + IndexSpec indexSpec = IndexSpec.newBuilder().setName(INDEX).build(); + Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec); + + // Fetch a single document by its doc_id + Document doc = index.get("AZ125"); + + // Fetch a range of documents by their doc_ids + GetResponse docs = index.getRange( + GetRequest.newBuilder().setStartId("AZ125").setLimit(100).build()); + // [END get_document] + out.println("myField: " + docs.getResults().get(0).getOnlyField("myField").getText()); + } +} diff --git a/appengine/search/src/main/java/com/example/appengine/search/SearchServlet.java b/appengine/search/src/main/java/com/example/appengine/search/SearchServlet.java new file mode 100644 index 00000000000..8804ac48cec --- /dev/null +++ b/appengine/search/src/main/java/com/example/appengine/search/SearchServlet.java @@ -0,0 +1,105 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed 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 com.example.appengine.search; + +// @formatter:off +// [START search_document_import] +import com.google.appengine.api.search.Document; +import com.google.appengine.api.search.Field; +import com.google.appengine.api.search.Results; +import com.google.appengine.api.search.ScoredDocument; +import com.google.appengine.api.search.SearchException; +import com.google.appengine.api.search.StatusCode; +// [END search_document_import] + +//CHECKSTYLE:OFF +import com.google.appengine.api.search.Index; +import com.google.appengine.api.search.IndexSpec; +import com.google.appengine.api.search.SearchServiceFactory; +// @formatter:on +//CHECKSTYLE:ON + +import java.io.IOException; +import java.io.PrintWriter; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + + +@SuppressWarnings("serial") +public class SearchServlet extends HttpServlet { + + private static final String SEARCH_INDEX = "searchIndex"; + + private Index getIndex() { + IndexSpec indexSpec = IndexSpec.newBuilder().setName(SEARCH_INDEX).build(); + Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec); + return index; + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws IOException { + PrintWriter out = resp.getWriter(); + Document doc = Document.newBuilder() + .setId("theOnlyPiano") + .addField(Field.newBuilder().setName("product").setText("piano")) + .addField(Field.newBuilder().setName("maker").setText("Yamaha")) + .addField(Field.newBuilder().setName("price").setNumber(4000)) + .build(); + try { + Utils.indexADocument(SEARCH_INDEX, doc); + } catch (InterruptedException e) { + // ignore + } + // [START search_document] + final int maxRetry = 3; + int attempts = 0; + int delay = 2; + while (true) { + try { + String queryString = "product: piano AND price < 5000"; + Results results = getIndex().search(queryString); + + // Iterate over the documents in the results + for (ScoredDocument document : results) { + // handle results + out.print("maker: " + document.getOnlyField("maker").getText()); + out.println(", price: " + document.getOnlyField("price").getNumber()); + } + } catch (SearchException e) { + if (StatusCode.TRANSIENT_ERROR.equals(e.getOperationResult().getCode()) + && ++attempts < maxRetry) { + // retry + try { + Thread.sleep(delay * 1000); + } catch (InterruptedException e1) { + // ignore + } + delay *= 2; // easy exponential backoff + continue; + } else { + throw e; + } + } + break; + } + // [START search_document] + out.println("Search performed"); + } +} diff --git a/appengine/search/src/main/java/com/example/appengine/search/Utils.java b/appengine/search/src/main/java/com/example/appengine/search/Utils.java new file mode 100644 index 00000000000..f0f84ddf524 --- /dev/null +++ b/appengine/search/src/main/java/com/example/appengine/search/Utils.java @@ -0,0 +1,63 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed 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 com.example.appengine.search; + +// [START index_import] +import com.google.appengine.api.search.Document; +import com.google.appengine.api.search.Index; +import com.google.appengine.api.search.IndexSpec; +import com.google.appengine.api.search.PutException; +import com.google.appengine.api.search.SearchServiceFactory; +import com.google.appengine.api.search.StatusCode; +// [END index_import] + +/** + * A utility class for the search API sample. + */ +public class Utils { + /** + * Put a given document into an index with the given indexName. + * @param indexName The name of the index. + * @param document A document to add. + * @throws InterruptedException When Thread.sleep is interrupted. + */ + // [START putting_document_with_retry] + public static void indexADocument(String indexName, Document document) + throws InterruptedException { + IndexSpec indexSpec = IndexSpec.newBuilder().setName(indexName).build(); + Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec); + + final int maxRetry = 3; + int attempts = 0; + int delay = 2; + while (true) { + try { + index.put(document); + } catch (PutException e) { + if (StatusCode.TRANSIENT_ERROR.equals(e.getOperationResult().getCode()) + && ++attempts < maxRetry) { // retrying + Thread.sleep(delay * 1000); + delay *= 2; // easy exponential backoff + continue; + } else { + throw e; // otherwise throw + } + } + break; + } + } + // [END putting_document_with_retry] +} diff --git a/appengine/search/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/search/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..c322e7d016e --- /dev/null +++ b/appengine/search/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,20 @@ + + + + + + YOUR-PROJECT-ID + YOUR-VERSION-ID + true + diff --git a/appengine/search/src/main/webapp/WEB-INF/web.xml b/appengine/search/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..a3f744efa07 --- /dev/null +++ b/appengine/search/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,38 @@ + + + + document + com.example.appengine.search.DocumentServlet + + + document + / + + + index + com.example.appengine.search.IndexServlet + + + index + /index + + + search + com.example.appengine.search.SearchServlet + + + search + /search + + + delete + com.example.appengine.search.DeleteServlet + + + delete + /delete + + diff --git a/appengine/search/src/test/java/com/example/appengine/search/DeleteServletTest.java b/appengine/search/src/test/java/com/example/appengine/search/DeleteServletTest.java new file mode 100644 index 00000000000..2ec6dde14c3 --- /dev/null +++ b/appengine/search/src/test/java/com/example/appengine/search/DeleteServletTest.java @@ -0,0 +1,50 @@ +package com.example.appengine.search; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import com.google.appengine.tools.development.testing.LocalServiceTestHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.PrintWriter; +import java.io.StringWriter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class DeleteServletTest { + private final LocalServiceTestHelper helper = new LocalServiceTestHelper(); + + @Mock private HttpServletRequest mockRequest; + @Mock private HttpServletResponse mockResponse; + private StringWriter responseWriter; + private DeleteServlet servletUnderTest; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + helper.setUp(); + + // Set up a fake HTTP response. + responseWriter = new StringWriter(); + when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter)); + + servletUnderTest = new DeleteServlet(); + } + + @After + public void tearDown() { + helper.tearDown(); + } + + @Test + public void doGet_successfulyInvoked() throws Exception { + servletUnderTest.doGet(mockRequest, mockResponse); + assertThat(responseWriter.toString()) + .named("DeleteServlet response") + .contains("Deleted documents."); + } +} \ No newline at end of file diff --git a/appengine/search/src/test/java/com/example/appengine/search/DocumentServletTest.java b/appengine/search/src/test/java/com/example/appengine/search/DocumentServletTest.java new file mode 100644 index 00000000000..789be7ea443 --- /dev/null +++ b/appengine/search/src/test/java/com/example/appengine/search/DocumentServletTest.java @@ -0,0 +1,89 @@ +package com.example.appengine.search; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import com.google.appengine.api.search.Document; +import com.google.appengine.tools.development.testing.LocalServiceTestHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.PrintWriter; +import java.io.StringWriter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class DocumentServletTest { + private final LocalServiceTestHelper helper = new LocalServiceTestHelper(); + + @Mock private HttpServletRequest mockRequest; + @Mock private HttpServletResponse mockResponse; + private StringWriter responseWriter; + private DocumentServlet servletUnderTest; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + helper.setUp(); + + // Set up a fake HTTP response. + responseWriter = new StringWriter(); + when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter)); + + servletUnderTest = new DocumentServlet(); + } + + @After + public void tearDown() { + helper.tearDown(); + } + + @Test + public void doGet_successfulyInvoked() throws Exception { + servletUnderTest.doGet(mockRequest, mockResponse); + String content = responseWriter.toString(); + assertThat(content) + .named("DocumentServlet response: coverLetter") + .contains("coverLetter: CoverLetter"); + assertThat(content) + .named("DocumentServlet response: resume") + .contains("resume: "); + assertThat(content) + .named("DocumentServlet response: fullName") + .contains("fullName: Foo Bar"); + assertThat(content) + .named("DocumentServlet response: submissionDate") + .contains("submissionDate: "); + } + + @Test + public void createDocument_withSignedInUser() throws Exception { + String email = "tmatsuo@example.com"; + String authDomain = "example.com"; + helper.setEnvEmail(email); + helper.setEnvAuthDomain(authDomain); + helper.setEnvIsLoggedIn(true); + Document doc = servletUnderTest.createDocument(); + assertThat(doc.getOnlyField("content").getText()) + .named("content") + .contains("the rain in spain"); + assertThat(doc.getOnlyField("email").getText()) + .named("email") + .isEqualTo(email); + } + + @Test + public void createDocument_withoutSignedIn() throws Exception { + helper.setEnvIsLoggedIn(false); + Document doc = servletUnderTest.createDocument(); + assertThat(doc.getOnlyField("content").getText()) + .named("content") + .contains("the rain in spain"); + assertThat(doc.getOnlyField("email").getText()) + .named("email") + .isEmpty(); + } +} \ No newline at end of file diff --git a/appengine/search/src/test/java/com/example/appengine/search/IndexServletTest.java b/appengine/search/src/test/java/com/example/appengine/search/IndexServletTest.java new file mode 100644 index 00000000000..041ac35e33a --- /dev/null +++ b/appengine/search/src/test/java/com/example/appengine/search/IndexServletTest.java @@ -0,0 +1,50 @@ +package com.example.appengine.search; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import com.google.appengine.tools.development.testing.LocalServiceTestHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.PrintWriter; +import java.io.StringWriter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class IndexServletTest { + private final LocalServiceTestHelper helper = new LocalServiceTestHelper(); + + @Mock private HttpServletRequest mockRequest; + @Mock private HttpServletResponse mockResponse; + private StringWriter responseWriter; + private IndexServlet servletUnderTest; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + helper.setUp(); + + // Set up a fake HTTP response. + responseWriter = new StringWriter(); + when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter)); + + servletUnderTest = new IndexServlet(); + } + + @After + public void tearDown() { + helper.tearDown(); + } + + @Test + public void doGet_successfulyInvoked() throws Exception { + servletUnderTest.doGet(mockRequest, mockResponse); + assertThat(responseWriter.toString()) + .named("IndexServlet response") + .contains("myField: myValue"); + } +} \ No newline at end of file diff --git a/appengine/search/src/test/java/com/example/appengine/search/SearchServletTest.java b/appengine/search/src/test/java/com/example/appengine/search/SearchServletTest.java new file mode 100644 index 00000000000..719855cb472 --- /dev/null +++ b/appengine/search/src/test/java/com/example/appengine/search/SearchServletTest.java @@ -0,0 +1,54 @@ +package com.example.appengine.search; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import com.google.appengine.tools.development.testing.LocalServiceTestHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.PrintWriter; +import java.io.StringWriter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class SearchServletTest { + private final LocalServiceTestHelper helper = new LocalServiceTestHelper(); + + @Mock private HttpServletRequest mockRequest; + @Mock private HttpServletResponse mockResponse; + private StringWriter responseWriter; + private SearchServlet servletUnderTest; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + helper.setUp(); + + // Set up a fake HTTP response. + responseWriter = new StringWriter(); + when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter)); + + servletUnderTest = new SearchServlet(); + } + + @After + public void tearDown() { + helper.tearDown(); + } + + @Test + public void doGet_successfulyInvoked() throws Exception { + servletUnderTest.doGet(mockRequest, mockResponse); + String content = responseWriter.toString(); + assertThat(content) + .named("SearchServlet response") + .contains("maker: Yamaha"); + assertThat(content) + .named("SearchServlet response") + .contains("price: 4000.0"); + } +} \ No newline at end of file diff --git a/appengine/search/src/test/java/com/example/appengine/search/UtilsTest.java b/appengine/search/src/test/java/com/example/appengine/search/UtilsTest.java new file mode 100644 index 00000000000..491cd377b23 --- /dev/null +++ b/appengine/search/src/test/java/com/example/appengine/search/UtilsTest.java @@ -0,0 +1,46 @@ +package com.example.appengine.search; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.appengine.api.search.Document; +import com.google.appengine.api.search.Field; +import com.google.appengine.api.search.Index; +import com.google.appengine.api.search.IndexSpec; +import com.google.appengine.api.search.SearchServiceFactory; +import com.google.appengine.tools.development.testing.LocalServiceTestHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +public class UtilsTest { + private static final String INDEX = "UtilsTestIndex"; + private final LocalServiceTestHelper helper = new LocalServiceTestHelper(); + + @Before + public void setUp() throws Exception { + helper.setUp(); + } + + @After + public void tearDown() { + helper.tearDown(); + } + + @Test + public void indexADocument_successfullyInvoked() throws Exception { + String id = "test"; + Document doc = Document.newBuilder() + .setId(id) + .addField(Field.newBuilder().setName("f").setText("v")) + .build(); + Utils.indexADocument(INDEX, doc); + // get the document by id + IndexSpec indexSpec = IndexSpec.newBuilder().setName(INDEX).build(); + Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec); + Document fetched = index.get(id); + assertThat(fetched.getOnlyField("f").getText()) + .named("A value of the fetched document") + .isEqualTo("v"); + } +} \ No newline at end of file diff --git a/appengine/search/suppressions.xml b/appengine/search/suppressions.xml new file mode 100644 index 00000000000..22a348c205e --- /dev/null +++ b/appengine/search/suppressions.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index f2a2134fea3..266efd87391 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ - 1.9.34 + 1.9.36 1 1.19.0 1.19.0 @@ -51,6 +51,7 @@ appengine/mailjet appengine/memcache appengine/oauth2 + appengine/search appengine/sendgrid appengine/static-files appengine/twilio