diff --git a/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs b/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs index e911ebb3aa..424a8c5d9a 100644 --- a/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs +++ b/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs @@ -37,7 +37,7 @@ public async Task ProvisioningServiceClient_QueryInvalidServiceCertificateHttp_F { using var provisioningServiceClient = ProvisioningServiceClient.CreateFromConnectionString( TestConfiguration.Provisioning.ConnectionStringInvalidServiceCertificate); - Query q = provisioningServiceClient.CreateEnrollmentGroupQuery( + Microsoft.Azure.Devices.Provisioning.Service.IQuery q = provisioningServiceClient.CreateEnrollmentGroupQuery( new QuerySpecification("SELECT * FROM enrollmentGroups")); ProvisioningServiceClientTransportException exception = await Assert.ThrowsExceptionAsync( diff --git a/e2e/test/provisioning/ProvisioningServiceClientE2ETests.cs b/e2e/test/provisioning/ProvisioningServiceClientE2ETests.cs index d26ca0cc49..ff0c717bc1 100644 --- a/e2e/test/provisioning/ProvisioningServiceClientE2ETests.cs +++ b/e2e/test/provisioning/ProvisioningServiceClientE2ETests.cs @@ -7,7 +7,6 @@ using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using FluentAssertions; -using Microsoft.Azure.Devices.Client; using Microsoft.Azure.Devices.E2ETests.Helpers; using Microsoft.Azure.Devices.Provisioning.Security.Samples; using Microsoft.Azure.Devices.Provisioning.Service; @@ -26,7 +25,7 @@ public class ProvisioningServiceClientE2ETests : E2EMsTestBase private static readonly string s_devicePrefix = $"{nameof(ProvisioningServiceClientE2ETests)}_"; private static readonly HashSet s_retryableExceptions = new HashSet { typeof(ProvisioningServiceClientHttpException) }; - private static readonly IRetryPolicy s_provisioningServiceRetryPolicy = new ProvisioningServiceRetryPolicy(); + private static readonly Microsoft.Azure.Devices.Client.IRetryPolicy s_provisioningServiceRetryPolicy = new ProvisioningServiceRetryPolicy(); public enum EnrollmentType { @@ -273,7 +272,7 @@ private async Task ProvisioningServiceClient_IndividualEnrollments_Query_Ok(stri { using ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(proxyServerAddress); var querySpecification = new QuerySpecification("SELECT * FROM enrollments"); - using Query query = provisioningServiceClient.CreateIndividualEnrollmentQuery(querySpecification); + using Microsoft.Azure.Devices.Provisioning.Service.IQuery query = provisioningServiceClient.CreateIndividualEnrollmentQuery(querySpecification); while (query.HasNext()) { QueryResult queryResult = await query.NextAsync().ConfigureAwait(false); diff --git a/provisioning/service/src/Config/QueryResult.cs b/provisioning/service/src/Config/QueryResult.cs index 91b452066a..853e185dc4 100644 --- a/provisioning/service/src/Config/QueryResult.cs +++ b/provisioning/service/src/Config/QueryResult.cs @@ -91,12 +91,19 @@ public class QueryResult /// /// /// - public IEnumerable Items { get; private set; } + public virtual IEnumerable Items { get; private set; } /// /// Getter for the query result continuationToken. /// public string ContinuationToken { get; private set; } + /// + /// For Mocking + /// + public QueryResult() + { + + } /// /// CONSTRUCTOR diff --git a/provisioning/service/src/Contract/IQuery.cs b/provisioning/service/src/Contract/IQuery.cs new file mode 100644 index 0000000000..d9becd8af1 --- /dev/null +++ b/provisioning/service/src/Contract/IQuery.cs @@ -0,0 +1,98 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Azure.Devices.Common; + +namespace Microsoft.Azure.Devices.Provisioning.Service +{ + + + /// + /// The query iterator. + /// + /// + /// The iterator is the result of the query factory for + /// + /// + /// + /// IndividualEnrollment + /// + /// + /// + /// + /// EnrollmentGroup + /// + /// + /// + /// + /// RegistrationStatus + /// + /// + /// + /// On all cases, the contains a SQL query that must follow the + /// Query Language for the Device Provisioning Service. + /// + /// Optionally, an Integer with the page size, can determine the maximum number of the items in the + /// returned by the . It must be any positive integer, and if it + /// contains 0, the Device Provisioning Service will ignore it and use a standard page size. + /// + /// You can use this Object as a standard iterator, just using the HasNext and NextAsync in a + /// while loop, up to the point where the HasNext contains false. But, keep + /// in mind that the can contain a empty list, even if the HasNext contained + /// true. For example, image that you have 10 IndividualEnrollment in the Device Provisioning Service + /// and you created new query with the PageSize equals 5. In the first iteration, HasNext + /// will contains true, and the first NextAsync will return a QueryResult with + /// 5 items. After, your code will check the HasNext, which will contains true again. Now, + /// before you get the next page, somebody deletes all the IndividualEnrollment. What happened, when you call the + /// NextAsync, it will return a valid QueryResult, but the + /// will contain an empty list. + /// + /// Besides the Items, the QueryResult contains the . + /// You can also store a query context (QuerySpecification + ContinuationToken) and restart it in the future, from + /// the point where you stopped. Just recreating the query with the same and calling + /// the passing the stored ContinuationToken. + /// + public interface IQuery :IDisposable + { + /// + /// The number of items in the current page. + /// + public int PageSize { get; set; } + + /// + /// The token to retrieve the next page. + /// + public string ContinuationToken { get; set; } + + /// + /// Getter for has next. + /// + /// + /// Contains true if the query is not finished in the Device Provisioning Service, and another + /// iteration with may return more items. Call after + /// a true HasNext will result in a that can or + /// cannot contains elements. But call after a false HasNext + /// will result in a exception. + /// + public bool HasNext(); + /// + /// Return the next page of result for the query using a new continuationToken. + /// + /// the string with the previous continuationToken. It cannot be null or empty. + /// The with the next page of items for the query. + /// if the query does no have more pages to return. + public Task NextAsync(string continuationToken); + /// + /// Getter for has next. + /// + /// + /// Contains true if the query is not finished in the Device Provisioning Service, and another + /// iteration with may return more items. Call after + /// a true HasNext will result in a that can or + /// cannot contains elements. But call after a false HasNext + /// will result in a exception. + /// + public Task NextAsync(); + } + +} \ No newline at end of file diff --git a/provisioning/service/src/ProvisioningServiceClient.cs b/provisioning/service/src/ProvisioningServiceClient.cs index a68fb7b009..6437546e28 100644 --- a/provisioning/service/src/ProvisioningServiceClient.cs +++ b/provisioning/service/src/ProvisioningServiceClient.cs @@ -445,7 +445,7 @@ public Task DeleteIndividualEnrollmentAsync(string registrationId, string eTag, /// The with the SQL query. It cannot be null. /// The iterator. /// If the provided parameter is not correct. - public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecification) + public IQuery CreateIndividualEnrollmentQuery(QuerySpecification querySpecification) { return IndividualEnrollmentManager.CreateQuery( _provisioningConnectionString, @@ -468,7 +468,7 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati /// Specifies the HTTP transport settings /// The iterator. /// If the provided parameter is not correct. - public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, HttpTransportSettings httpTransportSettings) + public IQuery CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, HttpTransportSettings httpTransportSettings) { return IndividualEnrollmentManager.CreateQuery( _provisioningConnectionString, @@ -491,7 +491,7 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati /// The cancellation token. /// The iterator. /// If the provided parameter is not correct. - public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, CancellationToken cancellationToken) + public IQuery CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, CancellationToken cancellationToken) { return IndividualEnrollmentManager.CreateQuery( _provisioningConnectionString, @@ -518,7 +518,7 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati /// The int with the maximum number of items per iteration. It can be 0 for default, but not negative. /// The iterator. /// If the provided parameters are not correct. - public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, int pageSize) + public IQuery CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, int pageSize) { return IndividualEnrollmentManager.CreateQuery( _provisioningConnectionString, @@ -547,7 +547,7 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati /// The cancellation token. /// The iterator. /// If the provided parameters are not correct. - public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, int pageSize, CancellationToken cancellationToken) + public IQuery CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, int pageSize, CancellationToken cancellationToken) { return IndividualEnrollmentManager.CreateQuery( _provisioningConnectionString, @@ -576,7 +576,7 @@ public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecificati /// Specifies the HTTP transport settings /// The iterator. /// If the provided parameters are not correct. - public Query CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, int pageSize, HttpTransportSettings httpTransportSettings) + public IQuery CreateIndividualEnrollmentQuery(QuerySpecification querySpecification, int pageSize, HttpTransportSettings httpTransportSettings) { return IndividualEnrollmentManager.CreateQuery( _provisioningConnectionString, @@ -811,7 +811,7 @@ public Task DeleteEnrollmentGroupAsync(string enrollmentGroupId, string eTag, Ca /// The with the SQL query. It cannot be null. /// The iterator. /// If the provided parameter is not correct. - public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification) + public IQuery CreateEnrollmentGroupQuery(QuerySpecification querySpecification) { return EnrollmentGroupManager.CreateQuery( _provisioningConnectionString, @@ -834,7 +834,7 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification) /// Specifies the HTTP transport settings /// The iterator. /// If the provided parameter is not correct. - public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, HttpTransportSettings httpTransportSettings) + public IQuery CreateEnrollmentGroupQuery(QuerySpecification querySpecification, HttpTransportSettings httpTransportSettings) { return EnrollmentGroupManager.CreateQuery( _provisioningConnectionString, @@ -857,7 +857,7 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, H /// The cancellation token. /// The iterator. /// If the provided parameter is not correct. - public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, CancellationToken cancellationToken) + public IQuery CreateEnrollmentGroupQuery(QuerySpecification querySpecification, CancellationToken cancellationToken) { return EnrollmentGroupManager.CreateQuery( _provisioningConnectionString, @@ -884,7 +884,7 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, C /// The int with the maximum number of items per iteration. It can be 0 for default, but not negative. /// The iterator. /// If the provided parameters are not correct. - public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, int pageSize) + public IQuery CreateEnrollmentGroupQuery(QuerySpecification querySpecification, int pageSize) { return EnrollmentGroupManager.CreateQuery( _provisioningConnectionString, @@ -913,7 +913,7 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, i /// The cancellation token. /// The iterator. /// If the provided parameters are not correct. - public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, int pageSize, CancellationToken cancellationToken) + public IQuery CreateEnrollmentGroupQuery(QuerySpecification querySpecification, int pageSize, CancellationToken cancellationToken) { return EnrollmentGroupManager.CreateQuery( _provisioningConnectionString, @@ -942,7 +942,7 @@ public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, i /// Specifies the HTTP transport settings /// The iterator. /// If the provided parameters are not correct. - public Query CreateEnrollmentGroupQuery(QuerySpecification querySpecification, int pageSize, HttpTransportSettings httpTransportSettings) + public IQuery CreateEnrollmentGroupQuery(QuerySpecification querySpecification, int pageSize, HttpTransportSettings httpTransportSettings) { return EnrollmentGroupManager.CreateQuery( _provisioningConnectionString, @@ -1125,7 +1125,7 @@ public Task DeleteDeviceRegistrationStateAsync(string id, string eTag, Cancellat /// The with the SQL query. It cannot be null. /// The string that identifies the enrollmentGroup. It cannot be null or empty. /// The iterator. - public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification querySpecification, string enrollmentGroupId) + public IQuery CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification querySpecification, string enrollmentGroupId) { return RegistrationStatusManager.CreateEnrollmentGroupQuery( _provisioningConnectionString, @@ -1149,7 +1149,7 @@ public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification quer /// The string that identifies the enrollmentGroup. It cannot be null or empty. /// Specifies the HTTP transport settings /// The iterator. - public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification querySpecification, string enrollmentGroupId, HttpTransportSettings httpTransportSettings) + public IQuery CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification querySpecification, string enrollmentGroupId, HttpTransportSettings httpTransportSettings) { return RegistrationStatusManager.CreateEnrollmentGroupQuery( _provisioningConnectionString, @@ -1173,7 +1173,7 @@ public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification quer /// The string that identifies the enrollmentGroup. It cannot be null or empty. /// The cancellation token. /// The iterator. - public Query CreateEnrollmentGroupRegistrationStateQuery( + public IQuery CreateEnrollmentGroupRegistrationStateQuery( QuerySpecification querySpecification, string enrollmentGroupId, CancellationToken cancellationToken) @@ -1205,7 +1205,7 @@ public Query CreateEnrollmentGroupRegistrationStateQuery( /// The int with the maximum number of items per iteration. It can be 0 for default, but not negative. /// The iterator. /// If the provided parameters are not correct. - public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification querySpecification, string enrollmentGroupId, int pageSize) + public IQuery CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification querySpecification, string enrollmentGroupId, int pageSize) { return RegistrationStatusManager.CreateEnrollmentGroupQuery( _provisioningConnectionString, @@ -1236,7 +1236,7 @@ public Query CreateEnrollmentGroupRegistrationStateQuery(QuerySpecification quer /// Specifies the HTTP transport settings /// The iterator. /// If the provided parameters are not correct. - public Query CreateEnrollmentGroupRegistrationStateQuery( + public IQuery CreateEnrollmentGroupRegistrationStateQuery( QuerySpecification querySpecification, string enrollmentGroupId, int pageSize, @@ -1271,7 +1271,7 @@ public Query CreateEnrollmentGroupRegistrationStateQuery( /// The int with the maximum number of items per iteration. It can be 0 for default, but not negative. /// The iterator. /// If the provided parameters are not correct. - public Query CreateEnrollmentGroupRegistrationStateQuery( + public IQuery CreateEnrollmentGroupRegistrationStateQuery( QuerySpecification querySpecification, string enrollmentGroupId, int pageSize, diff --git a/provisioning/service/src/Query.cs b/provisioning/service/src/Query.cs index 4215b032aa..17186e66a8 100644 --- a/provisioning/service/src/Query.cs +++ b/provisioning/service/src/Query.cs @@ -58,7 +58,7 @@ namespace Microsoft.Azure.Devices.Provisioning.Service /// the point where you stopped. Just recreating the query with the same and calling /// the passing the stored ContinuationToken. /// - public class Query : IDisposable + public class Query : IQuery, IDisposable { private const string ContinuationTokenHeaderKey = "x-ms-continuation"; private const string ItemTypeHeaderKey = "x-ms-item-type";