3
3
// See the LICENSE file in the project root for more information
4
4
5
5
using System ;
6
+ using System . Collections . Generic ;
6
7
using System . IO ;
7
8
using System . IO . Compression ;
9
+ using System . Linq ;
8
10
using System . Text ;
9
11
using System . Threading ;
10
12
using System . Threading . Tasks ;
11
13
12
14
namespace Elasticsearch . Net
13
15
{
16
+ public class InMemoryHttpResponse
17
+ {
18
+ public int StatusCode { get ; set ; } = 200 ;
19
+ public byte [ ] ResponseBytes { get ; set ; } = Array . Empty < byte > ( ) ;
20
+ public Dictionary < string , List < string > > Headers { get ; set ; } = new ( ) ;
21
+ public string ContentType { get ; set ; }
22
+ }
23
+
14
24
public class InMemoryConnection : IConnection
15
25
{
16
- internal static readonly byte [ ] EmptyBody = Encoding . UTF8 . GetBytes ( "" ) ;
26
+ private readonly string _basePath = "/" ;
27
+ private const string DefaultProductName = "Elasticsearch" ;
28
+ private static readonly byte [ ] EmptyBody = Encoding . UTF8 . GetBytes ( "" ) ;
17
29
private readonly string _contentType ;
18
30
private readonly Exception _exception ;
19
31
private readonly byte [ ] _responseBody ;
20
32
private readonly int _statusCode ;
33
+ private readonly InMemoryHttpResponse _productCheckResponse ;
34
+ private readonly string _productHeader ;
35
+
36
+ public static InMemoryHttpResponse ValidProductCheckResponse ( string productName = null )
37
+ {
38
+ var responseJson = new
39
+ {
40
+ name = "es01" ,
41
+ cluster_name = "elasticsearch-test-cluster" ,
42
+ version = new
43
+ {
44
+ number = "7.14.0" ,
45
+ build_flavor = "default" ,
46
+ build_hash = "af1dc6d8099487755c3143c931665b709de3c764" ,
47
+ build_timestamp = "2020-08-11T21:36:48.204330Z" ,
48
+ build_snapshot = false ,
49
+ lucene_version = "8.6.0"
50
+ } ,
51
+ tagline = "You Know, for Search"
52
+ } ;
53
+
54
+ using var ms = RecyclableMemoryStreamFactory . Default . Create ( ) ;
55
+ LowLevelRequestResponseSerializer . Instance . Serialize ( responseJson , ms ) ;
56
+
57
+ var response = new InMemoryHttpResponse
58
+ {
59
+ ResponseBytes = ms . ToArray ( )
60
+ } ;
61
+
62
+ response . Headers . Add ( "X-elastic-product" , new List < string > { productName ?? DefaultProductName } ) ;
63
+
64
+ return response ;
65
+ }
21
66
22
67
/// <summary>
23
68
/// Every request will succeed with this overload, note that it won't actually return mocked responses
24
69
/// so using this overload might fail if you are using it to test high level bits that need to deserialize the response.
25
70
/// </summary>
26
- public InMemoryConnection ( ) => _statusCode = 200 ;
71
+ public InMemoryConnection ( )
72
+ {
73
+ _statusCode = 200 ;
74
+ _productCheckResponse = ValidProductCheckResponse ( ) ;
75
+ }
27
76
28
- public InMemoryConnection ( byte [ ] responseBody , int statusCode = 200 , Exception exception = null , string contentType = null )
77
+ public InMemoryConnection ( string basePath ) : this ( ) => _basePath = $ "/{ basePath . Trim ( '/' ) } /";
78
+
79
+ public InMemoryConnection ( InMemoryHttpResponse productCheckResponse = null , int statusCode = 200 , string productHeader = null )
29
80
{
81
+ _statusCode = statusCode ;
82
+ _productCheckResponse = productCheckResponse ?? ValidProductCheckResponse ( ) ;
83
+ _productHeader = productHeader ;
84
+ }
30
85
86
+ public InMemoryConnection (
87
+ byte [ ] responseBody ,
88
+ int statusCode = 200 ,
89
+ Exception exception = null ,
90
+ string contentType = null ,
91
+ InMemoryHttpResponse productCheckResponse = null ,
92
+ string productNameFromHeader = null ) : this ( productCheckResponse , statusCode , productNameFromHeader )
93
+ {
31
94
_responseBody = responseBody ;
32
- _statusCode = statusCode ;
33
95
_exception = exception ;
34
96
_contentType = contentType ?? RequestData . DefaultJsonMimeType ;
35
97
}
@@ -43,59 +105,92 @@ public virtual Task<TResponse> RequestAsync<TResponse>(RequestData requestData,
43
105
ReturnConnectionStatusAsync < TResponse > ( requestData , cancellationToken ) ;
44
106
45
107
void IDisposable . Dispose ( ) => DisposeManagedResources ( ) ;
46
-
47
- protected TResponse ReturnConnectionStatus < TResponse > ( RequestData requestData , byte [ ] responseBody = null , int ? statusCode = null ,
48
- string contentType = null
108
+
109
+ protected TResponse ReturnConnectionStatus < TResponse > (
110
+ RequestData requestData ,
111
+ byte [ ] responseBody = null ,
112
+ int ? statusCode = null ,
113
+ string contentType = null ,
114
+ InMemoryHttpResponse productCheckResponse = null
49
115
)
50
116
where TResponse : class , IElasticsearchResponse , new ( )
51
117
{
118
+ if ( _basePath . Equals ( requestData . Uri . AbsolutePath , StringComparison . Ordinal ) && requestData . Method == HttpMethod . GET )
119
+ return ReturnProductCheckResponse < TResponse > ( requestData , statusCode , productCheckResponse ) ;
120
+
52
121
var body = responseBody ?? _responseBody ;
53
122
var data = requestData . PostData ;
54
- if ( data != null )
123
+
124
+ if ( data is not null )
55
125
{
56
- using ( var stream = requestData . MemoryStreamFactory . Create ( ) )
57
- {
58
- if ( requestData . HttpCompression )
59
- using ( var zipStream = new GZipStream ( stream , CompressionMode . Compress ) )
60
- data . Write ( zipStream , requestData . ConnectionSettings ) ;
61
- else
62
- data . Write ( stream , requestData . ConnectionSettings ) ;
63
- }
126
+ using var stream = requestData . MemoryStreamFactory . Create ( ) ;
127
+
128
+ if ( requestData . HttpCompression )
129
+ using ( var zipStream = new GZipStream ( stream , CompressionMode . Compress ) )
130
+ data . Write ( zipStream , requestData . ConnectionSettings ) ;
131
+ else
132
+ data . Write ( stream , requestData . ConnectionSettings ) ;
64
133
}
134
+
65
135
requestData . MadeItToResponse = true ;
66
136
67
137
var sc = statusCode ?? _statusCode ;
68
138
Stream s = body != null ? requestData . MemoryStreamFactory . Create ( body ) : requestData . MemoryStreamFactory . Create ( EmptyBody ) ;
69
139
return ResponseBuilder . ToResponse < TResponse > ( requestData , _exception , sc , null , s , contentType ?? _contentType ?? RequestData . DefaultJsonMimeType ) ;
70
140
}
71
141
72
- protected async Task < TResponse > ReturnConnectionStatusAsync < TResponse > ( RequestData requestData , CancellationToken cancellationToken ,
73
- byte [ ] responseBody = null , int ? statusCode = null , string contentType = null
142
+ protected async Task < TResponse > ReturnConnectionStatusAsync < TResponse > (
143
+ RequestData requestData ,
144
+ CancellationToken cancellationToken ,
145
+ byte [ ] responseBody = null ,
146
+ int ? statusCode = null ,
147
+ string contentType = null ,
148
+ InMemoryHttpResponse productCheckResponse = null
74
149
)
75
150
where TResponse : class , IElasticsearchResponse , new ( )
76
151
{
152
+ if ( _basePath . Equals ( requestData . Uri . AbsolutePath , StringComparison . Ordinal ) && requestData . Method == HttpMethod . GET )
153
+ return ReturnProductCheckResponse < TResponse > ( requestData , statusCode , productCheckResponse ) ;
154
+
77
155
var body = responseBody ?? _responseBody ;
78
156
var data = requestData . PostData ;
157
+
79
158
if ( data != null )
80
159
{
81
- using ( var stream = requestData . MemoryStreamFactory . Create ( ) )
82
- {
83
- if ( requestData . HttpCompression )
84
- using ( var zipStream = new GZipStream ( stream , CompressionMode . Compress ) )
85
- await data . WriteAsync ( zipStream , requestData . ConnectionSettings , cancellationToken ) . ConfigureAwait ( false ) ;
86
- else
87
- await data . WriteAsync ( stream , requestData . ConnectionSettings , cancellationToken ) . ConfigureAwait ( false ) ;
88
- }
160
+ using var stream = requestData . MemoryStreamFactory . Create ( ) ;
161
+ if ( requestData . HttpCompression )
162
+ using ( var zipStream = new GZipStream ( stream , CompressionMode . Compress ) )
163
+ await data . WriteAsync ( zipStream , requestData . ConnectionSettings , cancellationToken ) . ConfigureAwait ( false ) ;
164
+ else
165
+ await data . WriteAsync ( stream , requestData . ConnectionSettings , cancellationToken ) . ConfigureAwait ( false ) ;
89
166
}
90
167
requestData . MadeItToResponse = true ;
91
168
92
169
var sc = statusCode ?? _statusCode ;
93
170
Stream s = body != null ? requestData . MemoryStreamFactory . Create ( body ) : requestData . MemoryStreamFactory . Create ( EmptyBody ) ;
94
171
return await ResponseBuilder
95
- . ToResponseAsync < TResponse > ( requestData , _exception , sc , null , s , contentType ?? _contentType , cancellationToken )
172
+ . ToResponseAsync < TResponse > ( requestData , _exception , sc , null , s , contentType ?? _contentType , _productHeader , cancellationToken )
96
173
. ConfigureAwait ( false ) ;
97
174
}
98
175
176
+ private TResponse ReturnProductCheckResponse < TResponse > (
177
+ RequestData requestData ,
178
+ int ? statusCode = null ,
179
+ InMemoryHttpResponse productCheckResponse = null
180
+ ) where TResponse : class , IElasticsearchResponse , new ( )
181
+ {
182
+ productCheckResponse ??= _productCheckResponse ;
183
+ productCheckResponse . Headers . TryGetValue ( "X-elastic-product" , out var productNames ) ;
184
+
185
+ requestData . MadeItToResponse = true ;
186
+
187
+ using var ms = requestData . MemoryStreamFactory . Create ( productCheckResponse . ResponseBytes ) ;
188
+
189
+ return ResponseBuilder . ToResponse < TResponse > (
190
+ requestData , _exception , statusCode ?? productCheckResponse . StatusCode , null , ms ,
191
+ RequestData . DefaultJsonMimeType , productNames ? . FirstOrDefault ( ) ) ;
192
+ }
193
+
99
194
protected virtual void DisposeManagedResources ( ) { }
100
195
}
101
196
}
0 commit comments