1+ using Microsoft . Data . Sqlite ;
2+ using Microsoft . Extensions . Logging . Abstractions ;
3+ using Cosmos . DataTransfer . Interfaces ;
4+ using Cosmos . DataTransfer . Common ;
5+ using Cosmos . DataTransfer . Common . UnitTests ;
6+
7+ namespace Cosmos . DataTransfer . SqlServerExtension . UnitTests ;
8+
9+ [ TestClass ]
10+ public class SqlServerDataSourceExtensionTests
11+ {
12+
13+ private static async Task < Func < string , ValueTask < System . Data . Common . DbConnection > > > connectionFactory ( CancellationToken cancellationToken = default ( CancellationToken ) ) {
14+ var connection = new SqliteConnection ( "" ) ;
15+ await connection . OpenAsync ( cancellationToken ) ;
16+
17+ var cmd = connection . CreateCommand ( ) ;
18+ cmd . CommandText = @"CREATE TABLE foobar (
19+ id INTEGER NOT NULL,
20+ name TEXT
21+ );" ;
22+ await cmd . ExecuteNonQueryAsync ( cancellationToken ) ;
23+ cmd . CommandText = @"INSERT INTO foobar (id, name)
24+ VALUES (1, 'zoo');" ;
25+ await cmd . ExecuteNonQueryAsync ( cancellationToken ) ;
26+ cmd . CommandText = @"INSERT INTO foobar (id, name)
27+ VALUES (2, NULL);" ;
28+ await cmd . ExecuteNonQueryAsync ( cancellationToken ) ;
29+
30+ var func = ( string connectionString ) => {
31+ return new ValueTask < System . Data . Common . DbConnection > ( connection ) ;
32+ } ;
33+
34+ return func ;
35+ }
36+
37+ [ TestMethod ]
38+ public async Task TestReadAsync_QueryText ( ) {
39+ var extension = new SqlServerDataSourceExtension ( ) ;
40+ var config = TestHelpers . CreateConfig ( new Dictionary < string , string > {
41+ { "ConnectionString" , "Sqlite" } ,
42+ { "QueryText" , "SELECT * FROM foobar" }
43+ } ) ;
44+ Assert . AreEqual ( "SqlServer" , extension . DisplayName ) ;
45+
46+ var cancellationToken = new CancellationTokenSource ( 500 ) ;
47+
48+ var result = await extension . ReadAsync ( config , NullLogger . Instance , await connectionFactory ( cancellationToken . Token ) , cancellationToken . Token ) . ToListAsync ( ) ;
49+ var expected = new List < DictionaryDataItem > {
50+ new DictionaryDataItem ( new Dictionary < string , object ? > { { "id" , ( long ) 1 } , { "name" , "zoo" } } ) ,
51+ new DictionaryDataItem ( new Dictionary < string , object ? > { { "id" , ( long ) 2 } , { "name" , null } } )
52+ } ;
53+ CollectionAssert . That . AreEqual ( expected , result , new DataItemComparer ( ) ) ;
54+ }
55+
56+ [ TestMethod ]
57+ public async Task TestReadAsync_FromFile ( ) {
58+ var outputFile = Path . GetTempFileName ( ) ;
59+ await File . WriteAllTextAsync ( outputFile , "SELECT * FROM foobar;" ) ;
60+ var extension = new SqlServerDataSourceExtension ( ) ;
61+ var config = TestHelpers . CreateConfig ( new Dictionary < string , string > {
62+ { "ConnectionString" , "Sqlite" } ,
63+ { "FilePath" , outputFile }
64+ } ) ;
65+
66+
67+ var cancellationToken = new CancellationTokenSource ( 500 ) ;
68+
69+ var result = await extension . ReadAsync ( config , NullLogger . Instance , await connectionFactory ( cancellationToken . Token ) , cancellationToken . Token ) . ToListAsync ( ) ;
70+ var expected = new List < DictionaryDataItem > {
71+ new DictionaryDataItem ( new Dictionary < string , object ? > { { "id" , ( long ) 1 } , { "name" , "zoo" } } ) ,
72+ new DictionaryDataItem ( new Dictionary < string , object ? > { { "id" , ( long ) 2 } , { "name" , null } } )
73+ } ;
74+ CollectionAssert . That . AreEqual ( expected , result , new DataItemComparer ( ) ) ;
75+ }
76+
77+ // Allows for testing against an actual SQL Server by specifying a
78+ // connectionstring in either a .runsettings-file or environment variable.
79+ // Example: Using sql.runsettings
80+ // <?xml version="1.0" encoding="utf-8"?>
81+ // <RunSettings>
82+ // <TestRunParameters>
83+ // <Parameter name="TestReadAsync_LiveSqlServer_ConnectionString" value="<Your connection string>" />
84+ // </TestRunParameters>
85+ // </RunSettings>
86+ // run test with dotnet test --settings sql.runsettings
87+ #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
88+ public TestContext TestContext { get ; set ; }
89+ #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
90+ [ TestMethod ]
91+ [ Timeout ( 1000 ) ]
92+ public async Task TestReadAsync_LiveSqlServer ( ) {
93+ var connectionString = ( string ? ) TestContext . Properties [ "TestReadAsync_LiveSqlServer_ConnectionString" ] ;
94+ connectionString ??= Environment . GetEnvironmentVariable ( "TestReadAsync_LiveSqlServer_ConnectionString" ) ;
95+ if ( connectionString is null ) {
96+ Assert . Inconclusive ( "Could not run, as no connection string to live SQL Server was provided." ) ;
97+ }
98+
99+ var extension = new SqlServerDataSourceExtension ( ) ;
100+ var config = TestHelpers . CreateConfig ( new Dictionary < string , string > {
101+ { "ConnectionString" , connectionString ! } ,
102+ { "QueryText" , "SELECT 1, 'foo' as bar, NULL as zoo;" }
103+ } ) ;
104+
105+ var result = await extension . ReadAsync ( config , NullLogger . Instance ) . FirstAsync ( ) ;
106+
107+ Assert . IsTrue ( new DataItemComparer ( ) . Equals ( result ,
108+ new DictionaryDataItem ( new Dictionary < string , object ? > {
109+ { "" , 1 } ,
110+ { "bar" , "foo" } ,
111+ { "zoo" , null }
112+ } ) ) ) ;
113+ }
114+ }
0 commit comments