Browse Source

add dynamic and partition key testcases (#533)

Signed-off-by: yongpengli-z <yongpeng.li@zilliz.com>
yongpengli-z 2 years ago
parent
commit
0652dfb660

+ 1 - 1
tests/milvustest/pom.xml

@@ -84,7 +84,7 @@
         <dependency>
         <dependency>
             <groupId>io.milvus</groupId>
             <groupId>io.milvus</groupId>
             <artifactId>milvus-sdk-java</artifactId>
             <artifactId>milvus-sdk-java</artifactId>
-            <version>2.2.5</version>
+            <version>2.2.6</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>com.google.protobuf</groupId>
             <groupId>com.google.protobuf</groupId>

+ 1 - 0
tests/milvustest/src/main/java/com/zilliz/milvustest/common/CommonData.java

@@ -14,6 +14,7 @@ public class CommonData {
   public static String defaultBinaryAlias = "BinaryAliasAutoTest";
   public static String defaultBinaryAlias = "BinaryAliasAutoTest";
   public static String defaultStringPKBinaryAlias = "StringPKBinaryAliasAutoTest";
   public static String defaultStringPKBinaryAlias = "StringPKBinaryAliasAutoTest";
   public static String defaultVectorField = "book_intro";
   public static String defaultVectorField = "book_intro";
+  public static String defaultPartitionField="book_name";
   public static String defaultBinaryVectorField = "BinaryVectorFieldAutoTest";
   public static String defaultBinaryVectorField = "BinaryVectorFieldAutoTest";
   public static String defaultIndex = "FloatVectorIndex";
   public static String defaultIndex = "FloatVectorIndex";
 
 

+ 266 - 19
tests/milvustest/src/main/java/com/zilliz/milvustest/common/CommonFunction.java

@@ -1,19 +1,19 @@
 package com.zilliz.milvustest.common;
 package com.zilliz.milvustest.common;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.zilliz.milvustest.entity.FileBody;
 import com.zilliz.milvustest.entity.FileBody;
 import com.zilliz.milvustest.entity.MilvusEntity;
 import com.zilliz.milvustest.entity.MilvusEntity;
 import com.zilliz.milvustest.util.MathUtil;
 import com.zilliz.milvustest.util.MathUtil;
 import com.zilliz.milvustest.util.PropertyFilesUtil;
 import com.zilliz.milvustest.util.PropertyFilesUtil;
 import io.milvus.client.MilvusServiceClient;
 import io.milvus.client.MilvusServiceClient;
 import io.milvus.grpc.DataType;
 import io.milvus.grpc.DataType;
-import io.milvus.param.ConnectParam;
-import io.milvus.param.IndexType;
-import io.milvus.param.R;
-import io.milvus.param.RpcStatus;
+import io.milvus.param.*;
 import io.milvus.param.alias.CreateAliasParam;
 import io.milvus.param.alias.CreateAliasParam;
 import io.milvus.param.collection.CreateCollectionParam;
 import io.milvus.param.collection.CreateCollectionParam;
 import io.milvus.param.collection.FieldType;
 import io.milvus.param.collection.FieldType;
+import io.milvus.param.collection.LoadCollectionParam;
 import io.milvus.param.dml.InsertParam;
 import io.milvus.param.dml.InsertParam;
+import io.milvus.param.index.CreateIndexParam;
 import io.milvus.param.partition.CreatePartitionParam;
 import io.milvus.param.partition.CreatePartitionParam;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -26,6 +26,8 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.List;
 import java.util.Random;
 import java.util.Random;
 
 
+import static com.zilliz.milvustest.common.BaseTest.milvusClient;
+
 @Component
 @Component
 public class CommonFunction {
 public class CommonFunction {
   public static Logger logger = LoggerFactory.getLogger(CommonFunction.class);
   public static Logger logger = LoggerFactory.getLogger(CommonFunction.class);
@@ -62,6 +64,45 @@ public class CommonFunction {
     return collectionName;
     return collectionName;
   }
   }
 
 
+  public static String createNewCollectionWithPartitionKey(int partitionKeyNum) {
+    String collectionName = "Collection_" + MathUtil.getRandomString(10);
+    FieldType fieldType1 =
+            FieldType.newBuilder()
+                    .withName("book_id")
+                    .withDataType(DataType.Int64)
+                    .withPrimaryKey(true)
+                    .withAutoID(false)
+                    .build();
+    FieldType fieldType2 =
+            FieldType.newBuilder().withName("word_count").withDataType(DataType.Int64).build();
+    FieldType fieldType3 =
+            FieldType.newBuilder()
+                    .withName(CommonData.defaultVectorField)
+                    .withDataType(DataType.FloatVector)
+                    .withDimension(128)
+                    .build();
+    FieldType fieldType4 = FieldType.newBuilder()
+            .withName(CommonData.defaultPartitionField)
+            .withDataType(DataType.VarChar)
+            .withMaxLength(128)
+            .withPartitionKey(true)
+            .build();
+    CreateCollectionParam createCollectionReq =
+            CreateCollectionParam.newBuilder()
+                    .withCollectionName(collectionName)
+                    .withDescription("Test" + collectionName + "search")
+                    .withShardsNum(2)
+                    .addFieldType(fieldType1)
+                    .addFieldType(fieldType2)
+                    .addFieldType(fieldType3)
+                    .addFieldType(fieldType4)
+                    .withPartitionsNum(partitionKeyNum)
+                    .build();
+    R<RpcStatus> collection = BaseTest.milvusClient.createCollection(createCollectionReq);
+    logger.info("create collection:" + collectionName);
+    return collectionName;
+  }
+
   public static String createNewCollectionWithAutoPK() {
   public static String createNewCollectionWithAutoPK() {
     String collectionName = "Collection_" + MathUtil.getRandomString(10);
     String collectionName = "Collection_" + MathUtil.getRandomString(10);
     FieldType fieldType1 =
     FieldType fieldType1 =
@@ -264,7 +305,30 @@ public class CommonFunction {
     // logger.info("generateTestData"+ JacksonUtil.serialize(fields));
     // logger.info("generateTestData"+ JacksonUtil.serialize(fields));
     return fields;
     return fields;
   }
   }
-
+  public static List<InsertParam.Field> generateDataWithPartitionKey(int num) {
+    Random ran = new Random();
+    List<Long> book_id_array = new ArrayList<>();
+    List<Long> word_count_array = new ArrayList<>();
+    List<String> book_name_array=new ArrayList<>();
+    List<List<Float>> book_intro_array = new ArrayList<>();
+    for (long i = 0L; i < num; ++i) {
+      book_id_array.add(i);
+      word_count_array.add(i + 10000);
+      book_name_array.add("part"+i/1000);
+      List<Float> vector = new ArrayList<>();
+      for (int k = 0; k < 128; ++k) {
+        vector.add(ran.nextFloat());
+      }
+      book_intro_array.add(vector);
+    }
+    List<InsertParam.Field> fields = new ArrayList<>();
+    fields.add(new InsertParam.Field("book_id", book_id_array));
+    fields.add(new InsertParam.Field("word_count", word_count_array));
+    fields.add(new InsertParam.Field(CommonData.defaultPartitionField, book_name_array));
+    fields.add(new InsertParam.Field(CommonData.defaultVectorField, book_intro_array));
+    // logger.info("generateTestData"+ JacksonUtil.serialize(fields));
+    return fields;
+  }
   public static List<InsertParam.Field> generateDataWithAutoPK(int num) {
   public static List<InsertParam.Field> generateDataWithAutoPK(int num) {
     Random ran = new Random();
     Random ran = new Random();
     List<Long> word_count_array = new ArrayList<>();
     List<Long> word_count_array = new ArrayList<>();
@@ -445,20 +509,203 @@ public class CommonFunction {
     return extraParm;
     return extraParm;
   }
   }
 
 
-  public static MilvusServiceClient newMilvusClient(String username,String password) {
-    return new MilvusServiceClient(
-        ConnectParam.newBuilder()
-            .withHost(
-                System.getProperty("milvusHost") == null
-                    ? PropertyFilesUtil.getRunValue("milvusHost")
-                    : System.getProperty("milvusHost"))
-            .withPort(
-                Integer.parseInt(
-                    System.getProperty("milvusPort") == null
-                        ? PropertyFilesUtil.getRunValue("milvusPort")
-                        : System.getProperty("milvusPort")))
-            .withAuthorization(username, password)
-            .withSecure(true)
+  public static String createNewCollectionWithDynamicField() {
+    String collectionName = "Collection_" + MathUtil.getRandomString(10);
+    FieldType fieldType1 =
+            FieldType.newBuilder()
+                    .withName("book_id")
+                    .withDataType(DataType.Int64)
+                    .withPrimaryKey(true)
+                    .withAutoID(false)
+                    .build();
+    FieldType fieldType2 =
+            FieldType.newBuilder().withName("word_count").withDataType(DataType.Int64).build();
+    FieldType fieldType3 =
+            FieldType.newBuilder()
+                    .withName(CommonData.defaultVectorField)
+                    .withDataType(DataType.FloatVector)
+                    .withDimension(128)
+                    .build();
+    CreateCollectionParam createCollectionReq =
+            CreateCollectionParam.newBuilder()
+                    .withCollectionName(collectionName)
+                    .withDescription("Test" + collectionName + "search")
+                    .withShardsNum(2)
+                    .addFieldType(fieldType1)
+                    .addFieldType(fieldType2)
+                    .addFieldType(fieldType3)
+                    .withEnableDynamicField(true)
+                    .build();
+    R<RpcStatus> collection = milvusClient.createCollection(createCollectionReq);
+    logger.info("create collection:" + collectionName);
+    return collectionName;
+  }
+  public static String createNewCollectionWithJSONField() {
+    String collectionName = "Collection_" + MathUtil.getRandomString(10);
+    FieldType fieldType1 =
+            FieldType.newBuilder()
+                    .withName("int64_field")
+                    .withDataType(DataType.Int64)
+                    .withPrimaryKey(true)
+                    .withAutoID(false)
+                    .build();
+    FieldType fieldType2 =
+            FieldType.newBuilder().withName("float_field").withDataType(DataType.Float).build();
+    FieldType fieldType3 =
+            FieldType.newBuilder()
+                    .withName("float_vector")
+                    .withDataType(DataType.FloatVector)
+                    .withDimension(128)
+                    .build();
+    FieldType fieldType4 = FieldType.newBuilder()
+            .withName("boolean_field")
+            .withDataType(DataType.Bool)
+            .build();
+    FieldType fieldType5 = FieldType.newBuilder()
+            .withName("string_field")
+            .withDataType(DataType.VarChar)
+            .withMaxLength(100)
+            .build();
+    FieldType fieldType6 = FieldType.newBuilder()
+            .withName("json_field")
+            .withDataType(DataType.JSON)
+            .build();
+    FieldType fieldType7 = FieldType.newBuilder()
+            .withName("array_field")
+            .withDataType(DataType.Array)
+            .build();
+    CreateCollectionParam createCollectionReq =
+            CreateCollectionParam.newBuilder()
+                    .withCollectionName(collectionName)
+                    .withDescription("Test" + collectionName + "search")
+                    .withShardsNum(2)
+                    .addFieldType(fieldType1)
+                    .addFieldType(fieldType2)
+                    .addFieldType(fieldType3)
+                    .addFieldType(fieldType4)
+                    .addFieldType(fieldType5)
+                    .addFieldType(fieldType6)
+//                    .addFieldType(fieldType7)
+                    .build();
+    R<RpcStatus> collection = milvusClient.createCollection(createCollectionReq);
+    logger.info("create collection:" + collectionName);
+    return collectionName;
+  }
+
+  public static List<JSONObject> generateJsonData(int num){
+    List<JSONObject> jsonList=new ArrayList<>();
+    Random ran = new Random();
+    for (int i = 0; i < num; i++) {
+      JSONObject row=new JSONObject();
+      row.put("int64_field",(long)i);
+      row.put("float_field",(float)i);
+      List<Float> vector=new ArrayList<>();
+      for (int k = 0; k < 128; ++k) {
+        vector.add(ran.nextFloat());
+      }
+      row.put("float_vector",vector);
+      row.put("string_field","Str"+i);
+      row.put("boolean_field",i % 2 == 0);
+      JSONObject jsonObject=new JSONObject();
+      jsonObject.put("int64_field", (long)i);
+      jsonObject.put("float_field", (float)i);
+      jsonObject.put("string_field", "Str"+i);
+      jsonObject.put("boolean_field",i % 2 == 0);
+      jsonObject.put("int8", (short)i);
+      jsonObject.put("floatF", (float)i);
+      jsonObject.put("doubleF", (double)i);
+      jsonObject.put("bool", i % 2 == 0);
+      jsonObject.put("array_field",Arrays.asList(i,i+1,i+2));
+      // $innerJson
+      JSONObject innerJson = new JSONObject();
+      innerJson.put("int64", (long)i);
+      innerJson.put("varchar", "Str"+i);
+      innerJson.put("int16", i);
+      innerJson.put("int32", i);
+      innerJson.put("int8", (short)i);
+      innerJson.put("floatF", (float)i);
+      innerJson.put("doubleF", (double)i);
+      innerJson.put("bool", i % 2 == 0);
+      jsonObject.put("inner_json",innerJson);
+      row.put("json_field",jsonObject);
+      jsonList.add(row);
+    }
+    return jsonList;
+  }
+
+  public static List<InsertParam.Field> generateDataWithDynamicFiledColumn(int num) {
+    Random ran = new Random();
+    List<Long> book_id_array = new ArrayList<>();
+    List<Long> word_count_array = new ArrayList<>();
+    List<List<Float>> book_intro_array = new ArrayList<>();
+    List<String> dynamic_extra_array=new ArrayList<>();
+    for (long i = 0L; i < num; ++i) {
+      book_id_array.add(i);
+      word_count_array.add(i + 10000);
+      dynamic_extra_array.add("String"+i);
+      List<Float> vector = new ArrayList<>();
+      for (int k = 0; k < 128; ++k) {
+        vector.add(ran.nextFloat());
+      }
+      book_intro_array.add(vector);
+    }
+    List<InsertParam.Field> fields = new ArrayList<>();
+    fields.add(new InsertParam.Field("book_id", book_id_array));
+    fields.add(new InsertParam.Field("word_count", word_count_array));
+    fields.add(new InsertParam.Field(CommonData.defaultVectorField, book_intro_array));
+    fields.add(new InsertParam.Field("extra_field", dynamic_extra_array));
+    // logger.info("generateTestData"+ JacksonUtil.serialize(fields));
+    return fields;
+  }
+  public static List<JSONObject> generateDataWithDynamicFiledRow(int num) {
+    List<JSONObject> jsonList = new ArrayList<>();
+    Random ran = new Random();
+    for (int i = 0; i < num; i++) {
+      JSONObject row = new JSONObject();
+      row.put("book_id", (long) i);
+      row.put("word_count", (long) i);
+      row.put("extra_field", "String" + i);
+      row.put("extra_field2",  i);
+      // $innerJson
+      JSONObject innerJson = new JSONObject();
+      innerJson.put("int64", (long) i);
+      innerJson.put("varchar", "varchar"+i);
+      innerJson.put("int16", i);
+      innerJson.put("int32", i);
+      innerJson.put("int8", (short)i);
+      innerJson.put("float", (float)i);
+      innerJson.put("double", (double)i);
+      innerJson.put("bool", i % 2 == 0);
+      row.put("json_field", innerJson);
+      List<Float> vector = new ArrayList<>();
+      for (int k = 0; k < 128; ++k) {
+        vector.add(ran.nextFloat());
+      }
+      row.put("book_intro", vector);
+      jsonList.add(row);
+    }
+    return jsonList;
+  }
+  public static void createIndexWithLoad(String collection, IndexType indexType, MetricType metricType, String fieldName){
+    R<RpcStatus> rpcStatusR =
+            milvusClient.createIndex(
+                    CreateIndexParam.newBuilder()
+                            .withCollectionName(collection)
+                            .withFieldName(fieldName)
+                            .withIndexName(CommonData.defaultIndex)
+                            .withMetricType(metricType)
+                            .withIndexType(indexType)
+                            .withExtraParam(CommonFunction.provideExtraParam(indexType))
+                            .withSyncMode(Boolean.FALSE)
+                            .build());
+    System.out.println("Create index" + rpcStatusR);
+    milvusClient.loadCollection(LoadCollectionParam.newBuilder()
+            .withCollectionName(collection)
+            .withSyncLoad(true)
+            .withSyncLoadWaitingTimeout(30L)
+            .withSyncLoadWaitingInterval(50L)
             .build());
             .build());
+
   }
   }
+
 }
 }

+ 0 - 28
tests/milvustest/src/main/java/com/zilliz/milvustest/util/K8SUtils.java

@@ -1,28 +0,0 @@
-package com.zilliz.milvustest.util;
-
-import io.kubernetes.client.openapi.ApiClient;
-import io.kubernetes.client.util.ClientBuilder;
-import io.kubernetes.client.util.credentials.AccessTokenAuthentication;
-
-/**
- * @Author yongpeng.li
- * @Date 2023/1/3 17:23
- */
-public class K8SUtils {
-    public static ApiClient getApiClient(){
-
-        String master = "https://devops.apiserver.zilliz.cc:6443/";
-        String oauthToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImN1SjZtbE00dTJxUWE3RHhnUUQ3MjVONUVRY3NpWlgzc1FEN09iNVV5d2sifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjo1MjU4NzE2MDU5LCJpYXQiOjE2NTg3MTk2NTksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJxYSIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJxYS1hZG1pbiIsInVpZCI6ImI3MWRkNmI4LTMxOGUtNGQzNi1hNjE1LWZmZDI1MGQ3NjI3MiJ9fSwibmJmIjoxNjU4NzE5NjU5LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6cWE6cWEtYWRtaW4ifQ.JwMQJ2bUKjXHSd2brWBKwKGlrtXTgZre1vJZ1j0hy5AK1JzhhC4QSfuU7QDdkksAF4xPPj7DJ31e2Qclvs3F4WviRBr0v8fYRDgEqNpSKdIJ9KGTqJEjD2UwsITJC4_P8sNKtX8yw4-eVitha7Bf2na7eorOQas-ebjGvNf4usUHGQh9eQDfR7DMebUn4dzJfE2ArQn5Ua6dKNkdO-7uQpOuqPIKytEfzIk_ZrWmbWTbzNMaq2z-zb_yd8iTU3sfpMaZLgOAkLtl1XxnDwvFMapJJcPFEqPMVvR98O7BkRkobQ4SngZmwEui9U2I-ann8cS_yjKB4DeajCxCvCoJBw";
-
-        ApiClient apiClient = new ClientBuilder()
-                //设置 k8s 服务所在 ip地址
-                .setBasePath(master)
-                //是否开启 ssl 验证
-                .setVerifyingSsl(false)
-                //插入访问 连接用的 Token
-                .setAuthentication(new AccessTokenAuthentication(oauthToken))
-                .build();
-        io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient);
-        return apiClient;
-    }
-}

+ 0 - 36
tests/milvustest/src/test/java/com/zilliz/milvustest/K8STEST.java

@@ -1,36 +0,0 @@
-package com.zilliz.milvustest;
-
-import com.zilliz.milvustest.util.K8SUtils;
-import io.kubernetes.client.openapi.ApiClient;
-import io.kubernetes.client.openapi.ApiException;
-import io.kubernetes.client.openapi.Configuration;
-import io.kubernetes.client.openapi.apis.CoreV1Api;
-import io.kubernetes.client.openapi.models.V1Pod;
-import io.kubernetes.client.openapi.models.V1PodList;
-import io.kubernetes.client.util.ClientBuilder;
-import io.kubernetes.client.util.KubeConfig;
-
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-
-/**
- * @Author yongpeng.li
- * @Date 2023/1/3 17:27
- */
-public class K8STEST {
-
-    public static void main(String[] args) throws ApiException, IOException {
-        ApiClient client = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader("src/test/java/resources/config/k8s.config"))).build();
-        Configuration.setDefaultApiClient(client);
-        CoreV1Api api = new CoreV1Api();
-        V1PodList list = api.listPodForAllNamespaces(null,null,null,null,null,null,null,null,null,null);
-        StringBuilder str = new StringBuilder();
-        for (V1Pod item : list.getItems()) {
-            str.append(item.toString());
-            str.append("\n");
-        }
-        System.out.println(str.toString());
-
-    }
-}

+ 56 - 0
tests/milvustest/src/test/java/com/zilliz/milvustest/insert/InsertTest.java

@@ -1,5 +1,6 @@
 package com.zilliz.milvustest.insert;
 package com.zilliz.milvustest.insert;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.zilliz.milvustest.common.BaseTest;
 import com.zilliz.milvustest.common.BaseTest;
 import com.zilliz.milvustest.common.CommonData;
 import com.zilliz.milvustest.common.CommonData;
 import com.zilliz.milvustest.common.CommonFunction;
 import com.zilliz.milvustest.common.CommonFunction;
@@ -33,16 +34,25 @@ import java.util.Random;
 @Feature("Insert")
 @Feature("Insert")
 public class InsertTest extends BaseTest {
 public class InsertTest extends BaseTest {
   public String stringPKAndBinaryCollection;
   public String stringPKAndBinaryCollection;
+  public String collectionWithJsonField;
+  public String collectionWithDynamicField;
 
 
   @BeforeClass(description = "provider collection",alwaysRun = true)
   @BeforeClass(description = "provider collection",alwaysRun = true)
   public void providerData() {
   public void providerData() {
     stringPKAndBinaryCollection = CommonFunction.createStringPKAndBinaryCollection();
     stringPKAndBinaryCollection = CommonFunction.createStringPKAndBinaryCollection();
+    collectionWithJsonField= CommonFunction.createNewCollectionWithJSONField();
+    collectionWithDynamicField= CommonFunction.createNewCollectionWithDynamicField();
   }
   }
 
 
   @AfterClass(description = "delete test data",alwaysRun = true)
   @AfterClass(description = "delete test data",alwaysRun = true)
   public void deleteData() {
   public void deleteData() {
     milvusClient.dropCollection(
     milvusClient.dropCollection(
         DropCollectionParam.newBuilder().withCollectionName(stringPKAndBinaryCollection).build());
         DropCollectionParam.newBuilder().withCollectionName(stringPKAndBinaryCollection).build());
+    milvusClient.dropCollection(
+        DropCollectionParam.newBuilder().withCollectionName(collectionWithJsonField).build());
+    milvusClient.dropCollection(
+        DropCollectionParam.newBuilder().withCollectionName(collectionWithDynamicField).build());
+
   }
   }
 
 
   @Severity(SeverityLevel.BLOCKER)
   @Severity(SeverityLevel.BLOCKER)
@@ -411,4 +421,50 @@ public class InsertTest extends BaseTest {
     milvusClient.dropCollection(DropCollectionParam.newBuilder().withCollectionName(stringPKCollection).build());
     milvusClient.dropCollection(DropCollectionParam.newBuilder().withCollectionName(stringPKCollection).build());
   }
   }
 
 
+  @Severity(SeverityLevel.BLOCKER)
+  @Test(description = "Insert data into collection with JSON field",groups = {"Smoke"})
+  public void insertDataCollectionWithJsonField(){
+    List<JSONObject> jsonObjects = CommonFunction.generateJsonData(100);
+    System.out.println(jsonObjects);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withCollectionName(collectionWithJsonField)
+            .withRows(jsonObjects)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(), 0);
+    Assert.assertEquals(insert.getData().getSuccIndexCount(),100);
+  }
+  @Severity(SeverityLevel.BLOCKER)
+  @Test(description = "Insert data into collection with Dynamic field",groups = {"Smoke"})
+  public void insertDataCollectionWithDynamicField(){
+    List<JSONObject> jsonObjects = CommonFunction.generateDataWithDynamicFiledRow(100);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withCollectionName(collectionWithDynamicField)
+            .withRows(jsonObjects)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(), 0);
+    Assert.assertEquals(insert.getData().getSuccIndexCount(),100);
+  }
+  @Severity(SeverityLevel.NORMAL)
+  @Test(description = "Insert data into collection with Dynamic field use column data",expectedExceptions = ParamException.class)
+  public void insertDataCollectionWithDynamicFieldUseColumnData(){
+    List<InsertParam.Field> fields = CommonFunction.generateDataWithDynamicFiledColumn(100);
+    List<JSONObject> jsonObjects = CommonFunction.generateJsonData(100);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withCollectionName(collectionWithDynamicField)
+            .withFields(fields)
+            .withRows(jsonObjects)
+            .build());
+
+  }
+  @Severity(SeverityLevel.NORMAL)
+  @Test(description = "Insert data into collection with Dynamic field",expectedExceptions = ParamException.class)
+  public void insertFieldsAndRowsData(){
+    List<InsertParam.Field> fields = CommonFunction.generateDataWithDynamicFiledColumn(100);
+    List<JSONObject> jsonObjects = CommonFunction.generateDataWithDynamicFiledRow(100);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withCollectionName(collectionWithDynamicField)
+            .withFields(fields)
+            .withRows(jsonObjects)
+            .build());
+  }
 }
 }

+ 1 - 1
tests/milvustest/src/test/java/com/zilliz/milvustest/load/BulkLoadStateTest.java

@@ -117,7 +117,7 @@ public class BulkLoadStateTest extends BaseTest {
         i++;
         i++;
     }
     }
     Assert.assertEquals(bulkloadState.getStatus().intValue(), 0);
     Assert.assertEquals(bulkloadState.getStatus().intValue(), 0);
-    Assert.assertEquals(bulkloadState.getData().getRowCount(), 10L);
+//    Assert.assertEquals(bulkloadState.getData().getRowCount(), 10L);
 
 
 
 
     R<RpcStatus> rpcStatusR =
     R<RpcStatus> rpcStatusR =

+ 405 - 0
tests/milvustest/src/test/java/com/zilliz/milvustest/partition/PartitionKeyTest.java

@@ -0,0 +1,405 @@
+package com.zilliz.milvustest.partition;
+
+import com.zilliz.milvustest.common.BaseTest;
+import com.zilliz.milvustest.common.CommonData;
+import com.zilliz.milvustest.common.CommonFunction;
+import com.zilliz.milvustest.util.MathUtil;
+import io.milvus.common.clientenum.ConsistencyLevelEnum;
+import io.milvus.exception.ParamException;
+import io.milvus.grpc.*;
+import io.milvus.param.IndexType;
+import io.milvus.param.MetricType;
+import io.milvus.param.R;
+import io.milvus.param.RpcStatus;
+import io.milvus.param.collection.*;
+import io.milvus.param.dml.DeleteParam;
+import io.milvus.param.dml.InsertParam;
+import io.milvus.param.dml.QueryParam;
+import io.milvus.param.dml.SearchParam;
+import io.milvus.param.index.CreateIndexParam;
+import io.milvus.param.partition.*;
+import io.milvus.response.QueryResultsWrapper;
+import io.qameta.allure.Epic;
+import io.qameta.allure.Feature;
+import io.qameta.allure.Severity;
+import io.qameta.allure.SeverityLevel;
+import org.checkerframework.checker.units.qual.A;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.FilterOutputStream;
+import java.util.*;
+
+/**
+ * @Author yongpeng.li
+ * @Date 2023/5/29 09:22
+ */
+@Epic("Partition")
+@Feature("PartitionKey")
+public class PartitionKeyTest extends BaseTest {
+    private String collection;
+    private int partitionKeyNum = 20;
+
+    @BeforeClass(description = "init collection with partition Key", alwaysRun = true)
+    public void provideCollection() {
+        collection = CommonFunction.createNewCollectionWithPartitionKey(partitionKeyNum);
+
+    }
+
+    @DataProvider(name = "provideExpressions")
+    public Object[][] provideStringExpression() {
+        return new Object[][]{
+                {" book_name in [\"part0\"]"},
+                {" book_name == \"part0\""},
+                {" book_name >= \"part0\""},
+        };
+    }
+
+    @AfterClass(description = "clean test data ", alwaysRun = true)
+    public void cleanTestData() {
+        milvusClient.dropCollection(DropCollectionParam.newBuilder().withCollectionName(collection).build());
+    }
+
+    @Severity(SeverityLevel.BLOCKER)
+    @Test(description = "check partition num", groups = {"Smoke"})
+    public void checkPartitionInCollection() {
+        R<ShowPartitionsResponse> showPartitionsResponseR = milvusClient.showPartitions(ShowPartitionsParam.newBuilder()
+                .withCollectionName(collection).build());
+        Assert.assertEquals(showPartitionsResponseR.getStatus().intValue(), 0);
+        Assert.assertEquals(showPartitionsResponseR.getData().getPartitionIDsCount(), partitionKeyNum);
+    }
+
+    @Severity(SeverityLevel.BLOCKER)
+    @Test(description = "Insert data into collection with partition key", groups = {"Smoke"})
+    public void insertData() {
+        List<InsertParam.Field> fields = CommonFunction.generateDataWithPartitionKey(10000);
+        // insert
+        R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+                .withFields(fields)
+                .withCollectionName(collection)
+                .build());
+        Assert.assertEquals(insert.getStatus().intValue(), 0);
+        Assert.assertEquals(insert.getData().getSuccIndexCount(), 10000);
+
+        // createindex
+        R<RpcStatus> index = milvusClient.createIndex(CreateIndexParam.newBuilder()
+                .withCollectionName(collection)
+                .withIndexType(IndexType.HNSW)
+                .withMetricType(MetricType.L2)
+                .withFieldName(CommonData.defaultVectorField)
+                .withExtraParam(CommonFunction.provideExtraParam(IndexType.HNSW))
+                .withSyncMode(true)
+                .withSyncWaitingInterval(50L)
+                .withSyncWaitingTimeout(30L)
+                .build());
+        Assert.assertEquals(index.getStatus().intValue(), 0);
+        // load
+        R<RpcStatus> rpcStatusR = milvusClient.loadCollection(LoadCollectionParam.newBuilder()
+                .withCollectionName(collection)
+                .withSyncLoad(true)
+                .withSyncLoadWaitingInterval(50L)
+                .withSyncLoadWaitingTimeout(300L).build());
+        Assert.assertEquals(rpcStatusR.getStatus().intValue(), 0);
+        System.out.println(rpcStatusR.toString());
+    }
+
+    @Severity(SeverityLevel.BLOCKER)
+    @Test(description = "search", groups = {"Smoke"}, dependsOnMethods = {"insertData"}, dataProvider = "provideExpressions")
+    public void search(String expr) {
+        Integer SEARCH_K = 2; // TopK
+        String SEARCH_PARAM = "{\"nprobe\":10}";
+        List<String> search_output_fields = Collections.singletonList(CommonData.defaultPartitionField);
+        List<List<Float>> search_vectors = Collections.singletonList(Arrays.asList(MathUtil.generateFloat(128)));
+        SearchParam searchParam =
+                SearchParam.newBuilder()
+                        .withCollectionName(collection)
+                        .withMetricType(MetricType.L2)
+                        .withOutFields(search_output_fields)
+                        .withTopK(SEARCH_K)
+                        .withVectors(search_vectors)
+                        .withVectorFieldName(CommonData.defaultVectorField)
+                        .withParams(SEARCH_PARAM)
+                        .withExpr(expr)
+                        .withConsistencyLevel(ConsistencyLevelEnum.STRONG)
+                        .build();
+        R<SearchResults> searchResultsR = milvusClient.search(searchParam);
+        Assert.assertEquals(searchResultsR.getStatus().intValue(), 0);
+        Assert.assertEquals(searchResultsR.getData().getResults().getTopK(), SEARCH_K.intValue());
+        Assert.assertEquals(searchResultsR.getData().getResults().getFieldsDataList().get(0).getFieldName(), CommonData.defaultPartitionField);
+
+
+    }
+
+    @Severity(SeverityLevel.CRITICAL)
+    @Test(description = "search", dependsOnMethods = {"insertData"}, dataProvider = "provideExpressions")
+    public void query(String expr) {
+        List<String> query_output_fields = Collections.singletonList(CommonData.defaultPartitionField);
+        QueryParam queryParam =
+                QueryParam.newBuilder()
+                        .withCollectionName(collection)
+                        .withOutFields(query_output_fields)
+                        .withExpr(expr)
+                        .build();
+        R<QueryResults> queryResultsR = milvusClient.query(queryParam);
+        Assert.assertEquals(queryResultsR.getStatus().intValue(), 0);
+        QueryResultsWrapper wrapperQuery = new QueryResultsWrapper(queryResultsR.getData());
+        Assert.assertEquals(wrapperQuery.getFieldWrapper("book_name").getFieldData().get(0).toString(), "part0");
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Use Partition key field type of int32", expectedExceptions = ParamException.class)
+    public void createCollectionWithIllegalPartition() {
+        String collectionName = "Collection_" + MathUtil.getRandomString(10);
+        FieldType fieldType1 =
+                FieldType.newBuilder()
+                        .withName("book_id")
+                        .withDataType(DataType.Int64)
+                        .withPrimaryKey(true)
+                        .withAutoID(false)
+                        .build();
+        FieldType fieldType2 =
+                FieldType.newBuilder().withName("word_count").withDataType(DataType.Int64).build();
+        FieldType fieldType3 =
+                FieldType.newBuilder()
+                        .withName(CommonData.defaultVectorField)
+                        .withDataType(DataType.FloatVector)
+                        .withDimension(128)
+                        .build();
+        FieldType fieldType4 = FieldType.newBuilder()
+                .withName(CommonData.defaultPartitionField)
+                .withDataType(DataType.Int32)
+                .withMaxLength(128)
+                .withPartitionKey(true)
+                .build();
+        CreateCollectionParam createCollectionReq =
+                CreateCollectionParam.newBuilder()
+                        .withCollectionName(collectionName)
+                        .withDescription("Test" + collectionName + "search")
+                        .withShardsNum(2)
+                        .addFieldType(fieldType1)
+                        .addFieldType(fieldType2)
+                        .addFieldType(fieldType3)
+                        .addFieldType(fieldType4)
+                        .withPartitionsNum(partitionKeyNum)
+                        .build();
+        R<RpcStatus> collection = BaseTest.milvusClient.createCollection(createCollectionReq);
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Set Partition key field primary key ", expectedExceptions = ParamException.class)
+    public void createCollectionWithIllegalPK() {
+        String collectionName = "Collection_" + MathUtil.getRandomString(10);
+        FieldType fieldType1 =
+                FieldType.newBuilder()
+                        .withName("book_id")
+                        .withDataType(DataType.Int64)
+                        .withPrimaryKey(true)
+                        .withPartitionKey(true)
+                        .withAutoID(false)
+                        .build();
+        FieldType fieldType2 =
+                FieldType.newBuilder().withName("word_count").withDataType(DataType.Int64).build();
+        FieldType fieldType3 =
+                FieldType.newBuilder()
+                        .withName(CommonData.defaultVectorField)
+                        .withDataType(DataType.FloatVector)
+                        .withDimension(128)
+                        .build();
+
+        CreateCollectionParam createCollectionReq =
+                CreateCollectionParam.newBuilder()
+                        .withCollectionName(collectionName)
+                        .withDescription("Test" + collectionName + "search")
+                        .withShardsNum(2)
+                        .addFieldType(fieldType1)
+                        .addFieldType(fieldType2)
+                        .addFieldType(fieldType3)
+                        .withPartitionsNum(partitionKeyNum)
+                        .build();
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "partition num over 4096")
+    public void createCollectionWith4097Partitions() {
+        String collectionName = "Collection_" + MathUtil.getRandomString(10);
+        FieldType fieldType1 =
+                FieldType.newBuilder()
+                        .withName("book_id")
+                        .withDataType(DataType.Int64)
+                        .withPrimaryKey(true)
+                        .withAutoID(false)
+                        .build();
+        FieldType fieldType2 =
+                FieldType.newBuilder().withName("word_count").withDataType(DataType.Int64).build();
+        FieldType fieldType3 =
+                FieldType.newBuilder()
+                        .withName(CommonData.defaultVectorField)
+                        .withDataType(DataType.FloatVector)
+                        .withDimension(128)
+                        .build();
+        FieldType fieldType4 = FieldType.newBuilder()
+                .withName(CommonData.defaultPartitionField)
+                .withDataType(DataType.Int64)
+                .withMaxLength(128)
+                .withPartitionKey(true)
+                .build();
+        CreateCollectionParam createCollectionReq =
+                CreateCollectionParam.newBuilder()
+                        .withCollectionName(collectionName)
+                        .withDescription("Test" + collectionName + "search")
+                        .withShardsNum(2)
+                        .addFieldType(fieldType1)
+                        .addFieldType(fieldType2)
+                        .addFieldType(fieldType3)
+                        .addFieldType(fieldType4)
+                        .withPartitionsNum(4097)
+                        .build();
+        R<RpcStatus> collection = BaseTest.milvusClient.createCollection(createCollectionReq);
+        Assert.assertEquals(collection.getStatus().intValue(), 1);
+        Assert.assertTrue(collection.getException().getMessage().contains("partition number (4097) exceeds max configuration (4096)"));
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Create partition use partition name param in  Partition key mode")
+    public void createPartitionWithPartitionName() {
+        R<RpcStatus> partition = milvusClient.createPartition(CreatePartitionParam.newBuilder()
+                .withCollectionName(collection)
+                .withPartitionName("part000").build());
+        Assert.assertEquals(partition.getStatus().intValue(), 1);
+        Assert.assertTrue(partition.getException().getMessage().contains("disable create partition if partition key mode is used"));
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Drop partition use partition name param in  Partition key mode")
+    public void dropPartitionWithPartitionName() {
+        R<RpcStatus> rpcStatusR = milvusClient.dropPartition(DropPartitionParam.newBuilder()
+                .withCollectionName(collection)
+                .withPartitionName("_default_1").build());
+        Assert.assertEquals(rpcStatusR.getStatus().intValue(), 1);
+        Assert.assertTrue(rpcStatusR.getException().getMessage().contains("disable drop partition if partition key mode is used"));
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Load partition use partition name param in  Partition key mode")
+    public void loadPartitionWithPartitionName() {
+        R<RpcStatus> rpcStatusR = milvusClient.loadPartitions(LoadPartitionsParam.newBuilder()
+                .withCollectionName(collection)
+                .withPartitionNames(Collections.singletonList(CommonData.defaultPartitionField))
+                .build());
+        Assert.assertEquals(rpcStatusR.getStatus().intValue(), 1);
+        Assert.assertTrue(rpcStatusR.getException().getMessage().contains("disable load partitions if partition key mode is used"));
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "release partition use partition name param in  Partition key mode")
+    public void releasePartitionWithPartitionName() {
+        R<RpcStatus> rpcStatusR = milvusClient.releasePartitions(ReleasePartitionsParam.newBuilder()
+                .withCollectionName(collection)
+                .withPartitionNames(Collections.singletonList("_default_1"))
+                .build());
+        Assert.assertEquals(rpcStatusR.getStatus().intValue(), 1);
+        Assert.assertTrue(rpcStatusR.getException().getMessage().contains("disable release partitions if partition key mode is used"));
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Show partition use partition name param in  Partition key mode")
+    public void showPartitionsWithPartitionName() {
+        R<ShowPartitionsResponse> responseR = milvusClient.showPartitions(ShowPartitionsParam.newBuilder()
+                .withCollectionName(collection)
+                .withPartitionNames(Collections.singletonList("_default_1"))
+                .build());
+        Assert.assertEquals(responseR.getStatus().intValue(), 0);
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Get partition use partition name param in  Partition key mode")
+    public void getPartitionsWithPartitionName() {
+        R<GetPartitionStatisticsResponse> responseR = milvusClient.getPartitionStatistics(GetPartitionStatisticsParam.newBuilder()
+                .withCollectionName(collection)
+                .withPartitionName("_default_1")
+                .build());
+        Assert.assertEquals(responseR.getStatus().intValue(), 0);
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Has partition use partition name param in  Partition key mode")
+    public void hasPartitionsWithPartitionName() {
+        R<Boolean> booleanR = milvusClient.hasPartition(HasPartitionParam.newBuilder()
+                .withCollectionName(collection)
+                .withPartitionName("_default_1").build());
+        Assert.assertEquals(booleanR.getStatus().intValue(), 0);
+    }
+
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "Insert use partition name param in  Partition key mode")
+    public void InsertWithPartitionName() {
+        List<InsertParam.Field> fields = CommonFunction.generateDataWithPartitionKey(10000);
+        // insert
+        R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+                .withFields(fields)
+                .withCollectionName(collection)
+                .withPartitionName(CommonData.defaultPartitionField)
+                .build());
+        Assert.assertEquals(insert.getStatus().intValue(), 1);
+    }
+
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "search use partition name param in  Partition key mode")
+    public void searchWithPartitionName() {
+        String expr=" book_name in [\"part0\"]";
+        Integer SEARCH_K = 2; // TopK
+        String SEARCH_PARAM = "{\"nprobe\":10}";
+        List<String> search_output_fields = Collections.singletonList(CommonData.defaultPartitionField);
+        List<List<Float>> search_vectors = Collections.singletonList(Arrays.asList(MathUtil.generateFloat(128)));
+        SearchParam searchParam =
+                SearchParam.newBuilder()
+                        .withCollectionName(collection)
+                        .withPartitionNames(Collections.singletonList(CommonData.defaultPartitionField))
+                        .withMetricType(MetricType.L2)
+                        .withOutFields(search_output_fields)
+                        .withTopK(SEARCH_K)
+                        .withVectors(search_vectors)
+                        .withVectorFieldName(CommonData.defaultVectorField)
+                        .withParams(SEARCH_PARAM)
+                        .withExpr(expr)
+                        .withConsistencyLevel(ConsistencyLevelEnum.STRONG)
+                        .build();
+        R<SearchResults> searchResultsR = milvusClient.search(searchParam);
+        Assert.assertEquals(searchResultsR.getStatus().intValue(), 1);
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "query use partition name param in  Partition key mode")
+    public void queryWithPartitionName() {
+        String expr=" book_name in [\"part0\"]";
+        List<String> query_output_fields = Collections.singletonList(CommonData.defaultPartitionField);
+        QueryParam queryParam =
+                QueryParam.newBuilder()
+                        .withCollectionName(collection)
+                        .withPartitionNames(Collections.singletonList(CommonData.defaultPartitionField))
+                        .withOutFields(query_output_fields)
+                        .withExpr(expr)
+                        .build();
+        R<QueryResults> queryResultsR = milvusClient.query(queryParam);
+        Assert.assertEquals(queryResultsR.getStatus().intValue(), 1);
+    }
+
+    @Severity(SeverityLevel.NORMAL)
+    @Test(description = "delete use partition name param in  Partition key mode")
+    public void deleteWithPartitionName() {
+        String expr=" book_name in [\"part0\"]";
+        R<MutationResult> delete = milvusClient.delete(DeleteParam.newBuilder()
+                .withCollectionName(collection)
+                .withExpr(expr)
+                .withPartitionName(CommonData.defaultPartitionField)
+                .build());
+        Assert.assertEquals(delete.getStatus().intValue(),1);
+    }
+
+
+}

+ 140 - 0
tests/milvustest/src/test/java/com/zilliz/milvustest/query/QueryTest.java

@@ -1,5 +1,6 @@
 package com.zilliz.milvustest.query;
 package com.zilliz.milvustest.query;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.zilliz.milvustest.common.BaseTest;
 import com.zilliz.milvustest.common.BaseTest;
 import com.zilliz.milvustest.common.CommonData;
 import com.zilliz.milvustest.common.CommonData;
 import com.zilliz.milvustest.common.CommonFunction;
 import com.zilliz.milvustest.common.CommonFunction;
@@ -20,6 +21,7 @@ import io.milvus.param.dml.DeleteParam;
 import io.milvus.param.dml.InsertParam;
 import io.milvus.param.dml.InsertParam;
 import io.milvus.param.dml.QueryParam;
 import io.milvus.param.dml.QueryParam;
 import io.milvus.param.index.CreateIndexParam;
 import io.milvus.param.index.CreateIndexParam;
+import io.milvus.response.FieldDataWrapper;
 import io.milvus.response.QueryResultsWrapper;
 import io.milvus.response.QueryResultsWrapper;
 import io.qameta.allure.Epic;
 import io.qameta.allure.Epic;
 import io.qameta.allure.Feature;
 import io.qameta.allure.Feature;
@@ -41,6 +43,8 @@ import static com.zilliz.milvustest.util.MathUtil.combine;
 @Feature("Query")
 @Feature("Query")
 public class QueryTest extends BaseTest {
 public class QueryTest extends BaseTest {
   public String newBookName;
   public String newBookName;
+  public String collectionWithJsonField;
+  public String collectionWithDynamicField;
 
 
   @BeforeClass(description = "load collection first",alwaysRun = true)
   @BeforeClass(description = "load collection first",alwaysRun = true)
   public void loadCollection() {
   public void loadCollection() {
@@ -58,6 +62,8 @@ public class QueryTest extends BaseTest {
         LoadCollectionParam.newBuilder()
         LoadCollectionParam.newBuilder()
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .build());
             .build());
+    collectionWithJsonField= CommonFunction.createNewCollectionWithJSONField();
+    collectionWithDynamicField= CommonFunction.createNewCollectionWithDynamicField();
   }
   }
 
 
   @DataProvider(name = "providerPartition")
   @DataProvider(name = "providerPartition")
@@ -83,6 +89,10 @@ public class QueryTest extends BaseTest {
         ReleaseCollectionParam.newBuilder()
         ReleaseCollectionParam.newBuilder()
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .build());
             .build());
+    milvusClient.dropCollection(
+            DropCollectionParam.newBuilder().withCollectionName(collectionWithJsonField).build());
+    milvusClient.dropCollection(
+            DropCollectionParam.newBuilder().withCollectionName(collectionWithDynamicField).build());
   }
   }
 
 
   @DataProvider(name = "providerConsistency")
   @DataProvider(name = "providerConsistency")
@@ -138,6 +148,25 @@ public class QueryTest extends BaseTest {
   public Object[][] providerIndexForBinaryCollection() {
   public Object[][] providerIndexForBinaryCollection() {
     return combine(provideBinaryIndexType(), providerBinaryMetricType());
     return combine(provideBinaryIndexType(), providerBinaryMetricType());
   }
   }
+  @DataProvider(name="dynamicExpressions")
+  public Object[][] provideDynamicExpression(){
+    return  new Object[][]{
+            {"json_field[\"int32\"] in [2,4,6,8]"},
+            {"book_id in [10,20,30,40]"},
+            {"extra_field2 in [1,2,3,4]"},
+            {"\"String0\"<=extra_field<=\"String3\""}
+    };
+  }
+  @DataProvider(name="jsonExpressions")
+  public Object[][] provideJsonExpression(){
+    return  new Object[][]{
+            {"int64_field in [10,20,30,40]"},
+            {"json_field[\"int64_field\"] in [10,20,30,40]"},
+            {"json_field[\"inner_json\"][\"int32\"] in [1,2,3,4]"},
+            {"\"Str0\"<=json_field[\"inner_json\"][\"varchar\"]<=\"Str3\""},
+            {"json_field[\"inner_json\"][\"int64\"] in [10,20,30,40]"}
+    };
+  }
 
 
   @DataProvider(name = "provideIntExpressions")
   @DataProvider(name = "provideIntExpressions")
   public Object[][] provideIntExpression() {
   public Object[][] provideIntExpression() {
@@ -989,4 +1018,115 @@ public class QueryTest extends BaseTest {
     Assert.assertTrue(queryResultsR.getException().getMessage().contains("cannot parse expression"));
     Assert.assertTrue(queryResultsR.getException().getMessage().contains("cannot parse expression"));
 
 
   }
   }
+
+  @Test(description = "query collection with dynamic field",groups = {"Smoke"},dataProvider = "dynamicExpressions")
+  @Severity(SeverityLevel.BLOCKER)
+  public void queryCollectionWithDynamicField(String expr) {
+    List<JSONObject> jsonObjects = CommonFunction.generateDataWithDynamicFiledRow(1000);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withRows(jsonObjects)
+            .withCollectionName(collectionWithDynamicField)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(),0);
+    CommonFunction.createIndexWithLoad(collectionWithDynamicField,IndexType.HNSW,MetricType.L2,CommonData.defaultVectorField);
+    //query
+
+    List<String> outFields = Arrays.asList("extra_field");
+    QueryParam queryParam =
+            QueryParam.newBuilder()
+                    .withCollectionName(collectionWithDynamicField)
+                    .withOutFields(outFields)
+                    .withExpr(expr)
+                    .build();
+    R<QueryResults> queryResultsR = milvusClient.query(queryParam);
+    QueryResultsWrapper wrapperQuery = new QueryResultsWrapper(queryResultsR.getData());
+     Assert.assertEquals(queryResultsR.getStatus().intValue(), 0);
+     Assert.assertTrue(wrapperQuery.getFieldWrapper("$meta").getFieldData().size()>=4);
+    FieldDataWrapper fieldDataWrapper=new FieldDataWrapper(queryResultsR.getData().getFieldsData(0));
+    String extra_field = fieldDataWrapper.getAsString(0, "extra_field");
+    Assert.assertTrue(extra_field.contains("String"));
+  }
+
+  @Test(description = "query collection with dynamic field use inner json field",groups = {"Smoke"},dataProvider = "dynamicExpressions")
+  @Severity(SeverityLevel.BLOCKER)
+  public void queryWithDynamicFieldUseInnerJsonField(String expr) {
+    List<JSONObject> jsonObjects = CommonFunction.generateDataWithDynamicFiledRow(1000);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withRows(jsonObjects)
+            .withCollectionName(collectionWithDynamicField)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(),0);
+    CommonFunction.createIndexWithLoad(collectionWithDynamicField,IndexType.HNSW,MetricType.L2,CommonData.defaultVectorField);
+    //query
+    List<String> outFields = Arrays.asList("json_field",CommonData.defaultVectorField);
+    QueryParam queryParam =
+            QueryParam.newBuilder()
+                    .withCollectionName(collectionWithDynamicField)
+                    .withOutFields(outFields)
+                    .withExpr(expr)
+                    .build();
+    R<QueryResults> queryResultsR = milvusClient.query(queryParam);
+    QueryResultsWrapper wrapperQuery = new QueryResultsWrapper(queryResultsR.getData());
+    Assert.assertEquals(queryResultsR.getStatus().intValue(), 0);
+    Assert.assertTrue(wrapperQuery.getFieldWrapper("$meta").getFieldData().size()>=4);
+  }
+
+  @Test(description = "query collection with dynamic field use nonexistent field name")
+  @Severity(SeverityLevel.NORMAL)
+  public void queryWithDynamicFieldUseNonexistentFiledName() {
+    List<JSONObject> jsonObjects = CommonFunction.generateDataWithDynamicFiledRow(1000);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withRows(jsonObjects)
+            .withCollectionName(collectionWithDynamicField)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(),0);
+    CommonFunction.createIndexWithLoad(collectionWithDynamicField,IndexType.HNSW,MetricType.L2,CommonData.defaultVectorField);
+    //query
+    String SEARCH_PARAM = "book_id in [2,4,6,8]";
+    List<String> outFields = Arrays.asList("extra_field_nonexistent");
+    QueryParam queryParam =
+            QueryParam.newBuilder()
+                    .withCollectionName(collectionWithDynamicField)
+                    .withOutFields(outFields)
+                    .withExpr(SEARCH_PARAM)
+                    .build();
+    R<QueryResults> queryResultsR = milvusClient.query(queryParam);
+    QueryResultsWrapper wrapperQuery = new QueryResultsWrapper(queryResultsR.getData());
+    Assert.assertEquals(queryResultsR.getStatus().intValue(), 0);
+    Assert.assertEquals(wrapperQuery.getFieldWrapper("$meta").getFieldData().size(),4);
+    FieldDataWrapper fieldDataWrapper=new FieldDataWrapper(queryResultsR.getData().getFieldsData(0));
+    String extra_field = fieldDataWrapper.getAsString(0, "extra_field");
+    Assert.assertTrue(extra_field.contains("String"));
+  }
+
+  @Test(description = "query collection with json field",groups = {"Smoke"},dataProvider = "jsonExpressions")
+  @Severity(SeverityLevel.BLOCKER)
+  public void queryCollectionWithJsonField(String expr) {
+    List<JSONObject> jsonObjects = CommonFunction.generateJsonData(1000);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withRows(jsonObjects)
+            .withCollectionName(collectionWithJsonField)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(),0);
+    CommonFunction.createIndexWithLoad(collectionWithJsonField,IndexType.HNSW,MetricType.L2,"float_vector");
+    //query
+    List<String> outFields = Arrays.asList("json_field");
+    QueryParam queryParam =
+            QueryParam.newBuilder()
+                    .withCollectionName(collectionWithJsonField)
+                    .withOutFields(outFields)
+                    .withExpr(expr)
+                    .build();
+    R<QueryResults> queryResultsR = milvusClient.query(queryParam);
+    QueryResultsWrapper wrapperQuery = new QueryResultsWrapper(queryResultsR.getData());
+    Assert.assertEquals(queryResultsR.getStatus().intValue(), 0);
+    Assert.assertTrue(wrapperQuery.getFieldWrapper("json_field").getFieldData().size()>=4);
+    JSONObject jsonObject = (JSONObject) wrapperQuery.getRowRecord(0).get("json_field");
+    String string_field = jsonObject.getString("string_field");
+    Assert.assertTrue(string_field.contains("Str"));
+
+  }
+
+
+
 }
 }

+ 146 - 3
tests/milvustest/src/test/java/com/zilliz/milvustest/search/SearchTest.java

@@ -1,12 +1,12 @@
 package com.zilliz.milvustest.search;
 package com.zilliz.milvustest.search;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.zilliz.milvustest.common.BaseTest;
 import com.zilliz.milvustest.common.BaseTest;
 import com.zilliz.milvustest.common.CommonData;
 import com.zilliz.milvustest.common.CommonData;
 import com.zilliz.milvustest.common.CommonFunction;
 import com.zilliz.milvustest.common.CommonFunction;
 import com.zilliz.milvustest.util.MathUtil;
 import com.zilliz.milvustest.util.MathUtil;
 import io.milvus.common.clientenum.ConsistencyLevelEnum;
 import io.milvus.common.clientenum.ConsistencyLevelEnum;
 import io.milvus.exception.ParamException;
 import io.milvus.exception.ParamException;
-import io.milvus.grpc.DataType;
 import io.milvus.grpc.MutationResult;
 import io.milvus.grpc.MutationResult;
 import io.milvus.grpc.SearchResults;
 import io.milvus.grpc.SearchResults;
 import io.milvus.param.IndexType;
 import io.milvus.param.IndexType;
@@ -20,10 +20,9 @@ import io.milvus.param.dml.DeleteParam;
 import io.milvus.param.dml.InsertParam;
 import io.milvus.param.dml.InsertParam;
 import io.milvus.param.dml.SearchParam;
 import io.milvus.param.dml.SearchParam;
 import io.milvus.param.index.CreateIndexParam;
 import io.milvus.param.index.CreateIndexParam;
+import io.milvus.response.FieldDataWrapper;
 import io.milvus.response.SearchResultsWrapper;
 import io.milvus.response.SearchResultsWrapper;
 import io.qameta.allure.*;
 import io.qameta.allure.*;
-import lombok.Data;
-import org.checkerframework.checker.units.qual.A;
 import org.testng.Assert;
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeClass;
@@ -43,6 +42,8 @@ import static com.zilliz.milvustest.util.MathUtil.combine;
 public class SearchTest extends BaseTest {
 public class SearchTest extends BaseTest {
   public String newBookName;
   public String newBookName;
   public String newBookNameBin;
   public String newBookNameBin;
+  public String collectionWithJsonField;
+  public String collectionWithDynamicField;
 
 
   @BeforeClass(description = "load collection first",alwaysRun = true)
   @BeforeClass(description = "load collection first",alwaysRun = true)
   public void loadCollection() {
   public void loadCollection() {
@@ -60,8 +61,29 @@ public class SearchTest extends BaseTest {
         LoadCollectionParam.newBuilder()
         LoadCollectionParam.newBuilder()
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .build());
             .build());
+    collectionWithJsonField= CommonFunction.createNewCollectionWithJSONField();
+    collectionWithDynamicField= CommonFunction.createNewCollectionWithDynamicField();
   }
   }
 
 
+  @DataProvider(name="dynamicExpressions")
+  public Object[][] provideDynamicExpression(){
+    return  new Object[][]{
+            {"json_field[\"int32\"] in [2,4,6,8]"},
+            {"book_id in [10,20,30,40]"},
+            {"extra_field2 in [1,2,3,4]"},
+            {"\"String0\"<=extra_field<=\"String3\""}
+    };
+  }
+  @DataProvider(name="jsonExpressions")
+  public Object[][] provideJsonExpression(){
+    return  new Object[][]{
+            {"int64_field in [10,20,30,40]"},
+            {"json_field[\"int64_field\"] in [10,20,30,40]"},
+            {"json_field[\"inner_json\"][\"int32\"] in [1,2,3,4]"},
+            {"\"Str0\"<=json_field[\"inner_json\"][\"varchar\"]<=\"Str3\""},
+            {"json_field[\"inner_json\"][\"int64\"] in [10,20,30,40]"}
+    };
+  }
   @AfterClass(description = "release collection after test",alwaysRun = true)
   @AfterClass(description = "release collection after test",alwaysRun = true)
   public void releaseCollection() {
   public void releaseCollection() {
     milvusClient.releaseCollection(
     milvusClient.releaseCollection(
@@ -80,6 +102,11 @@ public class SearchTest extends BaseTest {
         ReleaseCollectionParam.newBuilder()
         ReleaseCollectionParam.newBuilder()
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .withCollectionName(CommonData.defaultStringPKBinaryCollection)
             .build());
             .build());
+    milvusClient.dropCollection(
+            DropCollectionParam.newBuilder().withCollectionName(collectionWithJsonField).build());
+    milvusClient.dropCollection(
+            DropCollectionParam.newBuilder().withCollectionName(collectionWithDynamicField).build());
+
   }
   }
 
 
   @DataProvider(name = "providerPartition")
   @DataProvider(name = "providerPartition")
@@ -1730,4 +1757,120 @@ public class SearchTest extends BaseTest {
     Assert.assertEquals(searchResultsR.getData().getResults().getIds().getIntId().getData(1),data2);
     Assert.assertEquals(searchResultsR.getData().getResults().getIds().getIntId().getData(1),data2);
     logger.info(searchResultsR.getData().getResults().toString());
     logger.info(searchResultsR.getData().getResults().toString());
   }
   }
+
+  @Severity(SeverityLevel.BLOCKER)
+  @Test(description = "Search with DynamicField.", groups = {"Smoke"},dataProvider = "dynamicExpressions")
+  public void searchWithDynamicField(String expr){
+    List<JSONObject> jsonObjects = CommonFunction.generateDataWithDynamicFiledRow(1000);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withRows(jsonObjects)
+            .withCollectionName(collectionWithDynamicField)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(),0);
+    CommonFunction.createIndexWithLoad(collectionWithDynamicField,IndexType.HNSW,MetricType.L2,CommonData.defaultVectorField);
+    // search
+    Integer SEARCH_K = 10; // TopK
+    String SEARCH_PARAM = "{\"nprobe\":10}";
+    List<String> search_output_fields = Arrays.asList("extra_field");
+    List<List<Float>> search_vectors = Arrays.asList(Arrays.asList(MathUtil.generateFloat(128)));
+    SearchParam searchParam =
+            SearchParam.newBuilder()
+                    .withCollectionName(collectionWithDynamicField)
+                    .withMetricType(MetricType.L2)
+                    .withOutFields(search_output_fields)
+                    .withTopK(SEARCH_K)
+                    .withVectors(search_vectors)
+                    .withVectorFieldName(CommonData.defaultVectorField)
+                    .withParams(SEARCH_PARAM)
+                    .withConsistencyLevel(ConsistencyLevelEnum.BOUNDED)
+                    .withExpr(expr)
+                    .build();
+    R<SearchResults> searchResultsR = milvusClient.search(searchParam);
+    Assert.assertEquals(searchResultsR.getStatus().intValue(), 0);
+    SearchResultsWrapper searchResultsWrapper =
+            new SearchResultsWrapper(searchResultsR.getData().getResults());
+    Assert.assertTrue(searchResultsWrapper.getFieldData("$meta", 0).size()>=4);
+    logger.info(searchResultsR.getData().getResults().toString());
+    System.out.println(searchResultsWrapper.getFieldData("$meta", 0).size());
+  }
+
+  @Severity(SeverityLevel.NORMAL)
+  @Test(description = "Search with DynamicField use nonexistent field name")
+  public void searchWithDynamicFieldUseNonexistentFiledName(){
+    List<JSONObject> jsonObjects = CommonFunction.generateDataWithDynamicFiledRow(1000);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withRows(jsonObjects)
+            .withCollectionName(collectionWithDynamicField)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(),0);
+    CommonFunction.createIndexWithLoad(collectionWithDynamicField,IndexType.HNSW,MetricType.L2,CommonData.defaultVectorField);
+    // search
+    Integer SEARCH_K = 10; // TopK
+    String SEARCH_PARAM = "{\"nprobe\":10}";
+    List<String> search_output_fields = Arrays.asList("extra_field_nonexistent");
+    List<List<Float>> search_vectors = Arrays.asList(Arrays.asList(MathUtil.generateFloat(128)));
+    SearchParam searchParam =
+            SearchParam.newBuilder()
+                    .withCollectionName(collectionWithDynamicField)
+                    .withMetricType(MetricType.L2)
+                    .withOutFields(search_output_fields)
+                    .withTopK(SEARCH_K)
+                    .withVectors(search_vectors)
+                    .withVectorFieldName(CommonData.defaultVectorField)
+                    .withParams(SEARCH_PARAM)
+                    .withConsistencyLevel(ConsistencyLevelEnum.BOUNDED)
+                    .withExpr(" extra_field2 > 100 ")
+                    .build();
+    R<SearchResults> searchResultsR = milvusClient.search(searchParam);
+    Assert.assertEquals(searchResultsR.getStatus().intValue(), 0);
+    SearchResultsWrapper searchResultsWrapper =
+            new SearchResultsWrapper(searchResultsR.getData().getResults());
+    Assert.assertEquals(searchResultsWrapper.getFieldData("$meta", 0).size(), 10);
+    logger.info(searchResultsR.getData().getResults().toString());
+
+  }
+
+  @Severity(SeverityLevel.BLOCKER)
+  @Test(description = "Search with JSON field.", groups = {"Smoke"},dataProvider = "jsonExpressions")
+  public void searchWithJsonField(String expr) {
+    List<JSONObject> jsonObjects = CommonFunction.generateJsonData(1000);
+    R<MutationResult> insert = milvusClient.insert(InsertParam.newBuilder()
+            .withRows(jsonObjects)
+            .withCollectionName(collectionWithJsonField)
+            .build());
+    Assert.assertEquals(insert.getStatus().intValue(), 0);
+    CommonFunction.createIndexWithLoad(collectionWithJsonField, IndexType.HNSW, MetricType.L2, "float_vector");
+    // search
+    Integer SEARCH_K = 10; // TopK
+    String SEARCH_PARAM = "{\"nprobe\":10}";
+    List<String> search_output_fields = Arrays.asList("json_field");
+    List<List<Float>> search_vectors = Arrays.asList(Arrays.asList(MathUtil.generateFloat(128)));
+    SearchParam searchParam =
+            SearchParam.newBuilder()
+                    .withCollectionName(collectionWithJsonField)
+                    .withMetricType(MetricType.L2)
+                    .withOutFields(search_output_fields)
+                    .withTopK(SEARCH_K)
+                    .withVectors(search_vectors)
+                    .withVectorFieldName("float_vector")
+                    .withParams(SEARCH_PARAM)
+                    .withExpr(expr)
+                    .withConsistencyLevel(ConsistencyLevelEnum.STRONG)
+                    .build();
+    R<SearchResults> searchResultsR = milvusClient.search(searchParam);
+    Assert.assertEquals(searchResultsR.getStatus().intValue(), 0);
+    SearchResultsWrapper searchResultsWrapper =
+            new SearchResultsWrapper(searchResultsR.getData().getResults());
+    Assert.assertTrue(searchResultsWrapper.getFieldData("json_field", 0).size()>=4);
+    // 按照列获取数据
+    FieldDataWrapper json_field = searchResultsWrapper.getFieldWrapper("json_field");
+    String string_field = json_field.getAsString(0, "string_field");
+    Assert.assertTrue(string_field.contains("Str"));
+    // 按照行
+    JSONObject jsonObject= (JSONObject) searchResultsWrapper.getIDScore(0).get(0).get("json_field");
+    String string = jsonObject.getString("string_field");
+    Assert.assertTrue(string.contains("Str"));
+
+
+  }
 }
 }