Browse Source

XPack/HLRC request/response compatibility tests (#34547)

Relates #34451 , #29827
Vladimir Dolzhenko 7 years ago
parent
commit
28bb1a3ac0
25 changed files with 600 additions and 228 deletions
  1. 2 2
      client/rest-high-level/src/main/java/org/elasticsearch/client/GraphClient.java
  2. 19 3
      client/rest-high-level/src/main/java/org/elasticsearch/client/graph/GraphExploreResponse.java
  3. 8 0
      client/rest-high-level/src/main/java/org/elasticsearch/client/graph/Vertex.java
  4. 6 3
      client/rest-high-level/src/main/java/org/elasticsearch/client/license/StartBasicResponse.java
  5. 1 15
      client/rest-high-level/src/main/java/org/elasticsearch/client/migration/UpgradeActionRequired.java
  6. 3 47
      client/rest-high-level/src/main/java/org/elasticsearch/client/xpack/XPackInfoResponse.java
  7. 1 1
      client/rest-high-level/src/main/java/org/elasticsearch/client/xpack/XPackUsageResponse.java
  8. 1 1
      client/rest-high-level/src/test/java/org/elasticsearch/client/graph/GraphExploreResponseTests.java
  9. 0 103
      client/rest-high-level/src/test/java/org/elasticsearch/client/license/StartBasicResponseTests.java
  10. 0 2
      client/rest-high-level/src/test/java/org/elasticsearch/client/migration/IndexUpgradeInfoRequestTests.java
  11. 0 26
      client/rest-high-level/src/test/java/org/elasticsearch/client/migration/IndexUpgradeInfoResponseTests.java
  12. 116 0
      client/rest-high-level/src/test/java/org/elasticsearch/client/xpack/XPackInfoResponseTests.java
  13. 1 0
      x-pack/plugin/core/build.gradle
  14. 106 10
      x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartBasicResponse.java
  15. 1 1
      x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/graph/GraphExploreResponse.java
  16. 46 0
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java
  17. 36 0
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java
  18. 37 2
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/XPackInfoResponseTests.java
  19. 54 4
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/graph/GraphExploreResponseTests.java
  20. 16 0
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/license/LicenseStatusTests.java
  21. 14 2
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/license/PutLicenseResponseTests.java
  22. 86 0
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/license/StartBasicResponseTests.java
  23. 20 2
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/migration/IndexUpgradeInfoResponseTests.java
  24. 13 2
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/DeleteWatchResponseTests.java
  25. 13 2
      x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/PutWatchResponseTests.java

+ 2 - 2
client/rest-high-level/src/main/java/org/elasticsearch/client/GraphClient.java

@@ -44,7 +44,7 @@ public class GraphClient {
     public final GraphExploreResponse explore(GraphExploreRequest graphExploreRequest,
                                                              RequestOptions options) throws IOException {
         return restHighLevelClient.performRequestAndParseEntity(graphExploreRequest, GraphRequestConverters::explore,
-                options, GraphExploreResponse::fromXContext, emptySet());
+                options, GraphExploreResponse::fromXContent, emptySet());
     }
 
     /**
@@ -57,7 +57,7 @@ public class GraphClient {
                                            RequestOptions options,
                                            ActionListener<GraphExploreResponse> listener) {
         restHighLevelClient.performRequestAsyncAndParseEntity(graphExploreRequest, GraphRequestConverters::explore,
-            options, GraphExploreResponse::fromXContext, listener, emptySet());
+            options, GraphExploreResponse::fromXContent, listener, emptySet());
     }    
     
 }

+ 19 - 3
client/rest-high-level/src/main/java/org/elasticsearch/client/graph/GraphExploreResponse.java

@@ -47,7 +47,7 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optiona
  * 
  * @see GraphExploreRequest
  */
-public class GraphExploreResponse  implements ToXContentObject {
+public class GraphExploreResponse implements ToXContentObject {
 
     private long tookInMillis;
     private boolean timedOut = false;
@@ -94,14 +94,30 @@ public class GraphExploreResponse  implements ToXContentObject {
         return connections.values();
     }
 
+    public Collection<ConnectionId> getConnectionIds() {
+        return connections.keySet();
+    }
+
+    public Connection getConnection(ConnectionId connectionId) {
+        return connections.get(connectionId);
+    }
+
     public Collection<Vertex> getVertices() {
         return vertices.values();
     }
-    
+
+    public Collection<VertexId> getVertexIds() {
+        return vertices.keySet();
+    }
+
     public Vertex getVertex(VertexId id) {
         return vertices.get(id);
     }
 
+    public boolean isReturnDetailedInfo() {
+        return returnDetailedInfo;
+    }
+
     private static final ParseField TOOK = new ParseField("took");
     private static final ParseField TIMED_OUT = new ParseField("timed_out");
     private static final ParseField VERTICES = new ParseField("vertices");
@@ -190,7 +206,7 @@ public class GraphExploreResponse  implements ToXContentObject {
         PARSER.declareObjectArray(optionalConstructorArg(), (p, c) -> ShardSearchFailure.fromXContent(p), FAILURES);
     } 
     
-    public static GraphExploreResponse fromXContext(XContentParser parser) throws IOException {
+    public static GraphExploreResponse fromXContent(XContentParser parser) throws IOException {
         return PARSER.apply(parser, null);
     }
 

+ 8 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/graph/Vertex.java

@@ -220,6 +220,14 @@ public class Vertex implements ToXContentFragment {
             this.term = term;
         }
 
+        public String getField() {
+            return field;
+        }
+
+        public String getTerm() {
+            return term;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (this == o)

+ 6 - 3
client/rest-high-level/src/main/java/org/elasticsearch/client/license/StartBasicResponse.java

@@ -84,14 +84,13 @@ public class StartBasicResponse {
                     }
                 }
                 return new Tuple<>(message, acknowledgeMessages);
-            },
-            new ParseField("acknowledge"));
+            }, new ParseField("acknowledge"));
     }
 
     private Map<String, String[]> acknowledgeMessages;
     private String acknowledgeMessage;
 
-    enum Status {
+    public enum Status {
         GENERATED_BASIC(true, null, RestStatus.OK),
         ALREADY_USING_BASIC(false, "Operation failed: Current license is basic.", RestStatus.FORBIDDEN),
         NEED_ACKNOWLEDGEMENT(false, "Operation failed: Needs acknowledgement.", RestStatus.OK);
@@ -141,6 +140,10 @@ public class StartBasicResponse {
         this.acknowledgeMessage = acknowledgeMessage;
     }
 
+    public Status getStatus() {
+        return status;
+    }
+
     public boolean isAcknowledged() {
         return status != StartBasicResponse.Status.NEED_ACKNOWLEDGEMENT;
     }

+ 1 - 15
client/rest-high-level/src/main/java/org/elasticsearch/client/migration/UpgradeActionRequired.java

@@ -18,17 +18,12 @@
  */
 package org.elasticsearch.client.migration;
 
-import org.elasticsearch.common.io.stream.StreamInput;
-import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.common.io.stream.Writeable;
-
-import java.io.IOException;
 import java.util.Locale;
 
 /**
  * Indicates the type of the upgrade required for the index
  */
-public enum UpgradeActionRequired implements Writeable {
+public enum UpgradeActionRequired {
     NOT_APPLICABLE,   // Indicates that the check is not applicable to this index type, the next check will be performed
     UP_TO_DATE,       // Indicates that the check finds this index to be up to date - no additional checks are required
     REINDEX,          // The index should be reindex
@@ -38,15 +33,6 @@ public enum UpgradeActionRequired implements Writeable {
         return UpgradeActionRequired.valueOf(value.toUpperCase(Locale.ROOT));
     }
 
-    public static UpgradeActionRequired readFromStream(StreamInput in) throws IOException {
-        return in.readEnum(UpgradeActionRequired.class);
-    }
-
-    @Override
-    public void writeTo(StreamOutput out) throws IOException {
-        out.writeEnum(this);
-    }
-
     @Override
     public String toString() {
         return name().toLowerCase(Locale.ROOT);

+ 3 - 47
client/rest-high-level/src/main/java/org/elasticsearch/client/xpack/XPackInfoResponse.java

@@ -21,9 +21,6 @@ package org.elasticsearch.client.xpack;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.ParseField;
 import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.io.stream.StreamInput;
-import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.common.io.stream.Writeable;
 import org.elasticsearch.common.xcontent.ConstructingObjectParser;
 import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
 import org.elasticsearch.common.xcontent.ToXContentObject;
@@ -252,7 +249,7 @@ public class XPackInfoResponse implements ToXContentObject {
         }
     }
 
-    public static class BuildInfo implements ToXContentObject, Writeable {
+    public static class BuildInfo implements ToXContentObject {
         private final String hash;
         private final String timestamp;
 
@@ -261,16 +258,6 @@ public class XPackInfoResponse implements ToXContentObject {
             this.timestamp = timestamp;
         }
 
-        public BuildInfo(StreamInput input) throws IOException {
-            this(input.readString(), input.readString());
-        }
-
-        @Override
-        public void writeTo(StreamOutput output) throws IOException {
-            output.writeString(hash);
-            output.writeString(timestamp);
-        }
-
         public String getHash() {
             return hash;
         }
@@ -309,7 +296,7 @@ public class XPackInfoResponse implements ToXContentObject {
         }
     }
 
-    public static class FeatureSetsInfo implements ToXContentObject, Writeable {
+    public static class FeatureSetsInfo implements ToXContentObject {
         private final Map<String, FeatureSet> featureSets;
 
         public FeatureSetsInfo(Set<FeatureSet> featureSets) {
@@ -320,24 +307,6 @@ public class XPackInfoResponse implements ToXContentObject {
             this.featureSets = Collections.unmodifiableMap(map);
         }
 
-        public FeatureSetsInfo(StreamInput in) throws IOException {
-            int size = in.readVInt();
-            Map<String, FeatureSet> featureSets = new HashMap<>(size);
-            for (int i = 0; i < size; i++) {
-                FeatureSet featureSet = new FeatureSet(in);
-                featureSets.put(featureSet.name, featureSet);
-            }
-            this.featureSets = Collections.unmodifiableMap(featureSets);
-        }
-
-        @Override
-        public void writeTo(StreamOutput out) throws IOException {
-            out.writeVInt(featureSets.size());
-            for (FeatureSet featureSet : featureSets.values()) {
-                featureSet.writeTo(out);
-            }
-        }
-
         public Map<String, FeatureSet> getFeatureSets() {
             return featureSets;
         }
@@ -365,7 +334,7 @@ public class XPackInfoResponse implements ToXContentObject {
             return builder.endObject();
         }
 
-        public static class FeatureSet implements ToXContentObject, Writeable {
+        public static class FeatureSet implements ToXContentObject {
             private final String name;
             @Nullable private final String description;
             private final boolean available;
@@ -381,19 +350,6 @@ public class XPackInfoResponse implements ToXContentObject {
                 this.nativeCodeInfo = nativeCodeInfo;
             }
 
-            public FeatureSet(StreamInput in) throws IOException {
-                this(in.readString(), in.readOptionalString(), in.readBoolean(), in.readBoolean(), in.readMap());
-            }
-
-            @Override
-            public void writeTo(StreamOutput out) throws IOException {
-                out.writeString(name);
-                out.writeOptionalString(description);
-                out.writeBoolean(available);
-                out.writeBoolean(enabled);
-                out.writeMap(nativeCodeInfo);
-            }
-
             public String name() {
                 return name;
             }

+ 1 - 1
client/rest-high-level/src/main/java/org/elasticsearch/client/xpack/XPackUsageResponse.java

@@ -34,7 +34,7 @@ public class XPackUsageResponse {
 
     private final Map<String, Map<String, Object>> usages;
 
-    private XPackUsageResponse(Map<String, Map<String, Object>> usages) throws IOException {
+    private XPackUsageResponse(Map<String, Map<String, Object>> usages) {
         this.usages = usages;
     }
 

+ 1 - 1
client/rest-high-level/src/test/java/org/elasticsearch/client/graph/GraphExploreResponseTests.java

@@ -81,7 +81,7 @@ public class GraphExploreResponseTests extends AbstractXContentTestCase<GraphExp
 
     @Override
     protected  GraphExploreResponse doParseInstance(XContentParser parser) throws IOException {
-        return GraphExploreResponse.fromXContext(parser);
+        return GraphExploreResponse.fromXContent(parser);
     }
 
     @Override

+ 0 - 103
client/rest-high-level/src/test/java/org/elasticsearch/client/license/StartBasicResponseTests.java

@@ -1,103 +0,0 @@
-/*
- * Licensed to Elasticsearch under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.client.license;
-
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentFactory;
-import org.elasticsearch.common.xcontent.XContentType;
-import org.elasticsearch.client.common.ProtocolUtils;
-import org.elasticsearch.test.ESTestCase;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-
-public class StartBasicResponseTests extends ESTestCase {
-
-    public void testFromXContent() throws Exception {
-        StartBasicResponse.Status status = randomFrom(StartBasicResponse.Status.values());
-
-        boolean acknowledged = status != StartBasicResponse.Status.NEED_ACKNOWLEDGEMENT;
-        String acknowledgeMessage = null;
-        Map<String, String[]> ackMessages = Collections.emptyMap();
-        if (status != StartBasicResponse.Status.GENERATED_BASIC) {
-            acknowledgeMessage = randomAlphaOfLength(10);
-            ackMessages = randomAckMessages();
-        }
-
-        final StartBasicResponse startBasicResponse = new StartBasicResponse(status, ackMessages, acknowledgeMessage);
-
-        XContentType xContentType = randomFrom(XContentType.values());
-        XContentBuilder builder = XContentFactory.contentBuilder(xContentType);
-
-        toXContent(startBasicResponse, builder);
-
-        final StartBasicResponse response = StartBasicResponse.fromXContent(createParser(builder));
-        assertThat(response.isAcknowledged(), equalTo(acknowledged));
-        assertThat(response.isBasicStarted(), equalTo(status.isBasicStarted()));
-        assertThat(response.getAcknowledgeMessage(), equalTo(acknowledgeMessage));
-        assertThat(ProtocolUtils.equals(response.getAcknowledgeMessages(), ackMessages), equalTo(true));
-    }
-
-    private static void toXContent(StartBasicResponse response, XContentBuilder builder) throws IOException {
-        builder.startObject();
-        builder.field("acknowledged", response.isAcknowledged());
-        if (response.isBasicStarted()) {
-            builder.field("basic_was_started", true);
-        } else {
-            builder.field("basic_was_started", false);
-            builder.field("error_message", response.getErrorMessage());
-        }
-        if (response.getAcknowledgeMessages().isEmpty() == false) {
-            builder.startObject("acknowledge");
-            builder.field("message", response.getAcknowledgeMessage());
-            for (Map.Entry<String, String[]> entry : response.getAcknowledgeMessages().entrySet()) {
-                builder.startArray(entry.getKey());
-                for (String message : entry.getValue()) {
-                    builder.value(message);
-                }
-                builder.endArray();
-            }
-            builder.endObject();
-        }
-        builder.endObject();
-    }
-
-    private static Map<String, String[]> randomAckMessages() {
-        int nFeatures = randomIntBetween(1, 5);
-
-        Map<String, String[]> ackMessages = new HashMap<>();
-
-        for (int i = 0; i < nFeatures; i++) {
-            String feature = randomAlphaOfLengthBetween(9, 15);
-            int nMessages = randomIntBetween(1, 5);
-            String[] messages = new String[nMessages];
-            for (int j = 0; j < nMessages; j++) {
-                messages[j] = randomAlphaOfLengthBetween(10, 30);
-            }
-            ackMessages.put(feature, messages);
-        }
-
-        return ackMessages;
-    }
-
-}

+ 0 - 2
client/rest-high-level/src/test/java/org/elasticsearch/client/migration/IndexUpgradeInfoRequestTests.java

@@ -23,8 +23,6 @@ import org.elasticsearch.test.ESTestCase;
 
 public class IndexUpgradeInfoRequestTests extends ESTestCase {
 
-    // TODO: add to cross XPack-HLRC serialization test
-
     public void testNullIndices() {
         expectThrows(NullPointerException.class, () -> new IndexUpgradeInfoRequest((String[])null));
         expectThrows(NullPointerException.class, () -> new IndexUpgradeInfoRequest().indices((String[])null));

+ 0 - 26
client/rest-high-level/src/test/java/org/elasticsearch/client/migration/IndexUpgradeInfoResponseTests.java

@@ -1,26 +0,0 @@
-/*
- * Licensed to Elasticsearch under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.client.migration;
-
-import org.elasticsearch.test.ESTestCase;
-
-public class IndexUpgradeInfoResponseTests extends ESTestCase {
-    // TODO: add to cross XPack-HLRC serialization test
-}

+ 116 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/xpack/XPackInfoResponseTests.java

@@ -0,0 +1,116 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.client.xpack;
+
+import org.elasticsearch.client.license.LicenseStatus;
+import org.elasticsearch.client.xpack.XPackInfoResponse.BuildInfo;
+import org.elasticsearch.client.xpack.XPackInfoResponse.FeatureSetsInfo;
+import org.elasticsearch.client.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
+import org.elasticsearch.client.xpack.XPackInfoResponse.LicenseInfo;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+
+public class XPackInfoResponseTests extends AbstractXContentTestCase<XPackInfoResponse> {
+
+    @Override
+    protected boolean supportsUnknownFields() {
+        return true;
+    }
+
+    protected XPackInfoResponse doParseInstance(XContentParser parser) throws IOException {
+        return XPackInfoResponse.fromXContent(parser);
+    }
+
+    protected Predicate<String> getRandomFieldsExcludeFilter() {
+        return path -> path.equals("features")
+                || (path.startsWith("features") && path.endsWith("native_code_info"));
+    }
+
+    protected ToXContent.Params getToXContentParams() {
+        Map<String, String> params = new HashMap<>();
+        if (randomBoolean()) {
+            params.put("human", randomBoolean() ? "true" : "false");
+        }
+        if (randomBoolean()) {
+            params.put("categories", "_none");
+        }
+        return new ToXContent.MapParams(params);
+    }
+
+    protected XPackInfoResponse createTestInstance() {
+        return new XPackInfoResponse(
+            randomBoolean() ? null : randomBuildInfo(),
+            randomBoolean() ? null : randomLicenseInfo(),
+            randomBoolean() ? null : randomFeatureSetsInfo());
+    }
+
+    private BuildInfo randomBuildInfo() {
+        return new BuildInfo(
+            randomAlphaOfLength(10),
+            randomAlphaOfLength(15));
+    }
+
+    private LicenseInfo randomLicenseInfo() {
+        return new LicenseInfo(
+            randomAlphaOfLength(10),
+            randomAlphaOfLength(4),
+            randomAlphaOfLength(5),
+            randomFrom(LicenseStatus.values()),
+            randomLong());
+    }
+
+    private FeatureSetsInfo randomFeatureSetsInfo() {
+        int size = between(0, 10);
+        Set<FeatureSet> featureSets = new HashSet<>(size);
+        while (featureSets.size() < size) {
+            featureSets.add(randomFeatureSet());
+        }
+        return new FeatureSetsInfo(featureSets);
+    }
+
+    private FeatureSet randomFeatureSet() {
+        return new FeatureSet(
+            randomAlphaOfLength(5),
+            randomBoolean() ? null : randomAlphaOfLength(20),
+            randomBoolean(),
+            randomBoolean(),
+            randomNativeCodeInfo());
+    }
+
+    private Map<String, Object> randomNativeCodeInfo() {
+        if (randomBoolean()) {
+            return null;
+        }
+        int size = between(0, 10);
+        Map<String, Object> nativeCodeInfo = new HashMap<>(size);
+        while (nativeCodeInfo.size() < size) {
+            nativeCodeInfo.put(randomAlphaOfLength(5), randomAlphaOfLength(5));
+        }
+        return nativeCodeInfo;
+    }
+}

+ 1 - 0
x-pack/plugin/core/build.gradle

@@ -49,6 +49,7 @@ dependencies {
     testCompile project(path: ':modules:reindex', configuration: 'runtime')
     testCompile project(path: ':modules:parent-join', configuration: 'runtime')
     testCompile project(path: ':modules:analysis-common', configuration: 'runtime')
+    testCompile ("org.elasticsearch.client:elasticsearch-rest-high-level-client:${version}")
 }
 
 ext.expansions = [

+ 106 - 10
x-pack/plugin/core/src/main/java/org/elasticsearch/license/PostStartBasicResponse.java

@@ -6,24 +6,88 @@
 package org.elasticsearch.license;
 
 import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.collect.Tuple;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
 import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentParseException;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.protocol.xpack.common.ProtocolUtils;
 import org.elasticsearch.rest.RestStatus;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
-import static org.elasticsearch.license.PostStartBasicResponse.Status.NEED_ACKNOWLEDGEMENT;
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
 
-class PostStartBasicResponse extends AcknowledgedResponse {
+public class PostStartBasicResponse extends AcknowledgedResponse {
+
+    private static final ConstructingObjectParser<PostStartBasicResponse, Void> PARSER = new ConstructingObjectParser<>(
+        "start_basic_response", true, (a, v) -> {
+        boolean basicWasStarted = (Boolean) a[0];
+        String errorMessage = (String) a[1];
+
+        if (basicWasStarted) {
+            return new PostStartBasicResponse(Status.GENERATED_BASIC);
+        }
+        Status status = Status.fromErrorMessage(errorMessage);
+        @SuppressWarnings("unchecked") Tuple<String, Map<String, String[]>> acknowledgements = (Tuple<String, Map<String, String[]>>) a[2];
+        return new PostStartBasicResponse(status, acknowledgements.v2(), acknowledgements.v1());
+    });
+
+    private static final ParseField BASIC_WAS_STARTED_FIELD = new ParseField("basic_was_started");
+    private static final ParseField ERROR_MESSAGE_FIELD = new ParseField("error_message");
+    private static final ParseField ACKNOWLEDGE_FIELD = new ParseField("acknowledge");
+    private static final ParseField MESSAGE_FIELD = new ParseField("message");
+
+    static {
+        PARSER.declareBoolean(constructorArg(), BASIC_WAS_STARTED_FIELD);
+        PARSER.declareString(optionalConstructorArg(), ERROR_MESSAGE_FIELD);
+        PARSER.declareObject(optionalConstructorArg(), (parser, v) -> {
+                Map<String, String[]> acknowledgeMessages = new HashMap<>();
+                String message = null;
+                XContentParser.Token token;
+                String currentFieldName = null;
+                while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+                    if (token == XContentParser.Token.FIELD_NAME) {
+                        currentFieldName = parser.currentName();
+                    } else {
+                        if (currentFieldName == null) {
+                            throw new XContentParseException(parser.getTokenLocation(), "expected message header or acknowledgement");
+                        }
+                        if (MESSAGE_FIELD.getPreferredName().equals(currentFieldName)) {
+                            ensureExpectedToken(XContentParser.Token.VALUE_STRING, token, parser::getTokenLocation);
+                            message = parser.text();
+                        } else {
+                            if (token != XContentParser.Token.START_ARRAY) {
+                                throw new XContentParseException(parser.getTokenLocation(), "unexpected acknowledgement type");
+                            }
+                            List<String> acknowledgeMessagesList = new ArrayList<>();
+                            while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
+                                ensureExpectedToken(XContentParser.Token.VALUE_STRING, token, parser::getTokenLocation);
+                                acknowledgeMessagesList.add(parser.text());
+                            }
+                            acknowledgeMessages.put(currentFieldName, acknowledgeMessagesList.toArray(new String[0]));
+                        }
+                    }
+                }
+                return new Tuple<>(message, acknowledgeMessages);
+            }, ACKNOWLEDGE_FIELD);
+    }
 
     private Map<String, String[]> acknowledgeMessages;
     private String acknowledgeMessage;
 
-    enum Status {
+    public enum Status {
         GENERATED_BASIC(true, null, RestStatus.OK),
         ALREADY_USING_BASIC(false, "Operation failed: Current license is basic.", RestStatus.FORBIDDEN),
         NEED_ACKNOWLEDGEMENT(false, "Operation failed: Needs acknowledgement.", RestStatus.OK);
@@ -49,19 +113,29 @@ class PostStartBasicResponse extends AcknowledgedResponse {
         RestStatus getRestStatus() {
             return restStatus;
         }
+
+        static Status fromErrorMessage(final String errorMessage) {
+            final Status[] values = Status.values();
+            for (Status status : values) {
+                if (Objects.equals(status.errorMessage, errorMessage)) {
+                    return status;
+                }
+            }
+            throw new IllegalArgumentException("No status for error message ['" + errorMessage + "']");
+        }
     }
 
     private Status status;
 
-    PostStartBasicResponse() {
+    public PostStartBasicResponse() {
     }
 
     PostStartBasicResponse(Status status) {
         this(status, Collections.emptyMap(), null);
     }
 
-    PostStartBasicResponse(Status status, Map<String, String[]> acknowledgeMessages, String acknowledgeMessage) {
-        super(status != NEED_ACKNOWLEDGEMENT);
+    public PostStartBasicResponse(Status status, Map<String, String[]> acknowledgeMessages, String acknowledgeMessage) {
+        super(status != Status.NEED_ACKNOWLEDGEMENT);
         this.status = status;
         this.acknowledgeMessages = acknowledgeMessages;
         this.acknowledgeMessage = acknowledgeMessage;
@@ -108,14 +182,14 @@ class PostStartBasicResponse extends AcknowledgedResponse {
     @Override
     protected void addCustomFields(XContentBuilder builder, Params params) throws IOException {
         if (status.isBasicStarted()) {
-            builder.field("basic_was_started", true);
+            builder.field(BASIC_WAS_STARTED_FIELD.getPreferredName(), true);
         } else {
-            builder.field("basic_was_started", false);
-            builder.field("error_message", status.getErrorMessage());
+            builder.field(BASIC_WAS_STARTED_FIELD.getPreferredName(), false);
+            builder.field(ERROR_MESSAGE_FIELD.getPreferredName(), status.getErrorMessage());
         }
         if (acknowledgeMessages.isEmpty() == false) {
             builder.startObject("acknowledge");
-            builder.field("message", acknowledgeMessage);
+            builder.field(MESSAGE_FIELD.getPreferredName(), acknowledgeMessage);
             for (Map.Entry<String, String[]> entry : acknowledgeMessages.entrySet()) {
                 builder.startArray(entry.getKey());
                 for (String message : entry.getValue()) {
@@ -126,4 +200,26 @@ class PostStartBasicResponse extends AcknowledgedResponse {
             builder.endObject();
         }
     }
+
+    public static PostStartBasicResponse fromXContent(XContentParser parser) throws IOException {
+        return PARSER.parse(parser, null);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+        PostStartBasicResponse that = (PostStartBasicResponse) o;
+
+        return status == that.status &&
+            ProtocolUtils.equals(acknowledgeMessages, that.acknowledgeMessages) &&
+            Objects.equals(acknowledgeMessage, that.acknowledgeMessage);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), status, ProtocolUtils.hashCode(acknowledgeMessages), acknowledgeMessage);
+    }
+
 }

+ 1 - 1
x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/graph/GraphExploreResponse.java

@@ -241,7 +241,7 @@ public class GraphExploreResponse extends ActionResponse implements ToXContentOb
         PARSER.declareObjectArray(optionalConstructorArg(), (p, c) -> ShardSearchFailure.fromXContent(p), FAILURES);
     } 
     
-    public static GraphExploreResponse fromXContext(XContentParser parser) throws IOException {
+    public static GraphExploreResponse fromXContent(XContentParser parser) throws IOException {
         return PARSER.apply(parser, null);
     }
 

+ 46 - 0
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcStreamableXContentTestCase.java

@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.protocol;
+
+import org.elasticsearch.common.io.stream.Streamable;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractStreamableXContentTestCase;
+
+import java.io.IOException;
+
+import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester;
+
+public abstract class AbstractHlrcStreamableXContentTestCase<T extends ToXContent & Streamable, H>
+        extends AbstractStreamableXContentTestCase<T> {
+
+    /**
+     * Generic test that creates new instance of HLRC request/response from the test instance and checks
+     * both for equality and asserts equality on the two queries.
+     */
+    public final void testHlrcFromXContent() throws IOException {
+        xContentTester(this::createParser, this::createTestInstance, getToXContentParams(),
+            p -> convertHlrcToInternal(doHlrcParseInstance(p)))
+            .numberOfTestRuns(NUMBER_OF_TEST_RUNS)
+            .supportsUnknownFields(supportsUnknownFields())
+            .shuffleFieldsExceptions(getShuffleFieldsExceptions())
+            .randomFieldsExcludeFilter(getRandomFieldsExcludeFilter())
+            .assertEqualsConsumer(this::assertEqualInstances)
+            .assertToXContentEquivalence(true)
+            .test();
+    }
+
+    /**
+     * Parses to a new HLRC instance using the provided {@link XContentParser}
+     */
+    public abstract H doHlrcParseInstance(XContentParser parser) throws IOException;
+
+    /**
+     * Converts a HLRC instance to a XPack instance
+     */
+    public abstract T convertHlrcToInternal(H instance);
+
+}

+ 36 - 0
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/AbstractHlrcXContentTestCase.java

@@ -0,0 +1,36 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.protocol;
+
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+
+public abstract class AbstractHlrcXContentTestCase<T extends ToXContent, H> extends AbstractXContentTestCase<T> {
+
+    /**
+     * Generic test that creates new instance of HLRC request/response from the test instance and checks
+     * both for equality and asserts equality on the two queries.
+     */
+    public final void testHlrcFromXContent() throws IOException {
+        AbstractXContentTestCase.testFromXContent(NUMBER_OF_TEST_RUNS, this::createTestInstance, supportsUnknownFields(),
+            getShuffleFieldsExceptions(), getRandomFieldsExcludeFilter(), this::createParser,
+            p -> convertHlrcToInternal(doHlrcParseInstance(p)),
+            this::assertEqualInstances, true, getToXContentParams());
+    }
+
+    /**
+     * Parses to a new HLRC instance using the provided {@link XContentParser}
+     */
+    public abstract H doHlrcParseInstance(XContentParser parser) throws IOException;
+
+    /**
+     * Converts a HLRC instance to a XPack instance
+     */
+    public abstract T convertHlrcToInternal(H instance);
+}

+ 37 - 2
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/XPackInfoResponseTests.java

@@ -7,12 +7,12 @@ package org.elasticsearch.protocol.xpack;
 
 import org.elasticsearch.common.xcontent.ToXContent;
 import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase;
 import org.elasticsearch.protocol.xpack.XPackInfoResponse.BuildInfo;
 import org.elasticsearch.protocol.xpack.XPackInfoResponse.LicenseInfo;
 import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo;
 import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
 import org.elasticsearch.protocol.xpack.license.LicenseStatus;
-import org.elasticsearch.test.AbstractStreamableXContentTestCase;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -21,8 +21,11 @@ import java.util.Set;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.io.IOException;
+import java.util.stream.Collectors;
+
+public class XPackInfoResponseTests extends
+        AbstractHlrcStreamableXContentTestCase<XPackInfoResponse, org.elasticsearch.client.xpack.XPackInfoResponse> {
 
-public class XPackInfoResponseTests extends AbstractStreamableXContentTestCase<XPackInfoResponse> {
     @Override
     protected XPackInfoResponse doParseInstance(XContentParser parser) throws IOException {
         return XPackInfoResponse.fromXContent(parser);
@@ -33,6 +36,38 @@ public class XPackInfoResponseTests extends AbstractStreamableXContentTestCase<X
         return new XPackInfoResponse();
     }
 
+    @Override
+    public org.elasticsearch.client.xpack.XPackInfoResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return org.elasticsearch.client.xpack.XPackInfoResponse.fromXContent(parser);
+    }
+
+    @Override
+    public XPackInfoResponse convertHlrcToInternal(org.elasticsearch.client.xpack.XPackInfoResponse instance) {
+        return new XPackInfoResponse(convertHlrcToInternal(instance.getBuildInfo()),
+            convertHlrcToInternal(instance.getLicenseInfo()), convertHlrcToInternal(instance.getFeatureSetsInfo()));
+    }
+
+    private BuildInfo convertHlrcToInternal(org.elasticsearch.client.xpack.XPackInfoResponse.BuildInfo buildInfo) {
+        return buildInfo != null ? new BuildInfo(buildInfo.getHash(), buildInfo.getTimestamp()) : null;
+    }
+
+    private LicenseInfo convertHlrcToInternal(org.elasticsearch.client.xpack.XPackInfoResponse.LicenseInfo licenseInfo) {
+        return licenseInfo != null
+            ? new LicenseInfo(licenseInfo.getUid(), licenseInfo.getType(), licenseInfo.getMode(),
+                licenseInfo.getStatus() != null ? LicenseStatus.valueOf(licenseInfo.getStatus().name()) : null,
+                licenseInfo.getExpiryDate())
+            : null;
+    }
+
+    private FeatureSetsInfo convertHlrcToInternal(org.elasticsearch.client.xpack.XPackInfoResponse.FeatureSetsInfo featureSetsInfo) {
+        return featureSetsInfo != null
+            ? new FeatureSetsInfo(featureSetsInfo.getFeatureSets().values().stream()
+            .map(fs -> new FeatureSet(fs.name(), fs.description(), fs.available(), fs.enabled(),
+                fs.nativeCodeInfo()))
+            .collect(Collectors.toSet()))
+            : null;
+    }
+
     @Override
     protected Predicate<String> getRandomFieldsExcludeFilter() {
         return path -> path.equals("features")

+ 54 - 4
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/graph/GraphExploreResponseTests.java

@@ -10,24 +10,74 @@ import org.elasticsearch.action.ShardOperationFailedException;
 import org.elasticsearch.action.search.ShardSearchFailure;
 import org.elasticsearch.common.xcontent.ToXContent;
 import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.protocol.AbstractHlrcXContentTestCase;
 import org.elasticsearch.test.AbstractXContentTestCase;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 
 import static org.hamcrest.Matchers.equalTo;
 
-public class GraphExploreResponseTests extends AbstractXContentTestCase< GraphExploreResponse> {
+public class GraphExploreResponseTests extends
+        AbstractHlrcXContentTestCase<GraphExploreResponse, org.elasticsearch.client.graph.GraphExploreResponse> {
+
+    static final Function<org.elasticsearch.client.graph.Vertex.VertexId, Vertex.VertexId> VERTEX_ID_FUNCTION =
+        vId -> new Vertex.VertexId(vId.getField(), vId.getTerm());
+    static final Function<org.elasticsearch.client.graph.Vertex, Vertex> VERTEX_FUNCTION =
+        v -> new Vertex(v.getField(), v.getTerm(), v.getWeight(), v.getHopDepth(), v.getBg(), v.getFg());
+
+    @Override
+    public org.elasticsearch.client.graph.GraphExploreResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return org.elasticsearch.client.graph.GraphExploreResponse.fromXContent(parser);
+    }
+
+    @Override
+    public GraphExploreResponse convertHlrcToInternal(org.elasticsearch.client.graph.GraphExploreResponse instance) {
+        return new GraphExploreResponse(instance.getTookInMillis(), instance.isTimedOut(),
+            instance.getShardFailures(), convertVertices(instance), convertConnections(instance), instance.isReturnDetailedInfo());
+    }
+
+    public Map<Vertex.VertexId, Vertex> convertVertices(org.elasticsearch.client.graph.GraphExploreResponse instance) {
+        final Collection<org.elasticsearch.client.graph.Vertex.VertexId> vertexIds = instance.getVertexIds();
+        final Map<Vertex.VertexId, Vertex> vertexMap = new LinkedHashMap<>(vertexIds.size());
+
+        for (org.elasticsearch.client.graph.Vertex.VertexId vertexId : vertexIds) {
+            final org.elasticsearch.client.graph.Vertex vertex = instance.getVertex(vertexId);
+
+            vertexMap.put(VERTEX_ID_FUNCTION.apply(vertexId), VERTEX_FUNCTION.apply(vertex));
+        }
+        return vertexMap;
+    }
+
+    public Map<Connection.ConnectionId, Connection> convertConnections(org.elasticsearch.client.graph.GraphExploreResponse instance) {
+        final Collection<org.elasticsearch.client.graph.Connection.ConnectionId> connectionIds = instance.getConnectionIds();
+        final Map<Connection.ConnectionId, Connection> connectionMap = new LinkedHashMap<>(connectionIds.size());
+        for (org.elasticsearch.client.graph.Connection.ConnectionId connectionId : connectionIds) {
+            final org.elasticsearch.client.graph.Connection connection = instance.getConnection(connectionId);
+            final Connection.ConnectionId connectionId1 =
+                new Connection.ConnectionId(VERTEX_ID_FUNCTION.apply(connectionId.getSource()),
+                    VERTEX_ID_FUNCTION.apply(connectionId.getTarget()));
+            final Connection connection1 = new Connection(VERTEX_FUNCTION.apply(connection.getFrom()),
+                VERTEX_FUNCTION.apply(connection.getTo()),
+                connection.getWeight(), connection.getDocCount());
+            connectionMap.put(connectionId1, connection1);
+        }
+        return connectionMap;
+    }
 
     @Override
     protected  GraphExploreResponse createTestInstance() {
         return createInstance(0);
     }
+
     private static  GraphExploreResponse createInstance(int numFailures) {
         int numItems = randomIntBetween(4, 128);
         boolean timedOut = randomBoolean();
@@ -62,13 +112,13 @@ public class GraphExploreResponseTests extends AbstractXContentTestCase< GraphEx
     }
     
 
-    private static   GraphExploreResponse createTestInstanceWithFailures() {
+    private static GraphExploreResponse createTestInstanceWithFailures() {
         return createInstance(randomIntBetween(1, 128));
     }
 
     @Override
     protected  GraphExploreResponse doParseInstance(XContentParser parser) throws IOException {
-        return GraphExploreResponse.fromXContext(parser);
+        return GraphExploreResponse.fromXContent(parser);
     }
 
     @Override
@@ -79,7 +129,7 @@ public class GraphExploreResponseTests extends AbstractXContentTestCase< GraphEx
     @Override
     protected boolean assertToXContentEquivalence() {
         return false;
-    }     
+    }
 
     @Override
     protected String[] getShuffleFieldsExceptions() {

+ 16 - 0
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/license/LicenseStatusTests.java

@@ -9,9 +9,25 @@ import java.io.IOException;
 
 import org.elasticsearch.test.ESTestCase;
 
+import static org.hamcrest.CoreMatchers.equalTo;
+
 public class LicenseStatusTests extends ESTestCase {
     public void testSerialization() throws IOException {
         LicenseStatus status = randomFrom(LicenseStatus.values());
         assertSame(status, copyWriteable(status, writableRegistry(), LicenseStatus::readFrom));
     }
+
+    public void testCompatibility() {
+        final LicenseStatus[] values = LicenseStatus.values();
+        final org.elasticsearch.client.license.LicenseStatus[] hlrcValues =
+            org.elasticsearch.client.license.LicenseStatus.values();
+
+        assertThat(values.length, equalTo(hlrcValues.length));
+
+        for (LicenseStatus value : values) {
+            final org.elasticsearch.client.license.LicenseStatus licenseStatus =
+                org.elasticsearch.client.license.LicenseStatus.fromString(value.label());
+            assertThat(licenseStatus.label(), equalTo(value.label()));
+        }
+    }
 }

+ 14 - 2
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/license/PutLicenseResponseTests.java

@@ -6,7 +6,7 @@
 package org.elasticsearch.protocol.xpack.license;
 
 import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.test.AbstractStreamableXContentTestCase;
+import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase;
 
 import java.io.IOException;
 import java.util.Collections;
@@ -15,7 +15,19 @@ import java.util.Map;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
-public class PutLicenseResponseTests extends AbstractStreamableXContentTestCase<PutLicenseResponse> {
+public class PutLicenseResponseTests extends
+        AbstractHlrcStreamableXContentTestCase<PutLicenseResponse, org.elasticsearch.client.license.PutLicenseResponse> {
+
+    @Override
+    public org.elasticsearch.client.license.PutLicenseResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return org.elasticsearch.client.license.PutLicenseResponse.fromXContent(parser);
+    }
+
+    @Override
+    public PutLicenseResponse convertHlrcToInternal(org.elasticsearch.client.license.PutLicenseResponse instance) {
+        return new PutLicenseResponse(instance.isAcknowledged(), LicensesStatus.valueOf(instance.status().name()),
+            instance.acknowledgeHeader(), instance.acknowledgeMessages());
+    }
 
     @Override
     protected boolean supportsUnknownFields() {

+ 86 - 0
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/license/StartBasicResponseTests.java

@@ -0,0 +1,86 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.protocol.xpack.license;
+
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.license.PostStartBasicResponse;
+import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
+
+public class StartBasicResponseTests extends
+        AbstractHlrcStreamableXContentTestCase<PostStartBasicResponse, org.elasticsearch.client.license.StartBasicResponse> {
+
+    @Override
+    public org.elasticsearch.client.license.StartBasicResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return org.elasticsearch.client.license.StartBasicResponse.fromXContent(parser);
+    }
+
+    @Override
+    public PostStartBasicResponse convertHlrcToInternal(org.elasticsearch.client.license.StartBasicResponse instance) {
+        return new PostStartBasicResponse(PostStartBasicResponse.Status.valueOf(instance.getStatus().name()),
+            instance.getAcknowledgeMessages(), instance.getAcknowledgeMessage());
+    }
+
+    @Override
+    protected PostStartBasicResponse doParseInstance(XContentParser parser) throws IOException {
+        return PostStartBasicResponse.fromXContent(parser);
+    }
+
+    @Override
+    protected PostStartBasicResponse createBlankInstance() {
+        return new PostStartBasicResponse();
+    }
+
+    @Override
+    protected boolean supportsUnknownFields() {
+        return true;
+    }
+
+    @Override
+    protected Predicate<String> getRandomFieldsExcludeFilter() {
+        // The structure of the response is such that unknown fields inside acknowledge cannot be supported since they
+        // are treated as messages from new services
+        return p -> p.startsWith("acknowledge");
+    }
+
+    @Override
+    protected PostStartBasicResponse createTestInstance() {
+        PostStartBasicResponse.Status status = randomFrom(PostStartBasicResponse.Status.values());
+        String acknowledgeMessage = null;
+        Map<String, String[]> ackMessages = Collections.emptyMap();
+        if (status != PostStartBasicResponse.Status.GENERATED_BASIC) {
+            acknowledgeMessage = randomAlphaOfLength(10);
+            ackMessages = randomAckMessages();
+        }
+        final PostStartBasicResponse postStartBasicResponse = new PostStartBasicResponse(status, ackMessages, acknowledgeMessage);
+        logger.info("{}", Strings.toString(postStartBasicResponse));
+        return postStartBasicResponse;
+    }
+
+    private static Map<String, String[]> randomAckMessages() {
+        int nFeatures = randomIntBetween(1, 5);
+
+        Map<String, String[]> ackMessages = new HashMap<>();
+
+        for (int i = 0; i < nFeatures; i++) {
+            String feature = randomAlphaOfLengthBetween(9, 15);
+            int nMessages = randomIntBetween(1, 5);
+            String[] messages = new String[nMessages];
+            for (int j = 0; j < nMessages; j++) {
+                messages[j] = randomAlphaOfLengthBetween(10, 30);
+            }
+            ackMessages.put(feature, messages);
+        }
+
+        return ackMessages;
+    }
+}

+ 20 - 2
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/migration/IndexUpgradeInfoResponseTests.java

@@ -6,18 +6,36 @@
 package org.elasticsearch.protocol.xpack.migration;
 
 import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.test.AbstractStreamableXContentTestCase;
+import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase;
 
+import java.io.IOException;
+import java.util.AbstractMap;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.stream.Collectors;
+
+public class IndexUpgradeInfoResponseTests extends
+        AbstractHlrcStreamableXContentTestCase<IndexUpgradeInfoResponse, org.elasticsearch.client.migration.IndexUpgradeInfoResponse> {
 
-public class IndexUpgradeInfoResponseTests extends AbstractStreamableXContentTestCase<IndexUpgradeInfoResponse> {
     @Override
     protected IndexUpgradeInfoResponse doParseInstance(XContentParser parser) {
         return IndexUpgradeInfoResponse.fromXContent(parser);
     }
 
+    @Override
+    public org.elasticsearch.client.migration.IndexUpgradeInfoResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return org.elasticsearch.client.migration.IndexUpgradeInfoResponse.fromXContent(parser);
+    }
+
+    @Override
+    public IndexUpgradeInfoResponse convertHlrcToInternal(org.elasticsearch.client.migration.IndexUpgradeInfoResponse instance) {
+        final Map<String, org.elasticsearch.client.migration.UpgradeActionRequired> actions = instance.getActions();
+        return new IndexUpgradeInfoResponse(actions.entrySet().stream().map(
+            e -> new AbstractMap.SimpleEntry<>(e.getKey(), UpgradeActionRequired.valueOf(e.getValue().name()))
+        ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
+    }
+
     @Override
     protected IndexUpgradeInfoResponse createBlankInstance() {
         return new IndexUpgradeInfoResponse();

+ 13 - 2
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/DeleteWatchResponseTests.java

@@ -6,11 +6,12 @@
 package org.elasticsearch.protocol.xpack.watcher;
 
 import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.test.AbstractXContentTestCase;
+import org.elasticsearch.protocol.AbstractHlrcXContentTestCase;
 
 import java.io.IOException;
 
-public class DeleteWatchResponseTests extends AbstractXContentTestCase<DeleteWatchResponse> {
+public class DeleteWatchResponseTests extends
+        AbstractHlrcXContentTestCase<DeleteWatchResponse, org.elasticsearch.client.watcher.DeleteWatchResponse> {
 
     @Override
     protected DeleteWatchResponse createTestInstance() {
@@ -25,6 +26,16 @@ public class DeleteWatchResponseTests extends AbstractXContentTestCase<DeleteWat
         return DeleteWatchResponse.fromXContent(parser);
     }
 
+    @Override
+    public org.elasticsearch.client.watcher.DeleteWatchResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return org.elasticsearch.client.watcher.DeleteWatchResponse.fromXContent(parser);
+    }
+
+    @Override
+    public DeleteWatchResponse convertHlrcToInternal(org.elasticsearch.client.watcher.DeleteWatchResponse instance) {
+        return new DeleteWatchResponse(instance.getId(), instance.getVersion(), instance.isFound());
+    }
+
     @Override
     protected boolean supportsUnknownFields() {
         return false;

+ 13 - 2
x-pack/plugin/core/src/test/java/org/elasticsearch/protocol/xpack/watcher/PutWatchResponseTests.java

@@ -6,11 +6,12 @@
 package org.elasticsearch.protocol.xpack.watcher;
 
 import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.test.AbstractXContentTestCase;
+import org.elasticsearch.protocol.AbstractHlrcXContentTestCase;
 
 import java.io.IOException;
 
-public class PutWatchResponseTests extends AbstractXContentTestCase<PutWatchResponse> {
+public class PutWatchResponseTests extends
+        AbstractHlrcXContentTestCase<PutWatchResponse, org.elasticsearch.client.watcher.PutWatchResponse> {
 
     @Override
     protected PutWatchResponse createTestInstance() {
@@ -25,6 +26,16 @@ public class PutWatchResponseTests extends AbstractXContentTestCase<PutWatchResp
         return PutWatchResponse.fromXContent(parser);
     }
 
+    @Override
+    public org.elasticsearch.client.watcher.PutWatchResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return org.elasticsearch.client.watcher.PutWatchResponse.fromXContent(parser);
+    }
+
+    @Override
+    public PutWatchResponse convertHlrcToInternal(org.elasticsearch.client.watcher.PutWatchResponse instance) {
+        return new PutWatchResponse(instance.getId(), instance.getVersion(), instance.isCreated());
+    }
+
     @Override
     protected boolean supportsUnknownFields() {
         return false;