1+ using System ;
2+ using System . Linq ;
3+ using System . Net . Http ;
4+ using System . Threading . Tasks ;
5+ using Grpc . Core ;
6+ using InfluxDB3 . Client . Config ;
7+ using WireMock . RequestBuilders ;
8+ using WireMock . ResponseBuilders ;
9+
10+ namespace InfluxDB3 . Client . Test ;
11+
12+ public class InfluxDBClientHttpsTest : MockHttpsServerTest
13+ {
14+ private InfluxDBClient _client ;
15+
16+ [ TearDown ]
17+ public new void TearDown ( )
18+ {
19+ _client ? . Dispose ( ) ;
20+ }
21+
22+ [ Test ]
23+ public Task NonExistingCertificateFile ( )
24+ {
25+ var ae = Assert . ThrowsAsync < ArgumentException > ( ( ) =>
26+ {
27+ _client = new InfluxDBClient ( new ClientConfig
28+ {
29+ Host = MockHttpsServerUrl ,
30+ Token = "my-token" ,
31+ Organization = "my-org" ,
32+ Database = "my-database" ,
33+ DisableServerCertificateValidation = false ,
34+ DisableCertificateRevocationListCheck = true ,
35+ SslRootsFilePath = "./not-existing.pem"
36+ } ) ;
37+ return null ;
38+ } ) ;
39+
40+ Assert . That ( ae , Is . Not . Null ) ;
41+ Assert . That ( ae . Message , Does . Match ( "Certificate file '.*' not found" ) ) ;
42+ return Task . CompletedTask ;
43+ }
44+
45+ [ Test ]
46+ public Task EmptyCertificateFile ( )
47+ {
48+ var ae = Assert . ThrowsAsync < ArgumentException > ( ( ) =>
49+ {
50+ _client = new InfluxDBClient ( new ClientConfig
51+ {
52+ Host = MockHttpsServerUrl ,
53+ Token = "my-token" ,
54+ Organization = "my-org" ,
55+ Database = "my-database" ,
56+ DisableServerCertificateValidation = false ,
57+ DisableCertificateRevocationListCheck = true ,
58+ SslRootsFilePath = "./TestData/OtherCerts/empty.pem"
59+ } ) ;
60+ return null ;
61+ } ) ;
62+
63+ Assert . That ( ae , Is . Not . Null ) ;
64+ Assert . That ( ae . Message , Does . Match ( "Certificate file '.*' is empty" ) ) ;
65+ return Task . CompletedTask ;
66+ }
67+
68+ [ Test ]
69+ public Task InvalidCertificateFile ( )
70+ {
71+ try
72+ {
73+ _client = new InfluxDBClient ( new ClientConfig
74+ {
75+ Host = MockHttpsServerUrl ,
76+ Token = "my-token" ,
77+ Organization = "my-org" ,
78+ Database = "my-database" ,
79+ DisableServerCertificateValidation = false ,
80+ DisableCertificateRevocationListCheck = true ,
81+ SslRootsFilePath = "./TestData/OtherCerts/invalid.pem"
82+ } ) ;
83+ }
84+ catch ( Exception e )
85+ {
86+ Assert . That ( e , Is . Not . Null ) ;
87+ Assert . That ( e . Message , Does . Match ( "Failed to import custom certificates" ) ) ;
88+ }
89+
90+ return Task . CompletedTask ;
91+ }
92+
93+ [ Test ]
94+ public async Task WriteWithValidSslRootCertificate ( )
95+ {
96+ _client = new InfluxDBClient ( new ClientConfig
97+ {
98+ Host = MockHttpsServerUrl ,
99+ Token = "my-token" ,
100+ Organization = "my-org" ,
101+ Database = "my-database" ,
102+ DisableServerCertificateValidation = false ,
103+ DisableCertificateRevocationListCheck = true ,
104+ SslRootsFilePath = "./TestData/ServerCert/rootCA.pem"
105+ } ) ;
106+
107+ await WriteData ( ) ;
108+
109+ var requests = MockHttpsServer . LogEntries . ToList ( ) ;
110+ Assert . That ( requests [ 0 ] . RequestMessage . BodyData ? . BodyAsString , Is . EqualTo ( "mem,tag=a field=1" ) ) ;
111+ }
112+
113+ [ Test ]
114+ public async Task WriteWithDisabledCertificates ( )
115+ {
116+ _client = new InfluxDBClient ( new ClientConfig
117+ {
118+ Host = MockHttpsServerUrl ,
119+ Token = "my-token" ,
120+ Organization = "my-org" ,
121+ Database = "my-database" ,
122+ DisableServerCertificateValidation = true ,
123+ } ) ;
124+
125+ await WriteData ( ) ;
126+
127+ var requests = MockHttpsServer . LogEntries . ToList ( ) ;
128+ Assert . That ( requests [ 0 ] . RequestMessage . BodyData ? . BodyAsString , Is . EqualTo ( "mem,tag=a field=1" ) ) ;
129+ }
130+
131+ [ Test ]
132+ public Task WriteWithOtherSslRootCertificate ( )
133+ {
134+ _client = new InfluxDBClient ( new ClientConfig
135+ {
136+ Host = MockHttpsServerUrl ,
137+ Token = "my-token" ,
138+ Organization = "my-org" ,
139+ Database = "my-database" ,
140+ DisableServerCertificateValidation = false ,
141+ DisableCertificateRevocationListCheck = true ,
142+ SslRootsFilePath = "./TestData/OtherCerts/otherCA.pem"
143+ } ) ;
144+
145+ var ae = Assert . ThrowsAsync < HttpRequestException > ( async ( ) =>
146+ {
147+ await _client . WriteRecordAsync ( "mem,tag=a field=1" ) ;
148+ } ) ;
149+
150+ Assert . That ( ae , Is . Not . Null ) ;
151+ Assert . That ( ae . Message , Does . Contain ( "The SSL connection could not be established" ) ) ;
152+ Assert . That ( ae . InnerException ? . Message ,
153+ Does . Contain ( "The remote certificate was rejected by the provided RemoteCertificateValidationCallback" ) ) ;
154+ return Task . CompletedTask ;
155+ }
156+
157+ [ Test ]
158+ public Task QueryWithValidSslRootCertificate ( )
159+ {
160+ _client = new InfluxDBClient ( new ClientConfig
161+ {
162+ Host = MockHttpsServerUrl ,
163+ Token = "my-token" ,
164+ Organization = "my-org" ,
165+ Database = "my-database" ,
166+ DisableServerCertificateValidation = false ,
167+ DisableCertificateRevocationListCheck = true ,
168+ SslRootsFilePath = "./TestData/ServerCert/rootCA.pem"
169+ } ) ;
170+
171+ var ae = Assert . ThrowsAsync < RpcException > ( async ( ) => { await QueryData ( ) ; } ) ;
172+
173+ // Verify: server successfully sent back the configured 404 status
174+ Assert . That ( ae , Is . Not . Null ) ;
175+ Assert . That ( ae . Message , Does . Contain ( "Bad gRPC response. HTTP status code: 404" ) ) ;
176+
177+ // Verify: the request reached the server
178+ var requests = MockHttpsServer . LogEntries . ToList ( ) ;
179+ Assert . That ( requests [ 0 ] . RequestMessage . BodyData ? . BodyAsString , Does . Contain ( "SELECT 1" ) ) ;
180+ return Task . CompletedTask ;
181+ }
182+
183+ [ Test ]
184+ public Task QueryWithDisabledCertificates ( )
185+ {
186+ _client = new InfluxDBClient ( new ClientConfig
187+ {
188+ Host = MockHttpsServerUrl ,
189+ Token = "my-token" ,
190+ Organization = "my-org" ,
191+ Database = "my-database" ,
192+ DisableServerCertificateValidation = true ,
193+ } ) ;
194+
195+ var ae = Assert . ThrowsAsync < RpcException > ( async ( ) => { await QueryData ( ) ; } ) ;
196+
197+ // Verify: server successfully sent back the configured 404 status
198+ Assert . That ( ae , Is . Not . Null ) ;
199+ Assert . That ( ae . Message , Does . Contain ( "Bad gRPC response. HTTP status code: 404" ) ) ;
200+
201+ // Verify: the request reached the server
202+ var requests = MockHttpsServer . LogEntries . ToList ( ) ;
203+ Assert . That ( requests [ 0 ] . RequestMessage . BodyData ? . BodyAsString , Does . Contain ( "SELECT 1" ) ) ;
204+ return Task . CompletedTask ;
205+ }
206+
207+ [ Test ]
208+ public Task QueryWithOtherSslRootCertificate ( )
209+ {
210+ _client = new InfluxDBClient ( new ClientConfig
211+ {
212+ Host = MockHttpsServerUrl ,
213+ Token = "my-token" ,
214+ Organization = "my-org" ,
215+ Database = "my-database" ,
216+ DisableServerCertificateValidation = false ,
217+ DisableCertificateRevocationListCheck = true ,
218+ SslRootsFilePath = "./TestData/OtherCerts/otherCA.pem"
219+ } ) ;
220+
221+ var ae = Assert . ThrowsAsync < RpcException > ( async ( ) => { await QueryData ( ) ; } ) ;
222+
223+ // Verify: the SSL connection was not established
224+ Assert . That ( ae , Is . Not . Null ) ;
225+ Assert . That ( ae . Message , Does . Contain ( "The SSL connection could not be established" ) ) ;
226+
227+ // Verify: the request did not reach the server
228+ var requests = MockHttpsServer . LogEntries . ToList ( ) ;
229+ Assert . That ( requests , Is . Empty ) ;
230+ return Task . CompletedTask ;
231+ }
232+
233+ private async Task WriteData ( )
234+ {
235+ MockHttpsServer
236+ . Given ( Request . Create ( ) . WithPath ( "/api/v2/write" ) . UsingPost ( ) )
237+ . RespondWith ( Response . Create ( ) . WithStatusCode ( 204 ) ) ;
238+
239+ await _client . WriteRecordAsync ( "mem,tag=a field=1" ) ;
240+ }
241+
242+
243+ private async Task QueryData ( )
244+ {
245+ // Setup mock server: return 404 for simplicity, so we don't have to implement a valid response.
246+ MockHttpsServer
247+ . Given ( Request . Create ( ) . WithPath ( "/arrow.flight.protocol.FlightService/DoGet" ) . UsingPost ( ) )
248+ . RespondWith ( Response . Create ( )
249+ . WithStatusCode ( 404 )
250+ ) ;
251+
252+ // Query data.
253+ var query = "SELECT 1" ;
254+ await _client . Query ( query ) . ToListAsync ( ) ;
255+ }
256+ }
0 commit comments