diff --git a/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.Eql.cs b/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.Eql.cs index fbad22711fc..638c6b217c9 100644 --- a/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.Eql.cs +++ b/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.Eql.cs @@ -44,12 +44,12 @@ namespace Elasticsearch.Net.Specification.EqlApi { ///Request options for Delete https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html - public class DeleteRequestParameters : RequestParameters + public class EqlDeleteRequestParameters : RequestParameters { } ///Request options for Get https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html - public class GetRequestParameters : RequestParameters + public class EqlGetRequestParameters : RequestParameters { ///Update the time interval in which the results (partial or final) for this search will be available public TimeSpan KeepAlive @@ -66,8 +66,8 @@ public TimeSpan WaitForCompletionTimeout } } - ///Request options for GetStatus https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html - public class GetStatusRequestParameters : RequestParameters + ///Request options for SearchStatus https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + public class EqlSearchStatusRequestParameters : RequestParameters { } diff --git a/src/Elasticsearch.Net/ElasticLowLevelClient.Eql.cs b/src/Elasticsearch.Net/ElasticLowLevelClient.Eql.cs index 124f1baeed8..8a9a16b5f88 100644 --- a/src/Elasticsearch.Net/ElasticLowLevelClient.Eql.cs +++ b/src/Elasticsearch.Net/ElasticLowLevelClient.Eql.cs @@ -65,35 +65,35 @@ internal LowLevelEqlNamespace(ElasticLowLevelClient client): base(client) ///DELETE on /_eql/search/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse Delete(string id, DeleteRequestParameters requestParameters = null) + public TResponse Delete(string id, EqlDeleteRequestParameters requestParameters = null) where TResponse : class, ITransportResponse, new() => DoRequest(DELETE, Url($"_eql/search/{id:id}"), null, RequestParams(requestParameters)); ///DELETE on /_eql/search/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. [MapsApi("eql.delete", "id")] - public Task DeleteAsync(string id, DeleteRequestParameters requestParameters = null, CancellationToken ctx = default) + public Task DeleteAsync(string id, EqlDeleteRequestParameters requestParameters = null, CancellationToken ctx = default) where TResponse : class, ITransportResponse, new() => DoRequestAsync(DELETE, Url($"_eql/search/{id:id}"), ctx, null, RequestParams(requestParameters)); ///GET on /_eql/search/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse Get(string id, GetRequestParameters requestParameters = null) + public TResponse Get(string id, EqlGetRequestParameters requestParameters = null) where TResponse : class, ITransportResponse, new() => DoRequest(GET, Url($"_eql/search/{id:id}"), null, RequestParams(requestParameters)); ///GET on /_eql/search/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. [MapsApi("eql.get", "id")] - public Task GetAsync(string id, GetRequestParameters requestParameters = null, CancellationToken ctx = default) + public Task GetAsync(string id, EqlGetRequestParameters requestParameters = null, CancellationToken ctx = default) where TResponse : class, ITransportResponse, new() => DoRequestAsync(GET, Url($"_eql/search/{id:id}"), ctx, null, RequestParams(requestParameters)); ///GET on /_eql/search/status/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse GetStatus(string id, GetStatusRequestParameters requestParameters = null) + public TResponse SearchStatus(string id, EqlSearchStatusRequestParameters requestParameters = null) where TResponse : class, ITransportResponse, new() => DoRequest(GET, Url($"_eql/search/status/{id:id}"), null, RequestParams(requestParameters)); ///GET on /_eql/search/status/{id} https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html ///The async search ID ///Request specific configuration such as querystring parameters & request specific connection settings. [MapsApi("eql.get_status", "id")] - public Task GetStatusAsync(string id, GetStatusRequestParameters requestParameters = null, CancellationToken ctx = default) + public Task SearchStatusAsync(string id, EqlSearchStatusRequestParameters requestParameters = null, CancellationToken ctx = default) where TResponse : class, ITransportResponse, new() => DoRequestAsync(GET, Url($"_eql/search/status/{id:id}"), ctx, null, RequestParams(requestParameters)); ///POST on /{index}/_eql/search https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html ///A comma-separated list of index names to search; use the special string `_all` or Indices.All to perform the operation on all indices diff --git a/src/Nest/Descriptors.Eql.cs b/src/Nest/Descriptors.Eql.cs index 0a15c620deb..9791850f570 100644 --- a/src/Nest/Descriptors.Eql.cs +++ b/src/Nest/Descriptors.Eql.cs @@ -49,6 +49,79 @@ // ReSharper disable RedundantNameQualifier namespace Nest { + ///Descriptor for Delete https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + public partial class EqlDeleteDescriptor : RequestDescriptorBase, IEqlDeleteRequest + { + internal override ApiUrls ApiUrls => ApiUrlsLookups.EqlDelete; + protected override HttpMethod HttpMethod => HttpMethod.DELETE; + protected override bool SupportsBody => false; + ////_eql/search/{id} + ///this parameter is required + public EqlDeleteDescriptor(Id id): base(r => r.Required("id", id)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected EqlDeleteDescriptor(): base() + { + } + + // values part of the url path + Id IEqlDeleteRequest.Id => Self.RouteValues.Get("id"); + // Request parameters + } + + ///Descriptor for Get https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + public partial class EqlGetDescriptor : RequestDescriptorBase, IEqlGetRequest + { + internal override ApiUrls ApiUrls => ApiUrlsLookups.EqlGet; + protected override HttpMethod HttpMethod => HttpMethod.GET; + protected override bool SupportsBody => false; + ////_eql/search/{id} + ///this parameter is required + public EqlGetDescriptor(Id id): base(r => r.Required("id", id)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected EqlGetDescriptor(): base() + { + } + + // values part of the url path + Id IEqlGetRequest.Id => Self.RouteValues.Get("id"); + // Request parameters + ///Update the time interval in which the results (partial or final) for this search will be available + public EqlGetDescriptor KeepAlive(Time keepalive) => Qs("keep_alive", keepalive); + ///Specify the time that the request should block waiting for the final response + public EqlGetDescriptor WaitForCompletionTimeout(Time waitforcompletiontimeout) => Qs("wait_for_completion_timeout", waitforcompletiontimeout); + } + + ///Descriptor for SearchStatus https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + public partial class EqlSearchStatusDescriptor : RequestDescriptorBase, IEqlSearchStatusRequest + { + internal override ApiUrls ApiUrls => ApiUrlsLookups.EqlSearchStatus; + protected override HttpMethod HttpMethod => HttpMethod.GET; + protected override bool SupportsBody => false; + ////_eql/search/status/{id} + ///this parameter is required + public EqlSearchStatusDescriptor(Id id): base(r => r.Required("id", id)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected EqlSearchStatusDescriptor(): base() + { + } + + // values part of the url path + Id IEqlSearchStatusRequest.Id => Self.RouteValues.Get("id"); + // Request parameters + } + ///Descriptor for Search https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html public partial class EqlSearchDescriptor : RequestDescriptorBase, EqlSearchRequestParameters, IEqlSearchRequest>, IEqlSearchRequest { diff --git a/src/Nest/ElasticClient.Eql.cs b/src/Nest/ElasticClient.Eql.cs index 23c5b658e65..e1c18d58174 100644 --- a/src/Nest/ElasticClient.Eql.cs +++ b/src/Nest/ElasticClient.Eql.cs @@ -54,6 +54,82 @@ internal EqlNamespace(ElasticClient client): base(client) { } + /// + /// DELETE request to the eql.delete API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public EqlDeleteResponse Delete(Id id, Func selector = null) => Delete(selector.InvokeOrDefault(new EqlDeleteDescriptor(id: id))); + /// + /// DELETE request to the eql.delete API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public Task DeleteAsync(Id id, Func selector = null, CancellationToken ct = default) => DeleteAsync(selector.InvokeOrDefault(new EqlDeleteDescriptor(id: id)), ct); + /// + /// DELETE request to the eql.delete API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public EqlDeleteResponse Delete(IEqlDeleteRequest request) => DoRequest(request, request.RequestParameters); + /// + /// DELETE request to the eql.delete API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public Task DeleteAsync(IEqlDeleteRequest request, CancellationToken ct = default) => DoRequestAsync(request, request.RequestParameters, ct); + /// + /// GET request to the eql.get API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public EqlGetResponse Get(Id id, Func selector = null) + where TDocument : class => Get(selector.InvokeOrDefault(new EqlGetDescriptor(id: id))); + /// + /// GET request to the eql.get API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public Task> GetAsync(Id id, Func selector = null, CancellationToken ct = default) + where TDocument : class => GetAsync(selector.InvokeOrDefault(new EqlGetDescriptor(id: id)), ct); + /// + /// GET request to the eql.get API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public EqlGetResponse Get(IEqlGetRequest request) + where TDocument : class => DoRequest>(request, request.RequestParameters); + /// + /// GET request to the eql.get API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public Task> GetAsync(IEqlGetRequest request, CancellationToken ct = default) + where TDocument : class => DoRequestAsync>(request, request.RequestParameters, ct); + /// + /// GET request to the eql.get_status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public EqlSearchStatusResponse SearchStatus(Id id, Func selector = null) => SearchStatus(selector.InvokeOrDefault(new EqlSearchStatusDescriptor(id: id))); + /// + /// GET request to the eql.get_status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public Task SearchStatusAsync(Id id, Func selector = null, CancellationToken ct = default) => SearchStatusAsync(selector.InvokeOrDefault(new EqlSearchStatusDescriptor(id: id)), ct); + /// + /// GET request to the eql.get_status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public EqlSearchStatusResponse SearchStatus(IEqlSearchStatusRequest request) => DoRequest(request, request.RequestParameters); + /// + /// GET request to the eql.get_status API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + /// + public Task SearchStatusAsync(IEqlSearchStatusRequest request, CancellationToken ct = default) => DoRequestAsync(request, request.RequestParameters, ct); /// /// POST request to the eql.search API, read more about this API online: /// diff --git a/src/Nest/Requests.Eql.cs b/src/Nest/Requests.Eql.cs index 1143f1dc1b6..2e446b18c85 100644 --- a/src/Nest/Requests.Eql.cs +++ b/src/Nest/Requests.Eql.cs @@ -50,6 +50,124 @@ // ReSharper disable RedundantNameQualifier namespace Nest { + [InterfaceDataContract] + public partial interface IEqlDeleteRequest : IRequest + { + [IgnoreDataMember] + Id Id + { + get; + } + } + + ///Request for Delete https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + public partial class EqlDeleteRequest : PlainRequestBase, IEqlDeleteRequest + { + protected IEqlDeleteRequest Self => this; + internal override ApiUrls ApiUrls => ApiUrlsLookups.EqlDelete; + protected override HttpMethod HttpMethod => HttpMethod.DELETE; + protected override bool SupportsBody => false; + ////_eql/search/{id} + ///this parameter is required + public EqlDeleteRequest(Id id): base(r => r.Required("id", id)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected EqlDeleteRequest(): base() + { + } + + // values part of the url path + [IgnoreDataMember] + Id IEqlDeleteRequest.Id => Self.RouteValues.Get("id"); + // Request parameters + } + + [InterfaceDataContract] + public partial interface IEqlGetRequest : IRequest + { + [IgnoreDataMember] + Id Id + { + get; + } + } + + ///Request for Get https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html + public partial class EqlGetRequest : PlainRequestBase, IEqlGetRequest + { + protected IEqlGetRequest Self => this; + internal override ApiUrls ApiUrls => ApiUrlsLookups.EqlGet; + protected override HttpMethod HttpMethod => HttpMethod.GET; + protected override bool SupportsBody => false; + ////_eql/search/{id} + ///this parameter is required + public EqlGetRequest(Id id): base(r => r.Required("id", id)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected EqlGetRequest(): base() + { + } + + // values part of the url path + [IgnoreDataMember] + Id IEqlGetRequest.Id => Self.RouteValues.Get("id"); + // Request parameters + ///Update the time interval in which the results (partial or final) for this search will be available + public Time KeepAlive + { + get => Q [DataMember(Name = "id")] - public Id Id { get; internal set; } + public string Id { get; internal set; } /// /// If true, the response does not contain complete search results. /// [DataMember(Name = "is_partial")] - public bool? IsPartial { get; internal set; } + public bool IsPartial { get; internal set; } /// /// If true, the search request is still executing. /// [DataMember(Name = "is_running")] - public bool? IsRunning { get; internal set; } + public bool IsRunning { get; internal set; } /// /// Milliseconds it took Elasticsearch to execute the request. /// [DataMember(Name = "took")] - public int Took { get; internal set; } + public long Took { get; internal set; } /// /// If true, the request timed out before completion. /// [DataMember(Name = "timed_out")] - public bool? TimedOut { get; internal set; } + public bool TimedOut { get; internal set; } /// /// The total number of hits. diff --git a/src/Nest/XPack/Eql/Get/EqlGetRequest.cs b/src/Nest/XPack/Eql/Get/EqlGetRequest.cs new file mode 100644 index 00000000000..d19ff4a1fce --- /dev/null +++ b/src/Nest/XPack/Eql/Get/EqlGetRequest.cs @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +namespace Nest +{ + [MapsApi("eql.get.json")] + [ReadAs(typeof(EqlGetRequest))] + public partial interface IEqlGetRequest { } + + public partial class EqlGetRequest { } + + public partial class EqlGetDescriptor { } +} diff --git a/src/Nest/XPack/Eql/Get/EqlGetResponse.cs b/src/Nest/XPack/Eql/Get/EqlGetResponse.cs new file mode 100644 index 00000000000..ae5cf02db24 --- /dev/null +++ b/src/Nest/XPack/Eql/Get/EqlGetResponse.cs @@ -0,0 +1,28 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +namespace Nest +{ + /// + /// A response to an EQL get async search request. + /// + public class EqlGetResponse : EqlSearchResponse where TDocument : class + { + } +} diff --git a/src/Nest/XPack/Eql/Status/EqlSearchStatusRequest.cs b/src/Nest/XPack/Eql/Status/EqlSearchStatusRequest.cs new file mode 100644 index 00000000000..e59f685c738 --- /dev/null +++ b/src/Nest/XPack/Eql/Status/EqlSearchStatusRequest.cs @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +namespace Nest +{ + [MapsApi("eql.get_status.json")] + [ReadAs(typeof(EqlSearchStatusRequest))] + public partial interface IEqlSearchStatusRequest { } + + public partial class EqlSearchStatusRequest { } + + public partial class EqlSearchStatusDescriptor { } +} diff --git a/src/Nest/XPack/Eql/Status/EqlSearchStatusResponse.cs b/src/Nest/XPack/Eql/Status/EqlSearchStatusResponse.cs new file mode 100644 index 00000000000..a8070e42d2e --- /dev/null +++ b/src/Nest/XPack/Eql/Status/EqlSearchStatusResponse.cs @@ -0,0 +1,65 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +using System.Runtime.Serialization; + +namespace Nest +{ + /// + /// A response to an EQL get status request. + /// + public class EqlSearchStatusResponse : ResponseBase + { + /// + /// For a completed search shows the http status code of the completed search. + /// + [DataMember(Name = "completion_status")] + public int CompletionStatus { get; internal set; } + + /// + /// For a running search shows a timestamp when the eql search started, in milliseconds since the Unix epoch. + /// + [DataMember(Name = "expiration_time_in_millis")] + public long ExpirationTimeInMillis { get; internal set; } + + /// + /// Identifier for the search. + /// + [DataMember(Name = "id")] + public string Id { get; internal set; } + + /// + /// If true, the response does not contain complete search results. + /// + [DataMember(Name = "is_partial")] + public bool IsPartial { get; internal set; } + + /// + /// If true, the search request is still executing. If false, the search is completed. + /// + [DataMember(Name = "is_running")] + public bool IsRunning { get; internal set; } + + /// + /// For a running search shows a timestamp when the eql search started, in milliseconds since the Unix epoch. + /// + [DataMember(Name = "start_time_in_millis")] + public long StartTimeInMillis { get; internal set; } + } +} diff --git a/src/Nest/_Generated/ApiUrlsLookup.generated.cs b/src/Nest/_Generated/ApiUrlsLookup.generated.cs index 01a79ff1825..20f1b660a0d 100644 --- a/src/Nest/_Generated/ApiUrlsLookup.generated.cs +++ b/src/Nest/_Generated/ApiUrlsLookup.generated.cs @@ -106,6 +106,9 @@ internal static class ApiUrlsLookups internal static ApiUrls EnrichGetPolicy = new ApiUrls(new[]{"_enrich/policy/{name}", "_enrich/policy"}); internal static ApiUrls EnrichPutPolicy = new ApiUrls(new[]{"_enrich/policy/{name}"}); internal static ApiUrls EnrichStats = new ApiUrls(new[]{"_enrich/_stats"}); + internal static ApiUrls EqlDelete = new ApiUrls(new[]{"_eql/search/{id}"}); + internal static ApiUrls EqlGet = new ApiUrls(new[]{"_eql/search/{id}"}); + internal static ApiUrls EqlSearchStatus = new ApiUrls(new[]{"_eql/search/status/{id}"}); internal static ApiUrls EqlSearch = new ApiUrls(new[]{"{index}/_eql/search"}); internal static ApiUrls NoNamespaceDocumentExists = new ApiUrls(new[]{"{index}/_doc/{id}"}); internal static ApiUrls NoNamespaceSourceExists = new ApiUrls(new[]{"{index}/_source/{id}"}); diff --git a/tests/Tests/XPack/Eql/Delete/EqlDeleteUrlTests.cs b/tests/Tests/XPack/Eql/Delete/EqlDeleteUrlTests.cs new file mode 100644 index 00000000000..8e2a5b851f3 --- /dev/null +++ b/tests/Tests/XPack/Eql/Delete/EqlDeleteUrlTests.cs @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +using System.Threading.Tasks; +using Elastic.Elasticsearch.Xunit.XunitPlumbing; +using Nest; +using Tests.Framework.EndpointTests; +using static Tests.Framework.EndpointTests.UrlTester; + +namespace Tests.XPack.Eql.Delete +{ + public class EqlDeleteUrlTests : UrlTestsBase + { + [U] public override async Task Urls() => await DELETE("/_eql/search/search_id") + .Fluent(c => c.Eql.Delete("search_id", f => f)) + .Request(c => c.Eql.Delete(new EqlDeleteRequest("search_id"))) + .FluentAsync(c => c.Eql.DeleteAsync("search_id", f => f)) + .RequestAsync(c => c.Eql.DeleteAsync(new EqlDeleteRequest("search_id"))); + } +} diff --git a/tests/Tests/XPack/Eql/EqlSearchApiCoordinatedTests.cs b/tests/Tests/XPack/Eql/EqlSearchApiCoordinatedTests.cs new file mode 100644 index 00000000000..dff546e3afc --- /dev/null +++ b/tests/Tests/XPack/Eql/EqlSearchApiCoordinatedTests.cs @@ -0,0 +1,155 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +using System.Linq; +using System.Threading.Tasks; +using Elastic.Elasticsearch.Xunit.XunitPlumbing; +using FluentAssertions; +using Nest; +using Tests.Core.Extensions; +using Tests.Core.ManagedElasticsearch.Clusters; +using Tests.Domain; +using Tests.Framework.EndpointTests; +using Tests.Framework.EndpointTests.TestState; + +namespace Tests.XPack.Eql +{ + [SkipVersion("<7.11.0", "GA in 7.11.0")] + public class EqlSearchApiCoordinatedTests : CoordinatedIntegrationTestBase + { + private const string SubmitStep = nameof(SubmitStep); + private const string StatusStep = nameof(StatusStep); + private const string GetStep = nameof(GetStep); + private const string WaitStep = nameof(WaitStep); + private const string DeleteStep = nameof(DeleteStep); + + public EqlSearchApiCoordinatedTests(TimeSeriesCluster cluster, EndpointUsage usage) : base(new CoordinatedUsage(cluster, usage, testOnlyOne: true) + { + {SubmitStep, u => + u.Calls, EqlSearchRequest, IEqlSearchRequest, EqlSearchResponse>( + v => new EqlSearchRequest + { + Query = "any where true", + KeepOnCompletion = true, + TimestampField = Infer.Field(f => f.Timestamp), + WaitForCompletionTimeout = "1nanos" + }, + (v, d) => d + .Query("any where true") + .KeepOnCompletion() + .TimestampField(Infer.Field(f => f.Timestamp)) + .WaitForCompletionTimeout("1nanos"), + (v, c, f) => c.Eql.Search(f), + (v, c, f) => c.Eql.SearchAsync(f), + (v, c, r) => c.Eql.Search(r), + (v, c, r) => c.Eql.SearchAsync(r), + onResponse: (r, values) => values.ExtendedValue("id", r.Id) + ) + }, + {StatusStep, u => + u.Calls( + v => new EqlSearchStatusRequest(v), + (v, d) => d, + (v, c, f) => c.Eql.SearchStatus(v, f), + (v, c, f) => c.Eql.SearchStatusAsync(v, f), + (v, c, r) => c.Eql.SearchStatus(r), + (v, c, r) => c.Eql.SearchStatusAsync(r), + uniqueValueSelector: values => values.ExtendedValue("id") + ) + }, + {WaitStep, u => u.Call(async (v, c) => + { + // wait for the search to complete + var complete = false; + var count = 0; + + while (!complete && count++ < 10) + { + await Task.Delay(100); + var status = await c.Eql.SearchStatusAsync(u.Usage.CallUniqueValues.ExtendedValue("id")); + complete = !status.IsRunning; + } + })}, // allows the search to complete + {GetStep, u => + u.Calls>( + v => new EqlGetRequest(v), + (v, d) => d, + (v, c, f) => c.Eql.Get(v, f), + (v, c, f) => c.Eql.GetAsync(v, f), + (v, c, r) => c.Eql.Get(r), + (v, c, r) => c.Eql.GetAsync(r), + uniqueValueSelector: values => values.ExtendedValue("id") + ) + }, + {DeleteStep, u => + u.Calls( + v => new EqlDeleteRequest(v), + (v, d) => d, + (v, c, f) => c.Eql.Delete(v, f), + (v, c, f) => c.Eql.DeleteAsync(v, f), + (v, c, r) => c.Eql.Delete(r), + (v, c, r) => c.Eql.DeleteAsync(r), + uniqueValueSelector: values => values.ExtendedValue("id") + ) + } + }) { } + + [I] public async Task EqlSearchResponse() => await Assert>(SubmitStep, r => + { + r.ShouldBeValid(); + r.Id.Should().NotBeNullOrEmpty(); + r.IsPartial.Should().BeTrue(); + r.IsRunning.Should().BeTrue(); + r.TimedOut.Should().BeFalse(); + }); + + [I] public async Task EqlSearchStatusResponse() => await Assert(StatusStep, r => + { + r.ShouldBeValid(); + r.Id.Should().NotBeNullOrEmpty(); + r.IsPartial.Should().BeTrue(); + r.IsRunning.Should().BeTrue(); + r.ExpirationTimeInMillis.Should().BeGreaterThan(0); + r.StartTimeInMillis.Should().BeGreaterThan(0); + }); + + [I] public async Task EqlGetResponse() => await Assert>(GetStep, r => + { + r.ShouldBeValid(); + r.IsPartial.Should().BeFalse(); + r.IsRunning.Should().BeFalse(); + r.Took.Should().BeGreaterOrEqualTo(0); + r.TimedOut.Should().BeFalse(); + r.Events.Count.Should().Be(10); + r.EqlHitsMetadata.Total.Value.Should().Be(10); + r.Total.Should().Be(10); + + var firstEvent = r.Events.First(); + firstEvent.Index.Should().StartWith("customlogs-"); + firstEvent.Id.Should().NotBeNullOrEmpty(); + firstEvent.Source.Event.Category.Should().BeOneOf(Log.EventCategories); + }); + + [I] public async Task EqlDeleteResponse() => await Assert(DeleteStep, r => + { + r.ShouldBeValid(); + r.Acknowledged.Should().BeTrue(); + }); + } +} diff --git a/tests/Tests/XPack/Eql/Get/EqlGetUrlTests.cs b/tests/Tests/XPack/Eql/Get/EqlGetUrlTests.cs new file mode 100644 index 00000000000..c9cc4b0d6ef --- /dev/null +++ b/tests/Tests/XPack/Eql/Get/EqlGetUrlTests.cs @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +using System.Threading.Tasks; +using Elastic.Elasticsearch.Xunit.XunitPlumbing; +using Nest; +using Tests.Domain; +using Tests.Framework.EndpointTests; +using static Tests.Framework.EndpointTests.UrlTester; + +namespace Tests.XPack.Eql.Get +{ + public class EqlGetUrlTests : UrlTestsBase + { + [U] public override async Task Urls() => await GET("/_eql/search/search_id") + .Fluent(c => c.Eql.Get("search_id", f => f)) + .Request(c => c.Eql.Get(new EqlGetRequest("search_id"))) + .FluentAsync(c => c.Eql.GetAsync("search_id", f => f)) + .RequestAsync(c => c.Eql.GetAsync(new EqlGetRequest("search_id"))); + } +} diff --git a/tests/Tests/XPack/Eql/Status/EqlSearchStatusUrlTests.cs b/tests/Tests/XPack/Eql/Status/EqlSearchStatusUrlTests.cs new file mode 100644 index 00000000000..ea4d46b8a49 --- /dev/null +++ b/tests/Tests/XPack/Eql/Status/EqlSearchStatusUrlTests.cs @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. 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. + */ + +using System.Threading.Tasks; +using Elastic.Elasticsearch.Xunit.XunitPlumbing; +using Nest; +using Tests.Framework.EndpointTests; +using static Tests.Framework.EndpointTests.UrlTester; + +namespace Tests.XPack.Eql.Status +{ + public class EqlSearchStatusUrlTests : UrlTestsBase + { + [U] public override async Task Urls() => await GET("/_eql/search/status/search_id") + .Fluent(c => c.Eql.SearchStatus("search_id", f => f)) + .Request(c => c.Eql.SearchStatus(new EqlSearchStatusRequest("search_id"))) + .FluentAsync(c => c.Eql.SearchStatusAsync("search_id", f => f)) + .RequestAsync(c => c.Eql.SearchStatusAsync(new EqlSearchStatusRequest("search_id"))); + } +}