1313// limitations under the License.
1414
1515using System . Data ;
16+ using Google . Cloud . SpannerLib ;
17+ using Google . Cloud . SpannerLib . MockServer ;
18+ using Google . Rpc ;
19+ using Grpc . Core ;
20+ using Status = Grpc . Core . Status ;
1621
1722namespace Google . Cloud . Spanner . DataProvider . Tests ;
1823
19- public class ConnectionStringBuilderTests
24+ public class ConnectionStringBuilderTests : AbstractMockServerTests
2025{
2126 [ Test ]
2227 public void Basic ( )
@@ -167,5 +172,126 @@ public void PropertiesToConnectionString()
167172 Assert . That ( builder . ConnectionString , Is . EqualTo ( "Data Source=projects/project1/instances/instance1/databases/database1;Host=localhost;Port=80;UsePlainText=True;DefaultIsolationLevel=RepeatableRead" ) ) ;
168173 Assert . That ( builder . SpannerLibConnectionString , Is . EqualTo ( "localhost:80/projects/project1/instances/instance1/databases/database1;UsePlainText=True;DefaultIsolationLevel=RepeatableRead" ) ) ;
169174 }
175+
176+ [ Test ]
177+ public void RequiredConnectionStringProperties ( )
178+ {
179+ using var connection = new SpannerConnection ( ) ;
180+ Assert . Throws < ArgumentException > ( ( ) => connection . ConnectionString = "Host=localhost;Port=80" ) ;
181+ }
182+
183+ [ Test ]
184+ public void FailedConnectThenSucceed ( )
185+ {
186+ // Close all current pools to ensure that we get a fresh pool.
187+ SpannerPool . CloseSpannerLib ( ) ;
188+ // TODO: Make this a public property in the mock server.
189+ const string detectDialectQuery =
190+ "select option_value from information_schema.database_options where option_name='database_dialect'" ;
191+ Fixture . SpannerMock . AddOrUpdateStatementResult ( detectDialectQuery , StatementResult . CreateException ( new RpcException ( new Status ( StatusCode . NotFound , "Database not found" ) ) ) ) ;
192+ using var conn = new SpannerConnection ( ) ;
193+ conn . ConnectionString = ConnectionString ;
194+ var exception = Assert . Throws < SpannerException > ( ( ) => conn . Open ( ) ) ;
195+ Assert . That ( exception . Code , Is . EqualTo ( Code . NotFound ) ) ;
196+ Assert . That ( conn . State , Is . EqualTo ( ConnectionState . Closed ) ) ;
197+
198+ // Remove the error and retry.
199+ Fixture . SpannerMock . AddOrUpdateStatementResult ( detectDialectQuery , StatementResult . CreateResultSet ( new List < Tuple < Google . Cloud . Spanner . V1 . TypeCode , string > >
200+ {
201+ Tuple . Create < Google . Cloud . Spanner . V1 . TypeCode , string > ( V1 . TypeCode . String , "option_value" )
202+ } , new List < object [ ] >
203+ {
204+ new object [ ] { "GOOGLE_STANDARD_SQL" }
205+ } ) ) ;
206+ conn . Open ( ) ;
207+ Assert . That ( conn . State , Is . EqualTo ( ConnectionState . Open ) ) ;
208+ }
209+
210+ [ Test ]
211+ [ Ignore ( "Needs connect_timeout property" ) ]
212+ public void OpenTimeout ( )
213+ {
214+ // TODO: Add connect_timeout property.
215+ var builder = new SpannerConnectionStringBuilder
216+ {
217+ Host = Fixture . Host ,
218+ Port = ( uint ) Fixture . Port ,
219+ UsePlainText = true ,
220+ DataSource = "projects/project1/instances/instance1/databases/database1" ,
221+ //ConnectTimeout = TimeSpan.FromMicroseconds(1),
222+ } ;
223+ using var connection = new SpannerConnection ( ) ;
224+ connection . ConnectionString = builder . ConnectionString ;
225+ var exception = Assert . Throws < SpannerDbException > ( ( ) => connection . Open ( ) ) ;
226+ Assert . That ( exception . ErrorCode , Is . EqualTo ( ( int ) Code . DeadlineExceeded ) ) ;
227+ }
228+
229+ [ Test ]
230+ [ Ignore ( "OpenAsync must be implemented" ) ]
231+ public async Task OpenCancel ( )
232+ {
233+ // Close all current pools to ensure that we get a fresh pool.
234+ SpannerPool . CloseSpannerLib ( ) ;
235+ Fixture . SpannerMock . AddOrUpdateExecutionTime ( nameof ( Fixture . SpannerMock . CreateSession ) , ExecutionTime . FromMillis ( 20 , 0 ) ) ;
236+ var builder = new SpannerConnectionStringBuilder
237+ {
238+ Host = Fixture . Host ,
239+ Port = ( uint ) Fixture . Port ,
240+ UsePlainText = true ,
241+ DataSource = "projects/project1/instances/instance1/databases/database1" ,
242+ } ;
243+ await using var connection = new SpannerConnection ( ) ;
244+ connection . ConnectionString = builder . ConnectionString ;
245+ var tokenSource = new CancellationTokenSource ( 5 ) ;
246+ // TODO: Implement actual async opening of connections
247+ Assert . ThrowsAsync < OperationCanceledException > ( async ( ) => await connection . OpenAsync ( tokenSource . Token ) ) ;
248+ Assert . That ( connection . State , Is . EqualTo ( ConnectionState . Closed ) ) ;
249+ }
250+
251+ [ Test ]
252+ public void DataSourceProperty ( )
253+ {
254+ using var conn = new SpannerConnection ( ) ;
255+ Assert . That ( conn . DataSource , Is . EqualTo ( string . Empty ) ) ;
256+
257+ var builder = new SpannerConnectionStringBuilder ( ConnectionString ) ;
258+
259+ conn . ConnectionString = builder . ConnectionString ;
260+ Assert . That ( conn . DataSource , Is . EqualTo ( "projects/p1/instances/i1/databases/d1" ) ) ;
261+ }
262+
263+ [ Test ]
264+ public void SettingConnectionStringWhileOpenThrows ( )
265+ {
266+ using var conn = new SpannerConnection ( ) ;
267+ conn . ConnectionString = ConnectionString ;
268+ conn . Open ( ) ;
269+ Assert . That ( ( ) => conn . ConnectionString = "" , Throws . Exception . TypeOf < InvalidOperationException > ( ) ) ;
270+ }
271+
272+ [ Test ]
273+ public void EmptyConstructor ( )
274+ {
275+ var conn = new SpannerConnection ( ) ;
276+ Assert . That ( conn . ConnectionTimeout , Is . EqualTo ( 15 ) ) ;
277+ Assert . That ( conn . ConnectionString , Is . SameAs ( string . Empty ) ) ;
278+ Assert . That ( ( ) => conn . Open ( ) , Throws . Exception . TypeOf < InvalidOperationException > ( ) ) ;
279+ }
280+
281+ [ Test ]
282+ public void Constructor_with_null_connection_string ( )
283+ {
284+ var conn = new SpannerConnection ( null ) ;
285+ Assert . That ( conn . ConnectionString , Is . SameAs ( string . Empty ) ) ;
286+ Assert . That ( ( ) => conn . Open ( ) , Throws . Exception . TypeOf < InvalidOperationException > ( ) ) ;
287+ }
288+
289+ [ Test ]
290+ public void Constructor_with_empty_connection_string ( )
291+ {
292+ var conn = new NpgsqlConnection ( "" ) ;
293+ Assert . That ( conn . ConnectionString , Is . SameAs ( string . Empty ) ) ;
294+ Assert . That ( ( ) => conn . Open ( ) , Throws . Exception . TypeOf < InvalidOperationException > ( ) ) ;
295+ }
170296
171297}
0 commit comments