aboutsummaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorCassie Wang <cassiewang@google.com>2020-01-20 22:39:24 -0800
committerCassie Wang <cassiewang@google.com>2020-02-28 14:45:01 -0800
commit43fec62894253136f0c8b6a0aa5132ddff6edaf7 (patch)
tree273f7807c68629771d1a03344ab17d207ae212b9 /java
parent8d99a2d3b71f111de0d83608c31ec3dc2ef29d3d (diff)
downloadicing-43fec62894253136f0c8b6a0aa5132ddff6edaf7.tar.gz
Create JNI layer for Icing
Bug: 146383629 Test: manual 'atest java/tests/instrumentation/src/com/google/android/icing/IcingSearchEngineTest.java' Change-Id: I3868ca19a477bd6996f268d2a73a1dc906afaee6
Diffstat (limited to 'java')
-rw-r--r--java/Android.bp22
-rw-r--r--java/src/com/google/android/icing/IcingSearchEngine.java347
-rw-r--r--java/tests/instrumentation/Android.bp42
-rw-r--r--java/tests/instrumentation/AndroidManifest.xml30
-rw-r--r--java/tests/instrumentation/src/com/google/android/icing/IcingSearchEngineTest.java284
5 files changed, 725 insertions, 0 deletions
diff --git a/java/Android.bp b/java/Android.bp
new file mode 100644
index 0000000..6bc8836
--- /dev/null
+++ b/java/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// 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.
+
+java_library {
+ name: "libicing-java",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "icing-java-proto-lite",
+ "libprotobuf-java-lite",
+ ],
+}
diff --git a/java/src/com/google/android/icing/IcingSearchEngine.java b/java/src/com/google/android/icing/IcingSearchEngine.java
new file mode 100644
index 0000000..03a4fbe
--- /dev/null
+++ b/java/src/com/google/android/icing/IcingSearchEngine.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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.google.android.icing;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import com.google.android.icing.proto.DeleteByNamespaceResultProto;
+import com.google.android.icing.proto.DeleteBySchemaTypeResultProto;
+import com.google.android.icing.proto.DeleteResultProto;
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.GetResultProto;
+import com.google.android.icing.proto.GetSchemaResultProto;
+import com.google.android.icing.proto.GetSchemaTypeResultProto;
+import com.google.android.icing.proto.IcingSearchEngineOptions;
+import com.google.android.icing.proto.InitializeResultProto;
+import com.google.android.icing.proto.OptimizeResultProto;
+import com.google.android.icing.proto.PersistToDiskResultProto;
+import com.google.android.icing.proto.PutResultProto;
+import com.google.android.icing.proto.ResultSpecProto;
+import com.google.android.icing.proto.SchemaProto;
+import com.google.android.icing.proto.ScoringSpecProto;
+import com.google.android.icing.proto.SearchResultProto;
+import com.google.android.icing.proto.SearchSpecProto;
+import com.google.android.icing.proto.SetSchemaResultProto;
+import com.google.android.icing.proto.StatusProto;
+import com.google.android.icing.protobuf.InvalidProtocolBufferException;
+
+/** Java wrapper to access native APIs in external/icing/icing/icing-search-engine.h */
+public final class IcingSearchEngine {
+
+ private static final String TAG = "IcingSearchEngine";
+
+ private long mNativePointer;
+
+ static {
+ // NOTE: This can fail with an UnsatisfiedLinkError
+ System.loadLibrary("icing_jni");
+ }
+
+ /**
+ * @throws RuntimeException if IcingSearchEngine fails to be created
+ */
+ public IcingSearchEngine(IcingSearchEngineOptions options) {
+ mNativePointer = nativeCreate(options.toByteArray());
+ if (mNativePointer == 0) {
+ Log.e(TAG, "Failed to create IcingSearchEngine.");
+ throw new RuntimeException("Failed to create IcingSearchEngine.");
+ }
+ }
+
+
+ @NonNull
+ public InitializeResultProto initialize() {
+ byte[] initializeResultBytes = nativeInitialize(mNativePointer);
+ if (initializeResultBytes == null) {
+ Log.e(TAG, "Received null InitializeResult from native.");
+ return InitializeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return InitializeResultProto.parseFrom(initializeResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing InitializeResultProto.", e);
+ return InitializeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public SetSchemaResultProto setSchema(@NonNull SchemaProto schema) {
+ return setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
+ }
+
+ @NonNull
+ public SetSchemaResultProto setSchema(
+ @NonNull SchemaProto schema, boolean ignoreErrorsAndDeleteDocuments) {
+ byte[] setSchemaResultBytes =
+ nativeSetSchema(mNativePointer, schema.toByteArray(), ignoreErrorsAndDeleteDocuments);
+ if (setSchemaResultBytes == null) {
+ Log.e(TAG, "Received null SetSchemaResultProto from native.");
+ return SetSchemaResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return SetSchemaResultProto.parseFrom(setSchemaResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing SetSchemaResultProto.", e);
+ return SetSchemaResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public GetSchemaResultProto getSchema() {
+ byte[] getSchemaResultBytes = nativeGetSchema(mNativePointer);
+ if (getSchemaResultBytes == null) {
+ Log.e(TAG, "Received null GetSchemaResultProto from native.");
+ return GetSchemaResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return GetSchemaResultProto.parseFrom(getSchemaResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing GetSchemaResultProto.", e);
+ return GetSchemaResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public GetSchemaTypeResultProto getSchemaType(@NonNull String schemaType) {
+ byte[] getSchemaTypeResultBytes = nativeGetSchemaType(mNativePointer, schemaType);
+ if (getSchemaTypeResultBytes == null) {
+ Log.e(TAG, "Received null GetSchemaTypeResultProto from native.");
+ return GetSchemaTypeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return GetSchemaTypeResultProto.parseFrom(getSchemaTypeResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing GetSchemaTypeResultProto.", e);
+ return GetSchemaTypeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public PutResultProto put(@NonNull DocumentProto document) {
+ byte[] putResultBytes = nativePut(mNativePointer, document.toByteArray());
+ if (putResultBytes == null) {
+ Log.e(TAG, "Received null PutResultProto from native.");
+ return PutResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return PutResultProto.parseFrom(putResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing PutResultProto.", e);
+ return PutResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public GetResultProto get(@NonNull String namespace, @NonNull String uri) {
+ byte[] getResultBytes = nativeGet(mNativePointer, namespace, uri);
+ if (getResultBytes == null) {
+ Log.e(TAG, "Received null GetResultProto from native.");
+ return GetResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return GetResultProto.parseFrom(getResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing GetResultProto.", e);
+ return GetResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public SearchResultProto search(
+ @NonNull SearchSpecProto searchSpec, @NonNull ScoringSpecProto scoringSpec, @NonNull ResultSpecProto resultSpec) {
+ byte[] searchResultBytes =
+ nativeSearch(
+ mNativePointer,
+ searchSpec.toByteArray(),
+ scoringSpec.toByteArray(),
+ resultSpec.toByteArray());
+ if (searchResultBytes == null) {
+ Log.e(TAG, "Received null SearchResultProto from native.");
+ return SearchResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return SearchResultProto.parseFrom(searchResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing SearchResultProto.", e);
+ return SearchResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public DeleteResultProto delete(@NonNull String namespace, @NonNull String uri) {
+ byte[] deleteResultBytes = nativeDelete(mNativePointer, namespace, uri);
+ if (deleteResultBytes == null) {
+ Log.e(TAG, "Received null DeleteResultProto from native.");
+ return DeleteResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return DeleteResultProto.parseFrom(deleteResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing DeleteResultProto.", e);
+ return DeleteResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public DeleteByNamespaceResultProto deleteByNamespace(@NonNull String namespace) {
+ byte[] deleteByNamespaceResultBytes = nativeDeleteByNamespace(mNativePointer, namespace);
+ if (deleteByNamespaceResultBytes == null) {
+ Log.e(TAG, "Received null DeleteByNamespaceResultProto from native.");
+ return DeleteByNamespaceResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return DeleteByNamespaceResultProto.parseFrom(deleteByNamespaceResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing DeleteByNamespaceResultProto.", e);
+ return DeleteByNamespaceResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public DeleteBySchemaTypeResultProto deleteBySchemaType(@NonNull String schemaType) {
+ byte[] deleteBySchemaTypeResultBytes = nativeDeleteBySchemaType(mNativePointer, schemaType);
+ if (deleteBySchemaTypeResultBytes == null) {
+ Log.e(TAG, "Received null DeleteBySchemaTypeResultProto from native.");
+ return DeleteBySchemaTypeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return DeleteBySchemaTypeResultProto.parseFrom(deleteBySchemaTypeResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing DeleteBySchemaTypeResultProto.", e);
+ return DeleteBySchemaTypeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public PersistToDiskResultProto persistToDisk() {
+ byte[] persistToDiskResultBytes = nativePersistToDisk(mNativePointer);
+ if (persistToDiskResultBytes == null) {
+ Log.e(TAG, "Received null PersistToDiskResultProto from native.");
+ return PersistToDiskResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return PersistToDiskResultProto.parseFrom(persistToDiskResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing PersistToDiskResultProto.", e);
+ return PersistToDiskResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ @NonNull
+ public OptimizeResultProto optimize() {
+ byte[] optimizeResultBytes = nativeOptimize(mNativePointer);
+ if (optimizeResultBytes == null) {
+ Log.e(TAG, "Received null OptimizeResultProto from native.");
+ return OptimizeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+
+ try {
+ return OptimizeResultProto.parseFrom(optimizeResultBytes);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e(TAG, "Error parsing OptimizeResultProto.", e);
+ return OptimizeResultProto.newBuilder()
+ .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
+ .build();
+ }
+ }
+
+ private static native long nativeCreate(byte[] icingSearchEngineOptionsBytes);
+
+ private static native byte[] nativeInitialize(long mNativePointer);
+
+ private static native byte[] nativeSetSchema(
+ long mNativePointer, byte[] schemaBytes, boolean ignoreErrorsAndDeleteDocuments);
+
+ private static native byte[] nativeGetSchema(long mNativePointer);
+
+ private static native byte[] nativeGetSchemaType(long mNativePointer, String schemaType);
+
+ private static native byte[] nativePut(long mNativePointer, byte[] documentBytes);
+
+ private static native byte[] nativeGet(long mNativePointer, String namespace, String uri);
+
+ private static native byte[] nativeSearch(
+ long mNativePointer, byte[] searchSpecBytes, byte[] scoringSpecBytes, byte[] resultSpecBytes);
+
+ private static native byte[] nativeDelete(long mNativePointer, String namespace, String uri);
+
+ private static native byte[] nativeDeleteByNamespace(long mNativePointer, String namespace);
+
+ private static native byte[] nativeDeleteBySchemaType(long mNativePointer, String schemaType);
+
+ private static native byte[] nativePersistToDisk(long mNativePointer);
+
+ private static native byte[] nativeOptimize(long mNativePointer);
+}
diff --git a/java/tests/instrumentation/Android.bp b/java/tests/instrumentation/Android.bp
new file mode 100644
index 0000000..c941acf
--- /dev/null
+++ b/java/tests/instrumentation/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+android_test {
+ name: "IcingSearchEngineTest",
+
+ manifest: "AndroidManifest.xml",
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "androidx.test.ext.truth",
+ "libicing-java",
+ "icing-java-proto-lite",
+ ],
+
+ jni_libs: [
+ "libicing_jni",
+ ],
+
+ test_suites: [
+ "device-tests",
+ ],
+
+ platform_apis: true,
+ use_embedded_native_libs: true,
+}
diff --git a/java/tests/instrumentation/AndroidManifest.xml b/java/tests/instrumentation/AndroidManifest.xml
new file mode 100644
index 0000000..790e5da
--- /dev/null
+++ b/java/tests/instrumentation/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.icing">
+
+ <uses-sdk android:minSdkVersion="28"/>
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.google.android.icing"/>
+</manifest>
diff --git a/java/tests/instrumentation/src/com/google/android/icing/IcingSearchEngineTest.java b/java/tests/instrumentation/src/com/google/android/icing/IcingSearchEngineTest.java
new file mode 100644
index 0000000..5c502d9
--- /dev/null
+++ b/java/tests/instrumentation/src/com/google/android/icing/IcingSearchEngineTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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.google.android.icing;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.google.android.icing.proto.DeleteByNamespaceResultProto;
+import com.google.android.icing.proto.DeleteBySchemaTypeResultProto;
+import com.google.android.icing.proto.DeleteResultProto;
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.GetResultProto;
+import com.google.android.icing.proto.GetSchemaResultProto;
+import com.google.android.icing.proto.GetSchemaTypeResultProto;
+import com.google.android.icing.proto.IcingSearchEngineOptions;
+import com.google.android.icing.proto.IndexingConfig;
+import com.google.android.icing.proto.IndexingConfig.TokenizerType;
+import com.google.android.icing.proto.InitializeResultProto;
+import com.google.android.icing.proto.OptimizeResultProto;
+import com.google.android.icing.proto.PersistToDiskResultProto;
+import com.google.android.icing.proto.PropertyConfigProto;
+import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.PutResultProto;
+import com.google.android.icing.proto.ResultSpecProto;
+import com.google.android.icing.proto.SchemaProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
+import com.google.android.icing.proto.ScoringSpecProto;
+import com.google.android.icing.proto.SearchResultProto;
+import com.google.android.icing.proto.SearchSpecProto;
+import com.google.android.icing.proto.SetSchemaResultProto;
+import com.google.android.icing.proto.StatusProto;
+import com.google.android.icing.proto.TermMatchType;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * This test is not intended to fully test the functionality of each API. But rather to test the JNI
+ * wrapper of Icing library.
+ */
+@RunWith(JUnit4.class)
+public final class IcingSearchEngineTest {
+
+ private static final String EMAIL_TYPE = "Email";
+
+ private Context mContext;
+ private String mFilesDir;
+
+ static SchemaTypeConfigProto createEmailTypeConfig() {
+ return SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(EMAIL_TYPE)
+ .addProperties(
+ PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ IndexingConfig.newBuilder()
+ .setTokenizerType(TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)))
+ .addProperties(
+ PropertyConfigProto.newBuilder()
+ .setPropertyName("body")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ IndexingConfig.newBuilder()
+ .setTokenizerType(TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)))
+ .build();
+ }
+
+ static DocumentProto createEmailDocument(String namespace, String uri) {
+ return DocumentProto.newBuilder()
+ .setNamespace(namespace)
+ .setUri(uri)
+ .setSchema(EMAIL_TYPE)
+ .setCreationTimestampMs(1) // Arbitrary non-zero number so Icing doesn't override it
+ .build();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ mFilesDir = mContext.getFilesDir().getCanonicalPath();
+ }
+
+ @Test
+ public void testInitialize() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+
+ InitializeResultProto initializeResultProto = icing.initialize();
+ assertThat(initializeResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ }
+
+ @Test
+ public void testSetAndGetSchema() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ SchemaTypeConfigProto emailTypeConfig = createEmailTypeConfig();
+ SchemaProto schema = SchemaProto.newBuilder().addTypes(emailTypeConfig).build();
+ SetSchemaResultProto setSchemaResultProto =
+ icing.setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
+ assertThat(setSchemaResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+
+ GetSchemaResultProto getSchemaResultProto = icing.getSchema();
+ assertThat(getSchemaResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ assertThat(getSchemaResultProto.getSchema()).isEqualTo(schema);
+
+ GetSchemaTypeResultProto getSchemaTypeResultProto =
+ icing.getSchemaType(emailTypeConfig.getSchemaType());
+ assertThat(getSchemaTypeResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ assertThat(getSchemaTypeResultProto.getSchemaTypeConfig()).isEqualTo(emailTypeConfig);
+ }
+
+ @Test
+ public void testPutAndGetDocuments() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ SchemaTypeConfigProto emailTypeConfig = createEmailTypeConfig();
+ SchemaProto schema = SchemaProto.newBuilder().addTypes(emailTypeConfig).build();
+ SetSchemaResultProto setSchemaResultProto =
+ icing.setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
+
+ DocumentProto emailDocument = createEmailDocument("namespace", "uri");
+ PutResultProto putResultProto = icing.put(emailDocument);
+ assertThat(putResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+
+ GetResultProto getResultProto = icing.get("namespace", "uri");
+ assertThat(getResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ assertThat(getResultProto.getDocument()).isEqualTo(emailDocument);
+ }
+
+ @Test
+ public void testSearch() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ SchemaTypeConfigProto emailTypeConfig = createEmailTypeConfig();
+ SchemaProto schema = SchemaProto.newBuilder().addTypes(emailTypeConfig).build();
+ SetSchemaResultProto setSchemaResultProto =
+ icing.setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
+
+ DocumentProto emailDocument =
+ createEmailDocument("namespace", "uri").toBuilder()
+ .addProperties(PropertyProto.newBuilder().setName("subject").addStringValues("foo"))
+ .build();
+ PutResultProto putResultProto = icing.put(emailDocument);
+
+ SearchSpecProto searchSpec =
+ SearchSpecProto.newBuilder()
+ .setQuery("foo")
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ .build();
+
+ SearchResultProto searchResultProto =
+ icing.search(
+ searchSpec,
+ ScoringSpecProto.getDefaultInstance(),
+ ResultSpecProto.getDefaultInstance());
+ assertThat(searchResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ assertThat(searchResultProto.getResultsCount()).isEqualTo(1);
+ assertThat(searchResultProto.getResults(0).getDocument()).isEqualTo(emailDocument);
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ SchemaTypeConfigProto emailTypeConfig = createEmailTypeConfig();
+ SchemaProto schema = SchemaProto.newBuilder().addTypes(emailTypeConfig).build();
+ SetSchemaResultProto setSchemaResultProto =
+ icing.setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
+
+ DocumentProto emailDocument = createEmailDocument("namespace", "uri");
+ PutResultProto putResultProto = icing.put(emailDocument);
+
+ DeleteResultProto deleteResultProto = icing.delete("namespace", "uri");
+ assertThat(deleteResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+
+ GetResultProto getResultProto = icing.get("namespace", "uri");
+ assertThat(getResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.NOT_FOUND);
+ }
+
+ @Test
+ public void testDeleteByNamespace() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ SchemaTypeConfigProto emailTypeConfig = createEmailTypeConfig();
+ SchemaProto schema = SchemaProto.newBuilder().addTypes(emailTypeConfig).build();
+ SetSchemaResultProto setSchemaResultProto =
+ icing.setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
+
+ DocumentProto emailDocument = createEmailDocument("namespace", "uri");
+ PutResultProto putResultProto = icing.put(emailDocument);
+
+ DeleteByNamespaceResultProto deleteByNamespaceResultProto =
+ icing.deleteByNamespace("namespace");
+ assertThat(deleteByNamespaceResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+
+ GetResultProto getResultProto = icing.get("namespace", "uri");
+ assertThat(getResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.NOT_FOUND);
+ }
+
+ @Test
+ public void testDeleteBySchemaType() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ SchemaTypeConfigProto emailTypeConfig = createEmailTypeConfig();
+ SchemaProto schema = SchemaProto.newBuilder().addTypes(emailTypeConfig).build();
+ SetSchemaResultProto setSchemaResultProto =
+ icing.setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
+
+ DocumentProto emailDocument = createEmailDocument("namespace", "uri");
+ PutResultProto putResultProto = icing.put(emailDocument);
+
+ DeleteBySchemaTypeResultProto deleteBySchemaTypeResultProto =
+ icing.deleteBySchemaType(EMAIL_TYPE);
+ assertThat(deleteBySchemaTypeResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+
+ GetResultProto getResultProto = icing.get("namespace", "uri");
+ assertThat(getResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.NOT_FOUND);
+ }
+
+ @Test
+ public void testPersistToDisk() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ PersistToDiskResultProto persistToDiskResultProto = icing.persistToDisk();
+ assertThat(persistToDiskResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ }
+
+ @Test
+ public void testOptimize() throws Exception {
+ IcingSearchEngineOptions options =
+ IcingSearchEngineOptions.newBuilder().setBaseDir(mFilesDir).build();
+ IcingSearchEngine icing = new IcingSearchEngine(options);
+ InitializeResultProto initializeResultProto = icing.initialize();
+
+ OptimizeResultProto optimizeResultProto = icing.optimize();
+ assertThat(optimizeResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ }
+}