diff --git a/retail/interactive-tutorials/pom.xml b/retail/interactive-tutorials/pom.xml
new file mode 100644
index 00000000000..c8dd8e57ce4
--- /dev/null
+++ b/retail/interactive-tutorials/pom.xml
@@ -0,0 +1,69 @@
+
+
+ 4.0.0
+ com.google.cloud
+ retail-interactive-tutorials
+ jar
+ Google Cloud Retail Interactive Tutorials
+ https://github.com/googleapis/java-retail
+
+
+
+ com.google.cloud.samples
+ shared-configuration
+ 1.2.0
+
+
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+
+ com.google.cloud
+ google-cloud-retail
+ 2.0.6
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+ com.google.cloud
+ google-cloud-bigquery
+ 2.5.1
+
+
+ com.google.cloud
+ google-cloud-storage
+ 2.2.2
+
+
+ com.google.code.gson
+ gson
+ 2.8.9
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.2.1
+
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithFiltering.java b/retail/interactive-tutorials/src/main/java/search/SearchWithFiltering.java
new file mode 100644
index 00000000000..11e70e5f187
--- /dev/null
+++ b/retail/interactive-tutorials/src/main/java/search/SearchWithFiltering.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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.
+ */
+
+// [START retail_search_for_products_with_filter]
+
+/*
+ * Call Retail API to search for a products in a catalog,
+ * filter the results by different product fields.
+ */
+
+package search;
+
+import com.google.cloud.retail.v2.SearchRequest;
+import com.google.cloud.retail.v2.SearchResponse;
+import com.google.cloud.retail.v2.SearchServiceClient;
+import java.io.IOException;
+import java.util.UUID;
+
+public class SearchWithFiltering {
+
+ public static void main(String[] args) throws IOException {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ getSearchResponse(defaultSearchPlacementName);
+ }
+
+ public static SearchResponse getSearchResponse(String defaultSearchPlacementName)
+ throws IOException {
+ // TRY DIFFERENT FILTER EXPRESSIONS HERE:
+ String filter = "(colorFamilies: ANY(\"Black\"))";
+ String queryPhrase = "Tee";
+ int pageSize = 10;
+ String visitorId = UUID.randomUUID().toString();
+
+ SearchRequest searchRequest =
+ SearchRequest.newBuilder()
+ .setPlacement(defaultSearchPlacementName)
+ .setVisitorId(visitorId)
+ .setQuery(queryPhrase)
+ .setPageSize(pageSize)
+ .setFilter(filter)
+ .build();
+
+ System.out.println("Search request: " + searchRequest);
+
+ try (SearchServiceClient client = SearchServiceClient.create()) {
+ SearchResponse searchResponse = client.search(searchRequest).getPage().getResponse();
+ System.out.println("Search response: " + searchResponse);
+
+ return searchResponse;
+ }
+ }
+}
+
+// [END retail_search_for_products_with_filter]
diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithOrdering.java b/retail/interactive-tutorials/src/main/java/search/SearchWithOrdering.java
new file mode 100644
index 00000000000..82b43a99bd6
--- /dev/null
+++ b/retail/interactive-tutorials/src/main/java/search/SearchWithOrdering.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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.
+ */
+
+// [START retail_search_for_products_with_ordering]
+
+/*
+ * Call Retail API to search for a products in a catalog,
+ * order the results by different product fields.
+ */
+
+package search;
+
+import com.google.cloud.retail.v2.SearchRequest;
+import com.google.cloud.retail.v2.SearchResponse;
+import com.google.cloud.retail.v2.SearchServiceClient;
+import java.io.IOException;
+import java.util.UUID;
+
+public class SearchWithOrdering {
+
+ public static void main(String[] args) throws IOException {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ getSearchResponse(defaultSearchPlacementName);
+ }
+
+ public static SearchResponse getSearchResponse(String defaultSearchPlacementName)
+ throws IOException {
+ // TRY DIFFERENT ORDER BY EXPRESSION HERE:
+ String order = "price desc";
+ String queryPhrase = "Hoodie";
+ int pageSize = 10;
+ String visitorId = UUID.randomUUID().toString();
+
+ SearchRequest searchRequest =
+ SearchRequest.newBuilder()
+ .setPlacement(defaultSearchPlacementName)
+ .setQuery(queryPhrase)
+ .setOrderBy(order)
+ .setVisitorId(visitorId)
+ .setPageSize(pageSize)
+ .build();
+ System.out.println("Search request: " + searchRequest);
+
+ try (SearchServiceClient client = SearchServiceClient.create()) {
+ SearchResponse searchResponse = client.search(searchRequest).getPage().getResponse();
+ System.out.println("Search response: " + searchResponse);
+
+ return searchResponse;
+ }
+ }
+}
+
+// [END retail_search_for_products_with_ordering]
diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithPagination.java b/retail/interactive-tutorials/src/main/java/search/SearchWithPagination.java
new file mode 100644
index 00000000000..6a7d270ecc4
--- /dev/null
+++ b/retail/interactive-tutorials/src/main/java/search/SearchWithPagination.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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.
+ */
+
+// [START retail_search_for_products_with_page_size]
+
+/*
+ * Call Retail API to search for a products in a catalog,
+ * limit the number of the products per page and go to the next page
+ * using "next_page_token" or jump to chosen page using "offset".
+ */
+
+package search;
+
+import com.google.cloud.retail.v2.SearchRequest;
+import com.google.cloud.retail.v2.SearchResponse;
+import com.google.cloud.retail.v2.SearchServiceClient;
+import java.io.IOException;
+import java.util.UUID;
+
+public class SearchWithPagination {
+
+ public static void main(String[] args) throws IOException {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ getSearchResponse(defaultSearchPlacementName);
+ }
+
+ public static SearchResponse getSearchResponse(String defaultSearchPlacementName)
+ throws IOException {
+ // TRY DIFFERENT PAGINATION PARAMETERS HERE:
+ int pageSize = 6;
+ String queryPhrase = "Hoodie";
+ int offset = 0;
+ String pageToken = "";
+ String visitorId = UUID.randomUUID().toString();
+
+ SearchRequest searchRequest =
+ SearchRequest.newBuilder()
+ .setPlacement(defaultSearchPlacementName)
+ .setVisitorId(visitorId)
+ .setQuery(queryPhrase)
+ .setPageSize(pageSize)
+ .setOffset(offset)
+ .setPageToken(pageToken)
+ .build();
+ System.out.println("Search request: " + searchRequest);
+
+ try (SearchServiceClient client = SearchServiceClient.create()) {
+ SearchResponse searchResponseFirstPage = client.search(searchRequest).getPage().getResponse();
+ System.out.println("Search response: " + searchResponseFirstPage);
+
+ // PASTE CALL WITH NEXT PAGE TOKEN HERE:
+
+ // PASTE CALL WITH OFFSET HERE:
+
+ return searchResponseFirstPage;
+ }
+ }
+}
+
+// [END retail_search_for_products_with_page_size]
diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithQueryExpansionSpec.java b/retail/interactive-tutorials/src/main/java/search/SearchWithQueryExpansionSpec.java
new file mode 100644
index 00000000000..30275d39092
--- /dev/null
+++ b/retail/interactive-tutorials/src/main/java/search/SearchWithQueryExpansionSpec.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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.
+ */
+
+// [START retail_search_for_products_with_query_expansion_specification]
+
+/*
+ * Call Retail API to search for a products in a catalog,
+ * enabling the query expansion feature to let the Google Retail Search
+ * build an automatic query expansion.
+ */
+
+package search;
+
+import com.google.cloud.retail.v2.SearchRequest;
+import com.google.cloud.retail.v2.SearchRequest.QueryExpansionSpec;
+import com.google.cloud.retail.v2.SearchRequest.QueryExpansionSpec.Condition;
+import com.google.cloud.retail.v2.SearchResponse;
+import com.google.cloud.retail.v2.SearchServiceClient;
+import java.io.IOException;
+import java.util.UUID;
+
+public class SearchWithQueryExpansionSpec {
+
+ public static void main(String[] args) throws IOException {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ getSearchResponse(defaultSearchPlacementName);
+ }
+
+ public static SearchResponse getSearchResponse(String defaultSearchPlacementName)
+ throws IOException {
+ // TRY DIFFERENT QUERY EXPANSION CONDITION HERE:
+ Condition condition = Condition.AUTO;
+ int pageSize = 10;
+ String queryPhrase = "Google Youth Hero Tee Grey";
+ String visitorId = UUID.randomUUID().toString();
+
+ QueryExpansionSpec queryExpansionSpec =
+ QueryExpansionSpec.newBuilder().setCondition(condition).build();
+
+ SearchRequest searchRequest =
+ SearchRequest.newBuilder()
+ .setPlacement(defaultSearchPlacementName)
+ .setQuery(queryPhrase)
+ .setVisitorId(visitorId)
+ .setQueryExpansionSpec(queryExpansionSpec)
+ .setPageSize(pageSize)
+ .build();
+ System.out.println("Search request: " + searchRequest);
+
+ try (SearchServiceClient client = SearchServiceClient.create()) {
+ SearchResponse searchResponse = client.search(searchRequest).getPage().getResponse();
+ System.out.println("Search response: " + searchResponse);
+
+ return searchResponse;
+ }
+ }
+}
+
+// [END retail_search_for_products_with_query_expansion_specification]
diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithFilteringTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithFilteringTest.java
new file mode 100644
index 00000000000..5c8401d5188
--- /dev/null
+++ b/retail/interactive-tutorials/src/test/java/search/SearchWithFilteringTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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 search;
+
+import com.google.cloud.retail.v2.SearchResponse;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import util.StreamGobbler;
+
+public class SearchWithFilteringTest {
+
+ private String output;
+ private String defaultSearchPlacementName;
+
+ @Before
+ public void setUp() throws IOException, InterruptedException, ExecutionException {
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ Process exec =
+ Runtime.getRuntime()
+ .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithFiltering");
+ StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream());
+ Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler);
+
+ output = stringFuture.get();
+ }
+
+ @Test
+ public void testOutput() {
+ Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$"));
+ }
+
+ @Test
+ public void TestSearchWithFiltering() throws IOException {
+ SearchResponse response = SearchWithFiltering.getSearchResponse(defaultSearchPlacementName);
+ Assert.assertEquals(10, response.getResultsCount());
+ String productTitle = response.getResults(0).getProduct().getTitle();
+ Assert.assertTrue(productTitle.contains("Google Black Cloud Tee"));
+ Assert.assertTrue(
+ response.getResults(0).getProduct().getColorInfo().getColorFamilies(0).contains("Black"));
+ Assert.assertEquals(16, response.getTotalSize());
+ }
+}
diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithOrderingTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithOrderingTest.java
new file mode 100644
index 00000000000..80244c192d8
--- /dev/null
+++ b/retail/interactive-tutorials/src/test/java/search/SearchWithOrderingTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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 search;
+
+import com.google.cloud.retail.v2.SearchResponse;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import util.StreamGobbler;
+
+public class SearchWithOrderingTest {
+
+ private String output;
+ private String defaultSearchPlacementName;
+
+ @Before
+ public void setUp() throws IOException, InterruptedException, ExecutionException {
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ Process exec =
+ Runtime.getRuntime()
+ .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithOrdering");
+ StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream());
+ Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler);
+
+ output = stringFuture.get();
+ }
+
+ @Test
+ public void testOutput() {
+ Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$"));
+ }
+
+ @Test
+ public void TestSearchWithOrdering() throws IOException {
+ SearchResponse response = SearchWithOrdering.getSearchResponse(defaultSearchPlacementName);
+ Assert.assertEquals(10, response.getResultsCount());
+ String productTitle = response.getResults(3).getProduct().getTitle();
+ Assert.assertTrue(productTitle.contains("Hoodie"));
+ Assert.assertEquals(39, response.getResults(0).getProduct().getPriceInfo().getPrice(), 0);
+ }
+}
diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithPaginationTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithPaginationTest.java
new file mode 100644
index 00000000000..9b618ccd485
--- /dev/null
+++ b/retail/interactive-tutorials/src/test/java/search/SearchWithPaginationTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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 search;
+
+import com.google.cloud.retail.v2.SearchResponse;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import util.StreamGobbler;
+
+public class SearchWithPaginationTest {
+ private String output;
+ private String defaultSearchPlacementName;
+
+ @Before
+ public void setUp() throws IOException, InterruptedException, ExecutionException {
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ Process exec =
+ Runtime.getRuntime()
+ .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithPagination");
+ StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream());
+ Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler);
+
+ output = stringFuture.get();
+ }
+
+ @Test
+ public void testOutput() {
+ Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$"));
+ }
+
+ @Test
+ public void TestSearchWithOrdering() throws IOException {
+ SearchResponse response = SearchWithPagination.getSearchResponse(defaultSearchPlacementName);
+ String productTitle = response.getResults(0).getProduct().getTitle();
+ Assert.assertTrue(productTitle.contains("Hoodie"));
+ Assert.assertEquals(6, response.getResultsCount());
+ }
+}
diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithQueryExpansionSpecTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithQueryExpansionSpecTest.java
new file mode 100644
index 00000000000..ce91e06a55f
--- /dev/null
+++ b/retail/interactive-tutorials/src/test/java/search/SearchWithQueryExpansionSpecTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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 search;
+
+import com.google.cloud.retail.v2.SearchResponse;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import util.StreamGobbler;
+
+public class SearchWithQueryExpansionSpecTest {
+
+ private String output;
+ private String defaultSearchPlacementName;
+
+ @Before
+ public void setUp() throws IOException, InterruptedException, ExecutionException {
+ String projectId = System.getenv("PROJECT_ID");
+ String defaultCatalogName =
+ String.format("projects/%s/locations/global/catalogs/default_catalog", projectId);
+ defaultSearchPlacementName = defaultCatalogName + "/placements/default_search";
+
+ Process exec =
+ Runtime.getRuntime()
+ .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithQueryExpansionSpec");
+ StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream());
+ Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler);
+
+ output = stringFuture.get();
+ }
+
+ @Test
+ public void testOutput() {
+ Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$"));
+ Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$"));
+ }
+
+ @Test
+ public void testSearchWithQueryExpansionSpec() throws IOException {
+ SearchResponse response =
+ SearchWithQueryExpansionSpec.getSearchResponse(defaultSearchPlacementName);
+ Assert.assertEquals(10, response.getResultsCount());
+ Assert.assertTrue(
+ response.getResults(0).getProduct().getTitle().contains("Google Youth Hero Tee Grey"));
+ Assert.assertFalse(
+ response.getResults(2).getProduct().getTitle().contains("Google Youth Hero Tee Grey"));
+ Assert.assertTrue(response.getQueryExpansionInfo().getExpandedQuery());
+ }
+}
diff --git a/retail/interactive-tutorials/src/test/java/util/StreamGobbler.java b/retail/interactive-tutorials/src/test/java/util/StreamGobbler.java
new file mode 100644
index 00000000000..a9c3c3a795b
--- /dev/null
+++ b/retail/interactive-tutorials/src/test/java/util/StreamGobbler.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * 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 util;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
+
+public class StreamGobbler implements Callable {
+
+ private final InputStream inputStream;
+
+ public StreamGobbler(InputStream inputStream) {
+ this.inputStream = inputStream;
+ }
+
+ @Override
+ public String call() {
+ List stringList =
+ new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.toList());
+ return String.join("\n", stringList);
+ }
+}