@@ -2,6 +2,7 @@ package dumper
22
33import (
44 "context"
5+ "os"
56 "testing"
67
78 qt "github.com/frankban/quicktest"
@@ -47,3 +48,186 @@ func TestLoader(t *testing.T) {
4748 err = loader .Run (context .Background ())
4849 c .Assert (err , qt .IsNil )
4950}
51+
52+ func TestRestoreTableSchema_WithComments (t * testing.T ) {
53+ tests := []struct {
54+ name string
55+ schemaContent string
56+ setupQueries []string
57+ description string
58+ }{
59+ {
60+ name : "schema with line comments at end" ,
61+ schemaContent : `CREATE TABLE example_table (
62+ id INT PRIMARY KEY
63+ );
64+ -- This is a comment
65+ -- This is another comment` ,
66+ setupQueries : []string {
67+ "CREATE TABLE example_table (\n id INT PRIMARY KEY\n )" ,
68+ },
69+ description : "Should execute CREATE TABLE and skip trailing comments" ,
70+ },
71+ {
72+ name : "schema with ALTER TABLE after comments" ,
73+ schemaContent : `CREATE TABLE example_table (
74+ id INT PRIMARY KEY,
75+ name VARCHAR(100)
76+ );
77+ -- This is a comment
78+ -- This is another comment
79+ ALTER TABLE example_table
80+ ADD INDEX idx_name (name);` ,
81+ setupQueries : []string {
82+ "CREATE TABLE example_table (\n id INT PRIMARY KEY,\n name VARCHAR(100)\n )" ,
83+ },
84+ description : "Should execute CREATE TABLE and ALTER TABLE, skipping comments in between" ,
85+ },
86+ {
87+ name : "schema with block comments" ,
88+ schemaContent : `/* This is a block comment */
89+ CREATE TABLE example_table (
90+ id INT PRIMARY KEY
91+ );` ,
92+ setupQueries : []string {
93+ "CREATE TABLE example_table (\n id INT PRIMARY KEY\n )" ,
94+ },
95+ description : "Should skip block comments and execute CREATE TABLE" ,
96+ },
97+ {
98+ name : "schema with interspersed comments" ,
99+ schemaContent : `CREATE TABLE example_table (
100+ id INT PRIMARY KEY
101+ );
102+ -- Comment between statements
103+ ALTER TABLE example_table ADD COLUMN name VARCHAR(100);
104+ -- Another comment
105+ ALTER TABLE example_table ADD INDEX idx_id (id);` ,
106+ setupQueries : []string {
107+ "CREATE TABLE example_table (\n id INT PRIMARY KEY\n )" ,
108+ },
109+ description : "Should execute all SQL statements and skip all comment lines" ,
110+ },
111+ }
112+
113+ for _ , tt := range tests {
114+ t .Run (tt .name , func (t * testing.T ) {
115+ c := qt .New (t )
116+
117+ log := xlog .NewStdLog (xlog .Level (xlog .ERROR ))
118+ fakedbs := driver .NewTestHandler (log )
119+ server , err := driver .MockMysqlServer (log , fakedbs )
120+ c .Assert (err , qt .IsNil )
121+ defer server .Close ()
122+
123+ address := server .Addr ()
124+
125+ // Set up mock expectations
126+ fakedbs .AddQueryPattern ("use .*" , & sqltypes.Result {})
127+ fakedbs .AddQueryPattern ("set foreign_key_checks=.*" , & sqltypes.Result {})
128+ fakedbs .AddQueryPattern ("drop table .*" , & sqltypes.Result {})
129+ fakedbs .AddQueryPattern ("alter table .*" , & sqltypes.Result {})
130+
131+ // Add expected queries - if these aren't executed, the test will fail
132+ for _ , query := range tt .setupQueries {
133+ fakedbs .AddQuery (query , & sqltypes.Result {})
134+ }
135+
136+ // Create test schema file
137+ tempDir := c .TempDir ()
138+ schemaFile := tempDir + "/testdb.test_table-schema.sql"
139+ err = os .WriteFile (schemaFile , []byte (tt .schemaContent ), 0644 )
140+ c .Assert (err , qt .IsNil )
141+
142+ // Create loader
143+ cfg := & Config {
144+ Database : "testdb" ,
145+ Outdir : tempDir ,
146+ User : "mock" ,
147+ Password : "mock" ,
148+ Threads : 1 ,
149+ Address : address ,
150+ IntervalMs : 500 ,
151+ OverwriteTables : true ,
152+ ShowDetails : false ,
153+ Debug : false ,
154+ }
155+ loader , err := NewLoader (cfg )
156+ c .Assert (err , qt .IsNil )
157+
158+ // Create connection pool
159+ pool , err := NewPool (loader .log , cfg .Threads , cfg .Address , cfg .User , cfg .Password , cfg .SessionVars , "" )
160+ c .Assert (err , qt .IsNil )
161+ defer pool .Close ()
162+
163+ conn := pool .Get ()
164+ defer pool .Put (conn )
165+
166+ // Execute restoreTableSchema - should not return error if all expected queries are executed
167+ err = loader .restoreTableSchema (cfg .OverwriteTables , []string {schemaFile }, conn )
168+ c .Assert (err , qt .IsNil , qt .Commentf ("%s: failed to restore table schema" , tt .description ))
169+ })
170+ }
171+ }
172+
173+ func TestRestoreTableSchema_DropTableCalledOnce (t * testing.T ) {
174+ c := qt .New (t )
175+
176+ log := xlog .NewStdLog (xlog .Level (xlog .ERROR ))
177+ fakedbs := driver .NewTestHandler (log )
178+ server , err := driver .MockMysqlServer (log , fakedbs )
179+ c .Assert (err , qt .IsNil )
180+ defer server .Close ()
181+
182+ address := server .Addr ()
183+
184+ // Set up mock expectations
185+ fakedbs .AddQueryPattern ("use .*" , & sqltypes.Result {})
186+ fakedbs .AddQueryPattern ("set foreign_key_checks=.*" , & sqltypes.Result {})
187+
188+ // Add DROP TABLE query only once - if it's called twice, the second call will fail
189+ // because there's no matching handler for it
190+ fakedbs .AddQuery ("DROP TABLE IF EXISTS `testdb`.`test_table`" , & sqltypes.Result {})
191+ fakedbs .AddQuery ("CREATE TABLE test_table (\n id INT PRIMARY KEY\n )" , & sqltypes.Result {})
192+
193+ // Create test schema file with comments at the end (the original bug scenario)
194+ tempDir := c .TempDir ()
195+ schemaFile := tempDir + "/testdb.test_table-schema.sql"
196+ schemaContent := `CREATE TABLE test_table (
197+ id INT PRIMARY KEY
198+ );
199+ -- This is a comment
200+ -- This is another comment`
201+ err = os .WriteFile (schemaFile , []byte (schemaContent ), 0644 )
202+ c .Assert (err , qt .IsNil )
203+
204+ // Create loader
205+ cfg := & Config {
206+ Database : "testdb" ,
207+ Outdir : tempDir ,
208+ User : "mock" ,
209+ Password : "mock" ,
210+ Threads : 1 ,
211+ Address : address ,
212+ IntervalMs : 500 ,
213+ OverwriteTables : true ,
214+ ShowDetails : false ,
215+ Debug : false ,
216+ }
217+ loader , err := NewLoader (cfg )
218+ c .Assert (err , qt .IsNil )
219+
220+ // Create connection pool
221+ pool , err := NewPool (loader .log , cfg .Threads , cfg .Address , cfg .User , cfg .Password , cfg .SessionVars , "" )
222+ c .Assert (err , qt .IsNil )
223+ defer pool .Close ()
224+
225+ conn := pool .Get ()
226+ defer pool .Put (conn )
227+
228+ // Execute restoreTableSchema
229+ // If DROP TABLE is called more than once, the test will fail because there's
230+ // only one handler registered for it
231+ err = loader .restoreTableSchema (cfg .OverwriteTables , []string {schemaFile }, conn )
232+ c .Assert (err , qt .IsNil , qt .Commentf ("DROP TABLE should be called exactly once. If called multiple times, this test will fail." ))
233+ }
0 commit comments