1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Net . Http ;
5+ using System . Threading ;
6+ using System . Threading . Tasks ;
7+ using Cognite . Extractor . Common ;
8+ using CogniteSdk ;
9+ using Moq ;
10+ using Xunit ;
11+
12+ namespace Cognite . Extractor . Testing . Mock
13+ {
14+ /// <summary>
15+ /// Mock implementation of the Events API.
16+ /// </summary>
17+ public class EventsMock
18+ {
19+ private long _nextId = 10000 ;
20+ private readonly Dictionary < string , Event > _eventsByExternalId = new Dictionary < string , Event > ( ) ;
21+ private readonly Dictionary < long , Event > _eventsById = new Dictionary < long , Event > ( ) ;
22+
23+ /// <summary>
24+ /// All mocked events.
25+ /// </summary>
26+ public ICollection < Event > Events => _eventsById . Values ;
27+
28+
29+ /// <summary>
30+ /// Mock an event, assigning it an ID.
31+ /// </summary>
32+ /// <param name="ev">Event to add.</param>
33+ public void MockEvent ( Event ev )
34+ {
35+ if ( ev == null ) throw new ArgumentNullException ( nameof ( ev ) ) ;
36+ ev . Id = _nextId ++ ;
37+ _eventsById [ ev . Id ] = ev ;
38+ if ( ! string . IsNullOrEmpty ( ev . ExternalId ) )
39+ {
40+ _eventsByExternalId [ ev . ExternalId ] = ev ;
41+ }
42+ }
43+
44+ /// <summary>
45+ /// Remove a mocked event by its external ID, if it is present.
46+ /// </summary>
47+ /// <param name="externalId">External ID of event to remove.</param>
48+ public bool Remove ( string externalId )
49+ {
50+ if ( _eventsByExternalId . TryGetValue ( externalId , out var ev ) )
51+ {
52+ _eventsByExternalId . Remove ( externalId ) ;
53+ _eventsById . Remove ( ev . Id ) ;
54+ return true ;
55+ }
56+ return false ;
57+ }
58+
59+ /// <summary>
60+ /// Mock an event with the given external ID, assigning it an ID.
61+ /// </summary>
62+ /// <param name="externalId">External ID of the event to add.</param>
63+ public void MockEvent ( string externalId )
64+ {
65+ MockEvent ( new Event
66+ {
67+ ExternalId = externalId ,
68+ Type = "someType" ,
69+ StartTime = DateTime . UtcNow . ToUnixTimeMilliseconds ( ) ,
70+ EndTime = DateTime . UtcNow . ToUnixTimeMilliseconds ( ) ,
71+ CreatedTime = DateTime . UtcNow . ToUnixTimeMilliseconds ( ) ,
72+ LastUpdatedTime = DateTime . UtcNow . ToUnixTimeMilliseconds ( ) ,
73+ } ) ;
74+ }
75+
76+ /// <summary>
77+ /// Get an event by its identity, if it exists.
78+ /// </summary>
79+ /// <param name="id">Event ID</param>
80+ /// <returns>The event, if it exists.</returns>
81+ public Event ? GetEvent ( Identity id )
82+ {
83+ if ( id == null ) throw new ArgumentNullException ( nameof ( id ) ) ;
84+
85+ if ( id . Id . HasValue && _eventsById . TryGetValue ( id . Id . Value , out var ev ) )
86+ {
87+ return ev ;
88+ }
89+ else if ( ! string . IsNullOrEmpty ( id . ExternalId ) && _eventsByExternalId . TryGetValue ( id . ExternalId , out var ev2 ) )
90+ {
91+ return ev2 ;
92+ }
93+
94+ return null ;
95+ }
96+ /// <summary>
97+ /// Get an event by its external ID, if it exists.
98+ /// </summary>
99+ /// <param name="externalId">Event external ID</param>
100+ /// <returns>The event, if it exists.</returns>
101+
102+ public Event ? GetEvent ( string externalId )
103+ {
104+ if ( externalId == null ) throw new ArgumentNullException ( nameof ( externalId ) ) ;
105+
106+ if ( _eventsByExternalId . TryGetValue ( externalId , out var ev ) )
107+ {
108+ return ev ;
109+ }
110+
111+ return null ;
112+ }
113+
114+ /// <summary>
115+ /// Get an event by its internal ID, if it exists.
116+ /// </summary>
117+ /// <param name="id">Event ID</param>
118+ /// <returns>The event, if it exists.</returns>
119+ public Event ? GetEvent ( long id )
120+ {
121+ if ( _eventsById . TryGetValue ( id , out var ev ) )
122+ {
123+ return ev ;
124+ }
125+
126+ return null ;
127+ }
128+
129+
130+ /// <summary>
131+ /// Clear the events mock, removing all mocked events.
132+ /// </summary>
133+ public void Clear ( )
134+ {
135+ _nextId = 10000 ;
136+ _eventsByExternalId . Clear ( ) ;
137+ _eventsById . Clear ( ) ;
138+ }
139+
140+ /// <summary>
141+ /// Get a matcher for the /events/byids endpoint.
142+ /// </summary>
143+ /// <param name="times">Expected number of executions.</param>
144+ public RequestMatcher MakeGetByIdsMatcher ( Times times )
145+ {
146+ return new SimpleMatcher ( "POST" , "/events/byids" , EventsByIdsImpl , times ) ;
147+ }
148+
149+ /// <summary>
150+ /// Get a matcher for the /events endpoint for creating events.
151+ /// </summary>
152+ /// <param name="times">Expected number of executions.</param>
153+ public RequestMatcher MakeCreateEventsMatcher ( Times times )
154+ {
155+ return new SimpleMatcher ( "POST" , "/events$" , EventsCreateImpl , times ) ;
156+ }
157+
158+ private async Task < HttpResponseMessage > EventsCreateImpl ( RequestContext context , CancellationToken token )
159+ {
160+ var events = await context . ReadJsonBody < ItemsWithoutCursor < EventCreate > > ( ) . ConfigureAwait ( false ) ;
161+ Assert . NotNull ( events ) ;
162+ var created = new List < Event > ( ) ;
163+ var conflict = new List < string > ( ) ;
164+
165+ foreach ( var ev in events . Items )
166+ {
167+ if ( ev . ExternalId != null && _eventsByExternalId . ContainsKey ( ev . ExternalId ) )
168+ {
169+ conflict . Add ( ev . ExternalId ) ;
170+ continue ;
171+ }
172+
173+ var newEvent = new Event
174+ {
175+ Id = _nextId ++ ,
176+ ExternalId = ev . ExternalId ,
177+ Type = ev . Type ,
178+ StartTime = ev . StartTime ,
179+ EndTime = ev . EndTime ,
180+ Source = ev . Source ,
181+ Description = ev . Description ,
182+ CreatedTime = DateTime . UtcNow . ToUnixTimeMilliseconds ( ) ,
183+ LastUpdatedTime = DateTime . UtcNow . ToUnixTimeMilliseconds ( ) ,
184+ Metadata = ev . Metadata ,
185+ } ;
186+
187+ _eventsById [ newEvent . Id ] = newEvent ;
188+ if ( newEvent . ExternalId != null )
189+ {
190+ _eventsByExternalId [ newEvent . ExternalId ] = newEvent ;
191+ }
192+ created . Add ( newEvent ) ;
193+ }
194+
195+ if ( conflict . Count > 0 )
196+ {
197+ return context . CreateError ( new CogniteError
198+ {
199+ Code = 409 ,
200+ Message = "Conflict" ,
201+ Duplicated = conflict . Distinct ( ) . Select ( id => MockUtils . ToMultiValueDict ( new Identity ( id ) ) ) . ToList ( )
202+ } ) ;
203+ }
204+
205+ return context . CreateJsonResponse ( new ItemsWithoutCursor < Event > { Items = created } ) ;
206+ }
207+
208+ private async Task < HttpResponseMessage > EventsByIdsImpl ( RequestContext context , CancellationToken token )
209+ {
210+ var ids = await context . ReadJsonBody < ItemsWithIgnoreUnknownIds < RawIdentity > > ( ) . ConfigureAwait ( false ) ;
211+ Assert . NotNull ( ids ) ;
212+ var found = new List < Event > ( ) ;
213+ var missing = new List < Identity > ( ) ;
214+
215+ foreach ( var id in ids . Items )
216+ {
217+ Event ? ev = null ;
218+ if ( id . Id . HasValue )
219+ {
220+ _eventsById . TryGetValue ( id . Id . Value , out ev ) ;
221+ }
222+ else if ( ! string . IsNullOrEmpty ( id . ExternalId ) )
223+ {
224+ _eventsByExternalId . TryGetValue ( id . ExternalId , out ev ) ;
225+ }
226+
227+ if ( ev != null )
228+ {
229+ found . Add ( ev ) ;
230+ }
231+ else
232+ {
233+ missing . Add ( id . ToIdentity ( ) ) ;
234+ }
235+ }
236+
237+ if ( ! ids . IgnoreUnknownIds && missing . Count > 0 )
238+ {
239+ return context . CreateError ( new CogniteError
240+ {
241+ Code = 400 ,
242+ Message = "Events not found" ,
243+ Missing = missing . Distinct ( ) . Select ( MockUtils . ToMultiValueDict ) . ToList ( ) ,
244+ } ) ;
245+ }
246+
247+ return context . CreateJsonResponse ( new ItemsWithoutCursor < Event >
248+ {
249+ Items = found
250+ } ) ;
251+ }
252+ }
253+ }
0 commit comments