66using System . Text . Json ;
77using System . Threading ;
88using System . Threading . Tasks ;
9+ using Azure . Core . TestFramework ;
910using FluentAssertions ;
1011using NUnit . Framework ;
1112
1213namespace Azure . DigitalTwins . Core . Tests
1314{
1415 public class QueryTests : E2eTestBase
1516 {
17+ private static readonly int s_retryCount = 10 ;
18+ private static readonly TimeSpan s_retryDelay = TimeSpan . FromSeconds ( 2 ) ;
19+
1620 public QueryTests ( bool isAsync )
1721 : base ( isAsync )
1822 {
@@ -37,19 +41,38 @@ public async Task Query_ValidQuery_Success()
3741 // Create a room twin, with property "IsOccupied": true
3842 string roomTwinId = await GetUniqueTwinIdAsync ( client , TestAssetDefaults . RoomTwinIdPrefix ) . ConfigureAwait ( false ) ;
3943 BasicDigitalTwin roomTwin = TestAssetsHelper . GetRoomTwinPayload ( roomModelId ) ;
40- await client . CreateOrReplaceDigitalTwinAsync < BasicDigitalTwin > ( roomTwinId , roomTwin ) . ConfigureAwait ( false ) ;
44+ await client . CreateOrReplaceDigitalTwinAsync ( roomTwinId , roomTwin ) . ConfigureAwait ( false ) ;
4145
42- string queryString = "SELECT * FROM digitaltwins where IsOccupied = true" ;
46+ // Construct a query string to find the twins with the EXACT model id and provided version. If EXACT is not specified, the query
47+ // call will get all twins with the same model id but that implement any version higher than the provided version
48+ string queryString = $ "SELECT * FROM digitaltwins WHERE IS_OF_MODEL('{ roomModelId } ', EXACT) AND IsOccupied = true";
4349
4450 // act
45- AsyncPageable < JsonElement > asyncPageableResponse = client . QueryAsync < JsonElement > ( queryString ) ;
51+ AsyncPageable < BasicDigitalTwin > asyncPageableResponse = client . QueryAsync < BasicDigitalTwin > ( queryString ) ;
4652
4753 // assert
48- await foreach ( JsonElement response in asyncPageableResponse )
54+
55+ // It takes a few seconds for the service to be able to fetch digital twins through queries after being created. Hence, adding the retry logic
56+ var digitalTwinFound = false ;
57+ await TestRetryHelper . RetryAsync < AsyncPageable < BasicDigitalTwin > > ( async ( ) =>
4958 {
50- JsonElement isOccupied = response . GetProperty ( "IsOccupied" ) ;
51- isOccupied . GetRawText ( ) . Should ( ) . Be ( "true" ) ;
52- }
59+ await foreach ( BasicDigitalTwin response in asyncPageableResponse )
60+ {
61+ digitalTwinFound = true ;
62+ bool isOccupied = ( ( JsonElement ) response . Contents [ "IsOccupied" ] ) . GetBoolean ( ) ;
63+ isOccupied . Should ( ) . BeTrue ( ) ;
64+ break ;
65+ }
66+
67+ if ( ! digitalTwinFound )
68+ {
69+ throw new Exception ( $ "Digital twin based on model Id { roomModelId } not found") ;
70+ }
71+
72+ return null ;
73+ } , s_retryCount , s_retryDelay ) ;
74+
75+ digitalTwinFound . Should ( ) . BeTrue ( ) ;
5376 }
5477 catch ( Exception ex )
5578 {
@@ -154,5 +177,78 @@ public async Task Query_PaginationWorks()
154177 }
155178 }
156179 }
180+
181+ [ Test ]
182+ public async Task Query_GetTwinCount ( )
183+ {
184+ DigitalTwinsClient client = GetClient ( ) ;
185+
186+ string floorModelId = await GetUniqueModelIdAsync ( client , TestAssetDefaults . FloorModelIdPrefix ) . ConfigureAwait ( false ) ;
187+ string roomModelId = await GetUniqueModelIdAsync ( client , TestAssetDefaults . RoomModelIdPrefix ) . ConfigureAwait ( false ) ;
188+
189+ try
190+ {
191+ // arrange
192+
193+ // Create room model
194+ string roomModel = TestAssetsHelper . GetRoomModelPayload ( roomModelId , floorModelId ) ;
195+ await CreateAndListModelsAsync ( client , new List < string > { roomModel } ) . ConfigureAwait ( false ) ;
196+
197+ // Create a room twin, with property "IsOccupied": true
198+ string roomTwinId = await GetUniqueTwinIdAsync ( client , TestAssetDefaults . RoomTwinIdPrefix ) . ConfigureAwait ( false ) ;
199+ BasicDigitalTwin roomTwin = TestAssetsHelper . GetRoomTwinPayload ( roomModelId ) ;
200+ await client . CreateOrReplaceDigitalTwinAsync ( roomTwinId , roomTwin ) . ConfigureAwait ( false ) ;
201+
202+ // Construct a query string to find the twins with the EXACT model id and provided version. If EXACT is not specified, the query
203+ // call will get all twins with the same model id but that implement any version higher than the provided version
204+ string queryString = $ "SELECT COUNT() FROM digitaltwins WHERE IS_OF_MODEL('{ roomModelId } ', EXACT) AND IsOccupied = true";
205+
206+ // act
207+ AsyncPageable < JsonElement > asyncPageableResponse = client . QueryAsync < JsonElement > ( queryString ) ;
208+
209+ // assert
210+
211+ // It takes a few seconds for the service to be able to fetch digital twins through queries after being created. Hence, adding the retry logic
212+ var currentCount = 0 ;
213+ await TestRetryHelper . RetryAsync < AsyncPageable < JsonElement > > ( async ( ) =>
214+ {
215+ await foreach ( JsonElement response in asyncPageableResponse )
216+ {
217+ string currentCountStr = response . GetRawText ( ) ;
218+ IDictionary < string , int > currentCountDictionary = JsonSerializer . Deserialize < IDictionary < string , int > > ( currentCountStr ) ;
219+ currentCountDictionary . ContainsKey ( "COUNT" ) . Should ( ) . BeTrue ( ) ;
220+ currentCount = currentCountDictionary [ "COUNT" ] ;
221+ }
222+
223+ if ( currentCount == 0 )
224+ {
225+ throw new Exception ( $ "Digital twin based on model Id { roomModelId } not found") ;
226+ }
227+
228+ return null ;
229+ } , s_retryCount , s_retryDelay ) ;
230+
231+ currentCount . Should ( ) . Be ( 1 ) ;
232+ }
233+ catch ( Exception ex )
234+ {
235+ Assert . Fail ( $ "Failure in executing a step in the test case: { ex . Message } .") ;
236+ }
237+ finally
238+ {
239+ // clean up
240+ try
241+ {
242+ if ( ! string . IsNullOrWhiteSpace ( roomModelId ) )
243+ {
244+ await client . DeleteModelAsync ( roomModelId ) . ConfigureAwait ( false ) ;
245+ }
246+ }
247+ catch ( Exception ex )
248+ {
249+ Assert . Fail ( $ "Test clean up failed: { ex . Message } ") ;
250+ }
251+ }
252+ }
157253 }
158254}
0 commit comments