Skip to content

Commit

Permalink
Add NEST support for Query Watcher API (#5680)
Browse files Browse the repository at this point in the history
* Add request and response

* Update request

* Generate code

* Update request properties

* Update request and response

* Add tests
  • Loading branch information
stevejgordon authored and github-actions[bot] committed May 5, 2021
1 parent 7446245 commit a308b6f
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/Nest/Descriptors.Watcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ protected PutWatchDescriptor(): base()
public PutWatchDescriptor Version(long? version) => Qs("version", version);
}

///<summary>Descriptor for QueryWatches <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</para></summary>
public partial class QueryWatchesDescriptor : RequestDescriptorBase<QueryWatchesDescriptor, QueryWatchesRequestParameters, IQueryWatchesRequest>, IQueryWatchesRequest
{
internal override ApiUrls ApiUrls => ApiUrlsLookups.WatcherQueryWatches;
// values part of the url path
// Request parameters
}

///<summary>Descriptor for Start <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html</para></summary>
public partial class StartWatcherDescriptor : RequestDescriptorBase<StartWatcherDescriptor, StartWatcherRequestParameters, IStartWatcherRequest>, IStartWatcherRequest
{
Expand Down
24 changes: 24 additions & 0 deletions src/Nest/ElasticClient.Watcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,30 @@ internal WatcherNamespace(ElasticClient client): base(client)
/// </summary>
public Task<PutWatchResponse> PutAsync(IPutWatchRequest request, CancellationToken ct = default) => DoRequestAsync<IPutWatchRequest, PutWatchResponse>(request, request.RequestParameters, ct);
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
/// </summary>
public QueryWatchesResponse QueryWatches(Func<QueryWatchesDescriptor, IQueryWatchesRequest> selector = null) => QueryWatches(selector.InvokeOrDefault(new QueryWatchesDescriptor()));
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
/// </summary>
public Task<QueryWatchesResponse> QueryWatchesAsync(Func<QueryWatchesDescriptor, IQueryWatchesRequest> selector = null, CancellationToken ct = default) => QueryWatchesAsync(selector.InvokeOrDefault(new QueryWatchesDescriptor()), ct);
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
/// </summary>
public QueryWatchesResponse QueryWatches(IQueryWatchesRequest request) => DoRequest<IQueryWatchesRequest, QueryWatchesResponse>(request, request.RequestParameters);
/// <summary>
/// <c>POST</c> request to the <c>watcher.query_watches</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</a>
/// </summary>
public Task<QueryWatchesResponse> QueryWatchesAsync(IQueryWatchesRequest request, CancellationToken ct = default) => DoRequestAsync<IQueryWatchesRequest, QueryWatchesResponse>(request, request.RequestParameters, ct);
/// <summary>
/// <c>POST</c> request to the <c>watcher.start</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html</a>
Expand Down
14 changes: 14 additions & 0 deletions src/Nest/Requests.Watcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,20 @@ public long? Version
}
}

[InterfaceDataContract]
public partial interface IQueryWatchesRequest : IRequest<QueryWatchesRequestParameters>
{
}

///<summary>Request for QueryWatches <para>https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html</para></summary>
public partial class QueryWatchesRequest : PlainRequestBase<QueryWatchesRequestParameters>, IQueryWatchesRequest
{
protected IQueryWatchesRequest Self => this;
internal override ApiUrls ApiUrls => ApiUrlsLookups.WatcherQueryWatches;
// values part of the url path
// Request parameters
}

[InterfaceDataContract]
public partial interface IStartWatcherRequest : IRequest<StartWatcherRequestParameters>
{
Expand Down
98 changes: 98 additions & 0 deletions src/Nest/XPack/Watcher/Query/QueryWatchesRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace Nest
{
[MapsApi("watcher.query_watches.json")]
[ReadAs(typeof(QueryWatchesRequest))]
public partial interface IQueryWatchesRequest
{
/// <summary>
/// The offset from the first result to fetch. Needs to be non-negative.
/// </summary>
[DataMember(Name = "from")]
int? From { get; set; }

/// <summary>
/// Optional, query filter watches to be returned.
/// </summary>
[DataMember(Name = "query")]
QueryContainer Query { get; set; }

/// <summary>
/// Sort values that can be used to start returning results "after" any document in the result list.
/// </summary>
[DataMember(Name = "search_after")]
IList<object> SearchAfter { get; set; }

/// <summary>
/// The number of hits to return. Defaults to 10.
/// </summary>
[DataMember(Name = "size")]
int? Size { get; set; }

/// <summary>
/// Specifies how to sort the search hits.
/// </summary>
[DataMember(Name = "sort")]
IList<ISort> Sort { get; set; }
}

/// <inheritdoc cref="IQueryWatchesRequest" />
public partial class QueryWatchesRequest
{
/// <inheritdoc />
public int? From { get; set; }

/// <inheritdoc />
public QueryContainer Query { get; set; }

/// <inheritdoc />
public IList<object> SearchAfter { get; set; }

/// <inheritdoc />
public int? Size { get; set; }

/// <inheritdoc />
public IList<ISort> Sort { get; set; }
}

/// <inheritdoc cref="IQueryWatchesRequest" />
public partial class QueryWatchesDescriptor
{
int? IQueryWatchesRequest.From { get; set; }
QueryContainer IQueryWatchesRequest.Query { get; set; }
IList<object> IQueryWatchesRequest.SearchAfter { get; set; }
int? IQueryWatchesRequest.Size { get; set; }
IList<ISort> IQueryWatchesRequest.Sort { get; set; }

/// <inheritdoc cref="IQueryWatchesRequest.From" />
public QueryWatchesDescriptor From(int? from) => Assign(from, (a, v) => a.From = v);

/// <inheritdoc cref="IQueryWatchesRequest.Query" />
public QueryWatchesDescriptor Query(Func<QueryContainerDescriptor<Watch>, QueryContainer> query) =>
Assign(query, (a, v) => a.Query = v?.Invoke(new QueryContainerDescriptor<Watch>()));

/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
public QueryWatchesDescriptor SearchAfter(IEnumerable<object> searchAfter) =>
Assign(searchAfter, (a, v) => a.SearchAfter = v?.ToListOrNullIfEmpty());

/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
public QueryWatchesDescriptor SearchAfter(IList<object> searchAfter) => Assign(searchAfter, (a, v) => a.SearchAfter = v);

/// <inheritdoc cref="IQueryWatchesRequest.SearchAfter" />
public QueryWatchesDescriptor SearchAfter(params object[] searchAfter) => Assign(searchAfter, (a, v) => a.SearchAfter = v);

/// <inheritdoc cref="IQueryWatchesRequest.Size" />
public QueryWatchesDescriptor Size(int? size) => Assign(size, (a, v) => a.Size = v);

/// <inheritdoc cref="IQueryWatchesRequest.Sort" />
public QueryWatchesDescriptor Sort(Func<SortDescriptor<Watch>, IPromise<IList<ISort>>> selector) =>
Assign(selector, (a, v) => a.Sort = v?.Invoke(new SortDescriptor<Watch>())?.Value);
}
}
37 changes: 37 additions & 0 deletions src/Nest/XPack/Watcher/Query/QueryWatchesResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Collections.Generic;
using System.Runtime.Serialization;

namespace Nest
{
public class QueryWatchesResponse : ResponseBase
{
[DataMember(Name = "count")]
public int Count { get; internal set; }

[DataMember(Name = "watches")]
public IReadOnlyCollection<WatchQueryResult> Watches { get; internal set; }
}

[DataContract]
public class WatchQueryResult
{
[DataMember(Name = "_id")]
public string Id { get; set; }

[DataMember(Name = "_primary_term")]
public int PrimaryTerm { get; set; }

[DataMember(Name = "_seq_no")]
public int SequenceNumber { get; set; }

[DataMember(Name = "status")]
public WatchStatus Status { get; set; }

[DataMember(Name = "watch")]
public IWatch Watch { get; set; }
}
}
1 change: 1 addition & 0 deletions src/Nest/_Generated/ApiUrlsLookup.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ internal static class ApiUrlsLookups
internal static ApiUrls WatcherExecute = new ApiUrls(new[]{"_watcher/watch/{id}/_execute", "_watcher/watch/_execute"});
internal static ApiUrls WatcherGet = new ApiUrls(new[]{"_watcher/watch/{id}"});
internal static ApiUrls WatcherPut = new ApiUrls(new[]{"_watcher/watch/{id}"});
internal static ApiUrls WatcherQueryWatches = new ApiUrls(new[]{"_watcher/_query/watches"});
internal static ApiUrls WatcherStart = new ApiUrls(new[]{"_watcher/_start"});
internal static ApiUrls WatcherStats = new ApiUrls(new[]{"_watcher/stats", "_watcher/stats/{metric}"});
internal static ApiUrls WatcherStop = new ApiUrls(new[]{"_watcher/_stop"});
Expand Down
104 changes: 104 additions & 0 deletions tests/Tests/XPack/Watcher/QueryWatches/QueryWatchesApiTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System;
using System.Collections.Generic;
using Elasticsearch.Net;
using FluentAssertions;
using Nest;
using Tests.Framework.EndpointTests;
using Tests.Framework.EndpointTests.TestState;

namespace Tests.XPack.Watcher.QueryWatches
{
public class QueryWatchesApiTests
: ApiIntegrationTestBase<WatcherCluster, QueryWatchesResponse, IQueryWatchesRequest, QueryWatchesDescriptor, QueryWatchesRequest>
{
private readonly Dictionary<string, object> _termCondition = new() { { "metadata.name", new { value = "value" } } };

public QueryWatchesApiTests(WatcherCluster cluster, EndpointUsage usage) : base(cluster, usage) { }

protected override bool ExpectIsValid => true;

protected override object ExpectJson => new
{
size = 5, from = 0, query = new { term = _termCondition }, sort = new[] { new { _id = new { order = "asc" } } }
};

protected override int ExpectStatusCode => 200;

protected override Func<QueryWatchesDescriptor, IQueryWatchesRequest> Fluent => p => p
.From(0)
.Size(5)
.Sort(s => s.Ascending("_id"))
.Query(q => q.Term(t => t.Field("metadata.name").Value("value")));

protected override HttpMethod HttpMethod => HttpMethod.POST;

protected override QueryWatchesRequest Initializer => new()
{
From = 0,
Size = 5,
Sort = new List<ISort> { new FieldSort { Field = "_id", Order = SortOrder.Ascending } },
Query = new TermQuery { Field = "metadata.name", Value = "value" }
};

protected override string UrlPath => "/_watcher/_query/watches";

protected override void IntegrationSetup(IElasticClient client, CallUniqueValues values)
{
foreach (var callUniqueValue in values)
{
var putWatchResponse = client.Watcher.Put(callUniqueValue.Value, p => p
.Input(i => i
.Simple(s => s
.Add("key", "value")
)
)
.Trigger(t => t
.Schedule(s => s
.Cron("0 5 9 * * ?")
)
)
.Actions(a => a
.Email("reminder_email", e => e
.To("[email protected]")
.Subject("Something's strange in the neighbourhood")
.Body(b => b
.Text("Who you gonna call?")
)
)
)
.Metadata(m => m.Add("name", "value"))
);

if (!putWatchResponse.IsValid)
throw new Exception("Problem setting up integration test");
}
}

protected override LazyResponses ClientUsage() => Calls(
(client, f) => client.Watcher.QueryWatches(f),
(client, f) => client.Watcher.QueryWatchesAsync(f),
(client, r) => client.Watcher.QueryWatches(r),
(client, r) => client.Watcher.QueryWatchesAsync(r)
);

protected override void ExpectResponse(QueryWatchesResponse response)
{
response.IsValid.Should().BeTrue();
response.Count.Should().Be(4);
response.Watches.Count.Should().Be(4);

foreach (var watchResult in response.Watches)
{
watchResult.Id.Should().NotBeNullOrEmpty();
watchResult.SequenceNumber.Should().BeGreaterOrEqualTo(0);
watchResult.PrimaryTerm.Should().Be(1);
watchResult.Status.State.Active.Should().BeTrue();
watchResult.Watch.Metadata["name"].Should().Be("value");
}
}
}
}
21 changes: 21 additions & 0 deletions tests/Tests/XPack/Watcher/QueryWatches/QueryWatchesUrlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Threading.Tasks;
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
using Nest;
using Tests.Framework.EndpointTests;
using static Tests.Framework.EndpointTests.UrlTester;

namespace Tests.XPack.Watcher.QueryWatches
{
public class QueryWatchesUrlTests : UrlTestsBase
{
[U] public override async Task Urls() => await POST("/_watcher/_query/watches")
.Fluent(c => c.Watcher.QueryWatches())
.Request(c => c.Watcher.QueryWatches(new QueryWatchesRequest()))
.FluentAsync(c => c.Watcher.QueryWatchesAsync())
.RequestAsync(c => c.Watcher.QueryWatchesAsync(new QueryWatchesRequest()));
}
}

0 comments on commit a308b6f

Please sign in to comment.