1+ using Respawn . Graph ;
2+ using Shouldly ;
3+ using Snowflake . Data . Client ;
4+ using System . Threading . Tasks ;
5+ using Xunit ;
6+ using Xunit . Abstractions ;
7+
8+ namespace Respawn . DatabaseTests
9+ {
10+ public class SnowflakeTests : IAsyncLifetime
11+ {
12+ private readonly ITestOutputHelper _output ;
13+ private SnowflakeDbConnection _connection ;
14+
15+ public SnowflakeTests ( ITestOutputHelper output ) => _output = output ;
16+
17+ public Task DisposeAsync ( )
18+ {
19+ _connection ? . Close ( ) ;
20+ _connection ? . Dispose ( ) ;
21+ _connection = null ;
22+ return Task . FromResult ( 0 ) ;
23+ }
24+
25+ public async Task InitializeAsync ( )
26+ {
27+ var rootconnString = "account=YOUR_ACCOUNT;user=YOUR_USER;password=YOUR_PASSWORD;" ;
28+
29+ await using ( var connection = new SnowflakeDbConnection ( rootconnString ) )
30+ {
31+ await connection . OpenAsync ( ) ;
32+
33+ var dropDbCommand = connection . CreateCommand ( ) ;
34+ dropDbCommand . CommandText = "DROP DATABASE IF EXISTS MYTESTDB" ;
35+ await dropDbCommand . ExecuteNonQueryAsync ( ) ;
36+
37+ var createDbCommand = connection . CreateCommand ( ) ;
38+ createDbCommand . CommandText = "CREATE DATABASE MYTESTDB" ;
39+ await createDbCommand . ExecuteNonQueryAsync ( ) ;
40+
41+ var createSchemaCommand = connection . CreateCommand ( ) ;
42+ createSchemaCommand . CommandText = "CREATE SCHEMA MYTESTSCHEMA" ;
43+ await createSchemaCommand . ExecuteNonQueryAsync ( ) ;
44+ }
45+
46+ _connection = new SnowflakeDbConnection ( rootconnString + "db=MYTESTDB;schema=MYTESTSCHEMA;" ) ;
47+ await _connection . OpenAsync ( ) ;
48+ }
49+
50+ private async Task ExecuteNonQueryAsync ( string commandText )
51+ {
52+ using ( var command = _connection . CreateCommand ( ) )
53+ {
54+ command . CommandText = commandText ;
55+ await command . ExecuteNonQueryAsync ( ) ;
56+ }
57+ }
58+
59+ [ SkipOnCI ]
60+ public async Task ShouldDeleteData ( )
61+ {
62+ await ExecuteNonQueryAsync ( "CREATE OR REPLACE TABLE foo (value INT)" ) ;
63+
64+ for ( int i = 0 ; i < 10 ; i ++ )
65+ {
66+ await InsertDataAsync ( "foo" , i ) ;
67+ }
68+
69+ long countBeforeReset = await CountRowsAsync ( "foo" ) ;
70+ countBeforeReset . ShouldBe ( 10L ) ;
71+
72+ var checkpoint = await Respawner . CreateAsync ( _connection , new RespawnerOptions
73+ {
74+ DbAdapter = DbAdapter . Snowflake
75+ } ) ;
76+
77+ await checkpoint . ResetAsync ( _connection ) ;
78+
79+ long countAfterReset = await CountRowsAsync ( "foo" ) ;
80+ countAfterReset . ShouldBe ( 0L ) ;
81+ }
82+
83+ [ SkipOnCI ]
84+ public async Task ShouldIgnoreTables ( )
85+ {
86+ await CreateTableAsync ( "Foo" ) ;
87+ await CreateTableAsync ( "Bar" ) ;
88+
89+ for ( int i = 0 ; i < 10 ; i ++ )
90+ {
91+ await InsertDataAsync ( "Foo" , i ) ;
92+ await InsertDataAsync ( "Bar" , i ) ;
93+ }
94+
95+ var checkpoint = await Respawner . CreateAsync ( _connection , new RespawnerOptions
96+ {
97+ DbAdapter = DbAdapter . Snowflake ,
98+ TablesToIgnore = new Table [ ] { "Foo" } ,
99+ SchemasToInclude = new [ ] { "MYTESTSCHEMA" }
100+ } ) ;
101+
102+ await checkpoint . ResetAsync ( _connection ) ;
103+
104+ long countFoo = await CountRowsAsync ( "Foo" ) ;
105+ countFoo . ShouldBe ( 10 ) ;
106+
107+ long countBar = await CountRowsAsync ( "Bar" ) ;
108+ countBar . ShouldBe ( 0L ) ;
109+ }
110+
111+ [ SkipOnCI ]
112+ public async Task ShouldIgnoreTablesIfSchemaSpecified ( )
113+ {
114+ await ExecuteNonQueryAsync ( "DROP SCHEMA IF EXISTS eggs" ) ;
115+ await ExecuteNonQueryAsync ( "CREATE SCHEMA eggs" ) ;
116+
117+ await ExecuteNonQueryAsync ( "CREATE TABLE eggs.foo (Value INT)" ) ;
118+ await ExecuteNonQueryAsync ( "CREATE TABLE eggs.bar (Value INT)" ) ;
119+
120+ for ( int i = 0 ; i < 10 ; i ++ )
121+ {
122+ await InsertDataAsync ( "eggs.foo" , i ) ;
123+ await InsertDataAsync ( "eggs.bar" , i ) ;
124+ }
125+
126+ var checkpoint = await Respawner . CreateAsync ( _connection , new RespawnerOptions
127+ {
128+ DbAdapter = DbAdapter . Snowflake ,
129+ TablesToIgnore = new Table [ ] { new Table ( "eggs" , "foo" ) }
130+ } ) ;
131+
132+ await checkpoint . ResetAsync ( _connection ) ;
133+
134+ long countFoo = await CountRowsAsync ( "eggs.foo" ) ;
135+ countFoo . ShouldBe ( 10L ) ;
136+
137+ long countBar = await CountRowsAsync ( "eggs.bar" ) ;
138+ countBar . ShouldBe ( 0L ) ;
139+ }
140+
141+ [ SkipOnCI ]
142+ public async Task ShouldIncludeTables ( )
143+ {
144+ await CreateTableAsync ( "Foo" ) ;
145+ await CreateTableAsync ( "Bar" ) ;
146+
147+ for ( int i = 0 ; i < 10 ; i ++ )
148+ {
149+ await InsertDataAsync ( "foo" , i ) ;
150+ await InsertDataAsync ( "bar" , i ) ;
151+ }
152+
153+ var checkpoint = await Respawner . CreateAsync ( _connection , new RespawnerOptions
154+ {
155+ DbAdapter = DbAdapter . Snowflake ,
156+ TablesToInclude = new Table [ ] { "foo" }
157+ } ) ;
158+ await checkpoint . ResetAsync ( _connection ) ;
159+
160+ long countFoo = await CountRowsAsync ( "Foo" ) ;
161+ countFoo . ShouldBe ( 0 ) ;
162+
163+ long countBar = await CountRowsAsync ( "Bar" ) ;
164+ countBar . ShouldBe ( 10L ) ;
165+ }
166+
167+ [ SkipOnCI ]
168+ public async Task ShouldIncludeTablesIfSchemaSpecified ( )
169+ {
170+ await ExecuteNonQueryAsync ( "DROP SCHEMA IF EXISTS eggs" ) ;
171+ await ExecuteNonQueryAsync ( "CREATE SCHEMA eggs" ) ;
172+
173+ await ExecuteNonQueryAsync ( "CREATE TABLE eggs.foo (Value INT)" ) ;
174+ await ExecuteNonQueryAsync ( "CREATE TABLE eggs.bar (Value INT)" ) ;
175+
176+ for ( int i = 0 ; i < 10 ; i ++ )
177+ {
178+ await InsertDataAsync ( "eggs.foo" , i ) ;
179+ await InsertDataAsync ( "eggs.bar" , i ) ;
180+ }
181+
182+ var checkpoint = await Respawner . CreateAsync ( _connection , new RespawnerOptions
183+ {
184+ DbAdapter = DbAdapter . Snowflake ,
185+ TablesToInclude = new Table [ ] { new Table ( "eggs" , "foo" ) }
186+ } ) ;
187+ await checkpoint . ResetAsync ( _connection ) ;
188+
189+ long countFoo = await CountRowsAsync ( "Foo" ) ;
190+ countFoo . ShouldBe ( 0 ) ;
191+
192+ long countBar = await CountRowsAsync ( "Bar" ) ;
193+ countBar . ShouldBe ( 10L ) ;
194+ }
195+
196+ [ SkipOnCI ]
197+ public async Task ShouldExcludeSchemas ( )
198+ {
199+ await ExecuteNonQueryAsync ( "CREATE SCHEMA a" ) ;
200+ await ExecuteNonQueryAsync ( "CREATE SCHEMA b" ) ;
201+
202+ await ExecuteNonQueryAsync ( "CREATE TABLE a.foo (Value INT)" ) ;
203+ await ExecuteNonQueryAsync ( "CREATE TABLE b.bar (Value INT)" ) ;
204+
205+ for ( int i = 0 ; i < 10 ; i ++ )
206+ {
207+ await InsertDataAsync ( "a.foo" , i ) ;
208+ await InsertDataAsync ( "b.bar" , i ) ;
209+ }
210+
211+ var checkpoint = await Respawner . CreateAsync ( _connection , new RespawnerOptions
212+ {
213+ DbAdapter = DbAdapter . Snowflake ,
214+ SchemasToExclude = new [ ] { "a" }
215+ } ) ;
216+
217+ await checkpoint . ResetAsync ( _connection ) ;
218+
219+ long countFoo = await CountRowsAsync ( "a.Foo" ) ;
220+ countFoo . ShouldBe ( 10L ) ;
221+
222+ long countBar = await CountRowsAsync ( "Bar" ) ;
223+ countBar . ShouldBe ( 0 ) ;
224+ }
225+
226+ [ SkipOnCI ]
227+ public async Task ShouldIncludeSchemas ( )
228+ {
229+ await ExecuteNonQueryAsync ( "CREATE SCHEMA a" ) ;
230+ await ExecuteNonQueryAsync ( "CREATE SCHEMA b" ) ;
231+
232+ await ExecuteNonQueryAsync ( "CREATE TABLE a.foo (Value INT)" ) ;
233+ await ExecuteNonQueryAsync ( "CREATE TABLE b.bar (Value INT)" ) ;
234+
235+ for ( int i = 0 ; i < 10 ; i ++ )
236+ {
237+ await InsertDataAsync ( "a.foo" , i ) ;
238+ await InsertDataAsync ( "b.bar" , i ) ;
239+ }
240+
241+ var checkpoint = await Respawner . CreateAsync ( _connection , new RespawnerOptions
242+ {
243+ DbAdapter = DbAdapter . Snowflake ,
244+ SchemasToInclude = new [ ] { "b" }
245+ } ) ;
246+ await checkpoint . ResetAsync ( _connection ) ;
247+
248+ long countFoo = await CountRowsAsync ( "a.Foo" ) ;
249+ countFoo . ShouldBe ( 10L ) ;
250+
251+ long countBar = await CountRowsAsync ( "Bar" ) ;
252+ countBar . ShouldBe ( 0 ) ;
253+ }
254+
255+ private async Task InsertDataAsync ( string tableName , int value )
256+ {
257+ using ( var command = _connection . CreateCommand ( ) )
258+ {
259+ command . CommandText = $ "INSERT INTO { tableName } (Value) VALUES ({ value } )";
260+ await command . ExecuteNonQueryAsync ( ) ;
261+ }
262+ }
263+
264+ private async Task < long > CountRowsAsync ( string tableName )
265+ {
266+ using ( var command = _connection . CreateCommand ( ) )
267+ {
268+ command . CommandText = $ "SELECT COUNT(1) FROM { tableName } ";
269+ return ( long ) await command . ExecuteScalarAsync ( ) ;
270+ }
271+ }
272+
273+ private async Task CreateTableAsync ( string tableName )
274+ {
275+ using ( var command = _connection . CreateCommand ( ) )
276+ {
277+ command . CommandText = $ "CREATE TABLE { tableName } (value INT)";
278+ await command . ExecuteNonQueryAsync ( ) ;
279+ }
280+ }
281+ }
282+ }
0 commit comments