flydata 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -141,1164 +141,4 @@ module Flydata
141
141
  end
142
142
  end
143
143
  end
144
-
145
- module FileUtil
146
- describe SyncFileManager do
147
- let(:default_mysqldump_dir) do
148
- File.join('/tmp', "sync_dump_#{Time.now.to_i}")
149
- end
150
- let(:default_data_entry) do
151
- {"id"=>93,
152
- "name"=>"flydata_sync_mysql",
153
- "data_port_id"=>52,
154
- "display_name"=>"flydata_sync_mysql",
155
- "enabled"=>true,
156
- "heroku_log_type"=>nil,
157
- "heroku_resource_id"=>nil,
158
- "log_deletion"=>nil,
159
- "log_file_delimiter"=>nil,
160
- "log_file_type"=>nil,
161
- "log_path"=>nil,
162
- "redshift_schema_name"=>"",
163
- "redshift_table_name"=>nil,
164
- "created_at"=>"2014-01-22T18:58:43Z",
165
- "updated_at"=>"2014-01-30T02:42:26Z",
166
- "type"=>"RedshiftMysqlDataEntry",
167
- "tag_name"=>"flydata.a458c641_dp52.flydata_mysql",
168
- "tag_name_dev"=>"flydata.a458c641_dp52.flydata_mysql.dev",
169
- "data_port_key"=>"a458c641",
170
- "mysql_data_entry_preference" =>
171
- { "host"=>"localhost", "port"=>3306, "username"=>"masashi",
172
- "password"=>"welcome", "database"=>"sync_test", "tables"=>nil,
173
- "mysqldump_dir"=>default_mysqldump_dir, "forwarder" => "tcpforwarder",
174
- "data_servers"=>"localhost:9905" }
175
- }
176
- end
177
- let(:default_sfm) { SyncFileManager.new(default_data_entry) }
178
-
179
- let (:status) { 'PARSING' }
180
- let (:table_name) { 'test_table' }
181
- let (:last_pos) { 9999 }
182
- let (:binlog_pos) { {binfile: 'mysqlbin.00001', pos: 111} }
183
- let (:state) { 'CREATE_TABLE' }
184
- let (:substate) { nil }
185
-
186
- after :each do
187
- if Dir.exists?(default_mysqldump_dir)
188
- Dir.delete(default_mysqldump_dir) rescue nil
189
- end
190
- if File.exists?(default_mysqldump_dir)
191
- File.delete(default_mysqldump_dir) rescue nil
192
- end
193
- end
194
-
195
- describe '#dump_file_path' do
196
- context 'when mysqldump_dir param is nil' do
197
- before do
198
- default_data_entry['mysql_data_entry_preference'].delete('mysqldump_dir')
199
- end
200
- it do
201
- expect(default_sfm.dump_file_path).to eq(
202
- File.join(Flydata::FLYDATA_HOME, 'dump', 'flydata_sync_mysql.dump'))
203
- end
204
- end
205
- context 'when file exists' do
206
- before { `touch #{default_mysqldump_dir}`}
207
- it do
208
- expect{default_sfm.dump_file_path}.to raise_error
209
- end
210
- end
211
- context 'when directory exists' do
212
- before { `mkdir -p #{default_mysqldump_dir}`}
213
- it do
214
- expect(FileUtils).to receive(:mkdir_p).with(default_mysqldump_dir).never
215
- expect(default_sfm.dump_file_path).to eq(
216
- File.join(default_mysqldump_dir, 'flydata_sync_mysql.dump'))
217
- end
218
- end
219
- context 'when directory or file does not exist' do
220
- it do
221
- expect(FileUtils).to receive(:mkdir_p).with(default_mysqldump_dir).once
222
- expect(default_sfm.dump_file_path).to eq(
223
- File.join(default_mysqldump_dir, 'flydata_sync_mysql.dump'))
224
- end
225
- end
226
- context 'when file name includes "~"' do
227
- let(:default_mysqldump_dir) { "~/tmp/dump/sync_spec_#{Time.now.to_i}" }
228
- it do
229
- expected_dir = File.join(ENV['HOME'], default_mysqldump_dir[1..-1])
230
- expect(FileUtils).to receive(:mkdir_p).with(expected_dir).once
231
- expect(default_sfm.dump_file_path).to eq(
232
- File.join(expected_dir, 'flydata_sync_mysql.dump'))
233
- end
234
- end
235
- end
236
-
237
- describe '#dump_pos_path' do
238
- it { expect(default_sfm.dump_pos_path).to eq(
239
- File.join(default_mysqldump_dir, 'flydata_sync_mysql.dump.pos')) }
240
- end
241
-
242
- describe '#save_dump_pos' do
243
- context 'without mysql marshal data' do
244
- it do
245
- expect{default_sfm.save_dump_pos(
246
- status, table_name, last_pos, binlog_pos, state, substate)}.not_to raise_error
247
- expect(default_sfm.load_dump_pos).to eq({
248
- status: status, table_name: table_name, last_pos: last_pos,
249
- binlog_pos: binlog_pos, state: state, substate: substate,
250
- mysql_table: nil
251
- })
252
- end
253
- end
254
- end
255
-
256
- describe '#load_dump_pos' do
257
- let (:mysql_table) do
258
- Flydata::Mysql::MysqlTable.new(
259
- table_name, { 'id' => { format_type: 'int' }, 'value' => { format_type: 'text' } }
260
- )
261
- end
262
-
263
- context 'with mysql marshal data' do
264
- before do
265
- default_sfm.save_mysql_table_marshal_dump(mysql_table)
266
- default_sfm.save_dump_pos(status, table_name, last_pos, binlog_pos, state, substate)
267
- end
268
- it do
269
- ret = default_sfm.load_dump_pos
270
- mt = ret.delete(:mysql_table)
271
- expect(ret).to eq({
272
- status: status, table_name: table_name, last_pos: last_pos,
273
- binlog_pos: binlog_pos, state: state, substate: substate,
274
- })
275
- expect(mt.table_name).to eq(table_name)
276
- expect(mt.columns).to eq({
277
- 'id' => { format_type: 'int' },
278
- 'value' => { format_type: 'text' },
279
- })
280
- end
281
- end
282
- end
283
-
284
- describe '#save_binlog' do
285
- let(:binfile) { 'mysqlbinlog.000001' }
286
- let(:pos) { 107 }
287
- let(:binlog_pos) { {binfile: binfile, pos: pos} }
288
- it do
289
- default_sfm.save_binlog(binlog_pos)
290
- expect(`cat #{default_sfm.binlog_path}`).to eq("#{binfile}\t#{pos}")
291
- end
292
- end
293
-
294
- describe '#binlog_path' do
295
- it { expect(default_sfm.binlog_path).to eq("#{FLYDATA_HOME}/flydata_sync_mysql.binlog.pos") }
296
- end
297
- end
298
- end
299
-
300
- module Output
301
- describe ForwarderFactory do
302
- let(:forwarder) do
303
- ForwarderFactory.create('tcpforwarder', 'test_tag', ['localhost:3456', 'localhost:4567'])
304
- end
305
- before :each do
306
- conn = double(TCPSocket)
307
- allow(conn).to receive(:setsockopt)
308
- allow(conn).to receive(:write)
309
- allow(conn).to receive(:close)
310
- allow(TCPSocket).to receive(:new).and_return(conn)
311
- allow(StringIO).to receive(:open)
312
- end
313
-
314
- describe '.create' do
315
- context 'with nil forwarder_key' do
316
- it 'should return TcpForwarder object' do
317
- forwarder = ForwarderFactory.create(nil, 'test_tag', ['localhost:3456', 'localhost:4567'])
318
- expect(forwarder.kind_of?(TcpForwarder)).to be_truthy
319
- end
320
- end
321
-
322
- context 'with tcpforwarder forwarder_key' do
323
- it 'should return TcpForwarder object' do
324
- forwarder = ForwarderFactory.create('tcpforwarder', 'test_tag', ['localhost:3456', 'localhost:4567'])
325
- expect(forwarder.kind_of?(TcpForwarder)).to be_truthy
326
- end
327
- end
328
-
329
- context 'with sslforwarder forwarder_key' do
330
- it 'should return SslForwarder object' do
331
- forwarder = ForwarderFactory.create('sslforwarder', 'test_tag', ['localhost:3456', 'localhost:4567'])
332
- expect(forwarder.kind_of?(SslForwarder)).to be_truthy
333
- end
334
- end
335
- end
336
-
337
- describe '#initialize' do
338
- context 'servers is empty' do
339
- it do
340
- expect{ForwarderFactory.create('tcpforwarder', 'test_tag', [])}.to raise_error
341
- end
342
- end
343
- context 'servers is nil' do
344
- it do
345
- expect{ForwarderFactory.create('tcpforwarder', 'test_tag', nil)}.to raise_error
346
- end
347
- end
348
- end
349
-
350
- describe '#emit' do
351
- let(:record) { {table_name: 'test_table_name', log: '{"key":"value"}'} }
352
- before :each do
353
- forwarder.set_options({buffer_size_limit: ([Time.now.to_i,record].to_msgpack.bytesize * 2.5)})
354
- end
355
- context 'when the buffer size is less than threthold' do
356
- it do
357
- expect(forwarder.emit(record)).to be(false)
358
- expect(forwarder.buffer_record_count).to be(1)
359
- end
360
- end
361
- context 'when the buffer size exceeds threthold' do
362
- it do
363
- expect(forwarder.emit(record)).to be(false)
364
- expect(forwarder.emit(record)).to be(false)
365
- expect(forwarder.buffer_record_count).to be(2)
366
- expect(forwarder.emit(record)).to be(true)
367
- expect(forwarder.buffer_record_count).to be(0)
368
- end
369
- end
370
- end
371
-
372
- describe '#pickup_server' do
373
- context 'with only one server' do
374
- let(:servers) { ['localhost:1111'] }
375
- let(:forwarder) {
376
- ForwarderFactory.create('tcpforwarder', 'test_tag', servers)
377
- }
378
- it 'expect to return same server' do
379
- expect(forwarder.pickup_server).to eq('localhost:1111')
380
- expect(forwarder.pickup_server).to eq('localhost:1111')
381
- expect(forwarder.pickup_server).to eq('localhost:1111')
382
- end
383
- end
384
- context 'with servers' do
385
- let(:servers) { ['localhost:1111', 'localhost:2222', 'localhost:3333'] }
386
- let(:forwarder) {
387
- ForwarderFactory.create('tcpforwarder', 'test_tag', servers)
388
- }
389
- it 'expect to return same server' do
390
- expect(forwarder.pickup_server).to eq('localhost:1111')
391
- expect(forwarder.pickup_server).to eq('localhost:2222')
392
- expect(forwarder.pickup_server).to eq('localhost:3333')
393
- expect(forwarder.pickup_server).to eq('localhost:1111')
394
- end
395
- end
396
- end
397
- end
398
- end
399
-
400
- module Mysql
401
- describe MysqlDumpGeneratorMasterData do
402
- let(:stdout) { double(:stdout) }
403
- let(:stderr) { double(:stderr) }
404
- let(:status) { double(:status) }
405
- let(:file_path) { File.join('/tmp', "flydata_sync_spec_mysqldump_#{Time.now.to_i}") }
406
- let(:default_conf) { {
407
- 'host' => 'localhost', 'port' => 3306, 'username' => 'admin',
408
- 'password' => 'pass', 'database' => 'dev', 'tables' => 'users,groups',
409
- } }
410
- let(:default_dump_generator) { MysqlDumpGeneratorMasterData.new(default_conf) }
411
-
412
- describe '#initialize' do
413
- context 'with password' do
414
- subject { default_dump_generator.instance_variable_get(:@dump_cmd) }
415
- it { is_expected.to eq('mysqldump --protocol=tcp -h localhost -P 3306 -uadmin -ppass --skip-lock-tables ' +
416
- '--single-transaction --hex-blob --flush-logs --master-data=2 dev users groups') }
417
- end
418
- context 'without password' do
419
- let (:dump_generator) do
420
- MysqlDumpGeneratorMasterData.new(default_conf.merge({'password' => ''}))
421
- end
422
- subject { dump_generator.instance_variable_get(:@dump_cmd) }
423
- it { is_expected.to eq('mysqldump --protocol=tcp -h localhost -P 3306 -uadmin --skip-lock-tables ' +
424
- '--single-transaction --hex-blob --flush-logs --master-data=2 dev users groups') }
425
- end
426
- end
427
-
428
- describe '#dump' do
429
- context 'when exit status is not 0' do
430
- before do
431
- `touch #{file_path}`
432
- expect(status).to receive(:exitstatus).and_return 1
433
- expect(Open3).to receive(:capture3).and_return(
434
- ['(dummy std out)', '(dummy std err)', status]
435
- )
436
- end
437
- it do
438
- expect{ default_dump_generator.dump(file_path) }.to raise_error
439
- expect(File.exists?(file_path)).to be_falsey
440
- end
441
- end
442
- context 'when exit status is 0 but no file' do
443
- before do
444
- expect(status).to receive(:exitstatus).and_return 0
445
- expect(Open3).to receive(:capture3).and_return(
446
- ['(dummy std out)', '(dummy std err)', status]
447
- )
448
- end
449
- it do
450
- expect{ default_dump_generator.dump(file_path) }.to raise_error
451
- expect(File.exists?(file_path)).to be_falsey
452
- end
453
- end
454
- context 'when exit status is 0 but file size is 0' do
455
- before do
456
- `touch #{file_path}`
457
- expect(status).to receive(:exitstatus).and_return 0
458
- expect(Open3).to receive(:capture3).and_return(
459
- ['(dummy std out)', '(dummy std err)', status]
460
- )
461
- end
462
- it do
463
- expect{ default_dump_generator.dump(file_path) }.to raise_error
464
- expect(File.exists?(file_path)).to be_truthy
465
- end
466
- end
467
- context 'when exit status is 0' do
468
- before do
469
- `echo "something..." > #{file_path}`
470
- expect(status).to receive(:exitstatus).and_return 0
471
- expect(Open3).to receive(:capture3).and_return(
472
- ['(dummy std out)', '(dummy std err)', status]
473
- )
474
- end
475
- it do
476
- expect(default_dump_generator.dump(file_path)).to be_truthy
477
- expect(File.exists?(file_path)).to be_truthy
478
- end
479
- end
480
- after :each do
481
- File.delete(file_path) if File.exists?(file_path)
482
- end
483
- end
484
- end
485
-
486
- describe MysqlDumpParser do
487
- let(:file_path) { File.join('/tmp', "flydata_sync_spec_mysqldump_parse_#{Time.now.to_i}") }
488
- let(:default_parser) { MysqlDumpParser.new(file_path) }
489
-
490
- def generate_dump_file(content)
491
- File.open(file_path, 'w') {|f| f.write(content)}
492
- end
493
-
494
- after do
495
- File.delete(file_path) if File.exists?(file_path)
496
- end
497
-
498
- describe '#initialize' do
499
- context 'when file does not exist' do
500
- it do
501
- expect{ MysqlDumpParser.new(file_path) }.to raise_error
502
- end
503
- end
504
- context 'when file exists' do
505
- before { generate_dump_file('') }
506
- it do
507
- expect(MysqlDumpParser.new(file_path)).to be_an_instance_of(MysqlDumpParser)
508
- end
509
- end
510
- end
511
-
512
- describe '#parse' do
513
- DUMP_HEADER = <<EOT
514
- -- MySQL dump 10.13 Distrib 5.6.13, for osx10.9 (x86_64)
515
- --
516
- -- Host: localhost Database: sync_test
517
- -- ------------------------------------------------------
518
- -- Server version>--5.6.13-log
519
-
520
- /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
521
- /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
522
- /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
523
- /*!40101 SET NAMES utf8 */;
524
- /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
525
- /*!40103 SET TIME_ZONE='+00:00' */;
526
- /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
527
- /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
528
- /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
529
- /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
530
-
531
- --
532
- -- Position to start replication or point-in-time recovery from
533
- --
534
-
535
- -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000267', MASTER_LOG_POS=120;
536
- EOT
537
-
538
- def index_after(content, string)
539
- content.index(string) + string.bytesize + 1
540
- end
541
-
542
- let(:default_parser) { MysqlDumpParser.new(file_path) }
543
- let(:default_binlog_pos) { {binfile: 'mysql-bin.000267', pos: 120 } }
544
- let(:dump_pos_after_binlog_pos) { index_after(DUMP_HEADER, 'MASTER_LOG_POS=120;') }
545
-
546
- let(:create_table_block) { double('create_table_block') }
547
- let(:insert_record_block) { double('insert_record_block') }
548
- let(:check_point_block) { double('check_point_block') }
549
-
550
- before do
551
- generate_dump_file('')
552
- end
553
-
554
- context 'when dump does not contain binlog pos' do
555
- before { generate_dump_file('dummy content') }
556
- it do
557
- expect(create_table_block).to receive(:call).never
558
- expect(insert_record_block).to receive(:call).never
559
- expect(check_point_block).to receive(:call).never
560
- binlog_pos = default_parser.parse(
561
- create_table_block, insert_record_block, check_point_block
562
- )
563
- expect(binlog_pos).to be_nil
564
- end
565
- end
566
-
567
- context 'when dump contains only binlog pos' do
568
- before { generate_dump_file(<<EOT
569
- #{DUMP_HEADER}
570
- EOT
571
- ) }
572
- it do
573
- expect(create_table_block).to receive(:call).never
574
- expect(insert_record_block).to receive(:call).never
575
- expect(check_point_block).to receive(:call).once
576
- binlog_pos = default_parser.parse(
577
- create_table_block, insert_record_block, check_point_block
578
- )
579
- expect(binlog_pos).to eq(default_binlog_pos)
580
- end
581
- end
582
-
583
- context 'when dump contains create table without records' do
584
- let(:dump_content) { <<EOT
585
- #{DUMP_HEADER}
586
-
587
- DROP TABLE IF EXISTS `users_login`;
588
- /*!40101 SET @saved_cs_client = @@character_set_client */;
589
- /*!40101 SET character_set_client = utf8 */;
590
- CREATE TABLE `users_login` (
591
- `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'users id',
592
- `login_count` int(10) unsigned DEFAULT '0' COMMENT 'login count',
593
- `create_time` datetime NOT NULL COMMENT 'create time',
594
- `update_time` datetime NOT NULL COMMENT 'update time',
595
- PRIMARY KEY (`user_id`)
596
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='';
597
- /*!40101 SET character_set_client = @saved_cs_client */;
598
-
599
- --
600
- -- Dumping data for table `users_login`
601
- --
602
-
603
- LOCK TABLES `users_login` WRITE;
604
- /*!40000 ALTER TABLE `users_login` DISABLE KEYS */;
605
- /*!40000 ALTER TABLE `users_login` ENABLE KEYS */;
606
- UNLOCK TABLES;
607
-
608
- EOT
609
- }
610
- before { generate_dump_file(dump_content) }
611
- it do
612
- expect(create_table_block).to receive(:call) { |mysql_table|
613
- expect(mysql_table.table_name).to eq('users_login')
614
- }.once
615
- expect(insert_record_block).to receive(:call).never
616
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
617
- expect(mysql_table).to be_nil
618
- expect(last_pos).to eq(dump_pos_after_binlog_pos)
619
- expect(binlog_pos).to eq(default_binlog_pos)
620
- expect(state).to eq(Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE)
621
- expect(substate).to be_nil
622
- }
623
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
624
- expect(mysql_table.table_name).to eq('users_login')
625
- expect(mysql_table.columns.keys).to eq(['user_id', 'login_count', 'create_time', 'update_time'])
626
- expect(last_pos).to eq(index_after(dump_content, 'ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\'\';'))
627
- expect(binlog_pos).to eq(default_binlog_pos)
628
- expect(state).to eq(Flydata::Mysql::MysqlDumpParser::State::INSERT_RECORD)
629
- expect(substate).to be_nil
630
- }
631
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
632
- expect(mysql_table.table_name).to eq('users_login')
633
- expect(last_pos).to eq(index_after(dump_content, 'UNLOCK TABLES;'))
634
- expect(binlog_pos).to eq(default_binlog_pos)
635
- expect(state).to eq(Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE)
636
- expect(substate).to be_nil
637
- }
638
- expect(check_point_block).to receive(:call).never
639
-
640
- binlog_pos = default_parser.parse(
641
- create_table_block, insert_record_block, check_point_block
642
- )
643
- expect(binlog_pos).to eq(default_binlog_pos)
644
- end
645
- end
646
-
647
- context 'when dump contains create table with multi inserts' do
648
- let(:dump_content) { <<EOT
649
- #{DUMP_HEADER}
650
-
651
- DROP TABLE IF EXISTS `users_login`;
652
- /*!40101 SET @saved_cs_client = @@character_set_client */;
653
- /*!40101 SET character_set_client = utf8 */;
654
- CREATE TABLE `users_login` (
655
- `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'users id',
656
- `login_count` int(10) unsigned DEFAULT '0' COMMENT 'login count',
657
- `comment` varchar(255) DEFAULT NULL COMMENT 'comment',
658
- `create_time` datetime NOT NULL COMMENT 'create time',
659
- `update_time` datetime NOT NULL COMMENT 'update time',
660
- PRIMARY KEY (`user_id`)
661
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
662
- /*!40101 SET character_set_client = @saved_cs_client */;
663
-
664
- --
665
- -- Dumping data for table `users_login`
666
- --
667
-
668
- LOCK TABLES `users_login` WRITE;
669
- /*!40000 ALTER TABLE `users_login` DISABLE KEYS */;
670
- INSERT INTO `users_login` VALUES (15,46,'moodier','2001-10-02 08:18:08','1986-06-11 22:50:10'),(35,6,'missあいうえおteer','1991-10-15 19:38:07','1970-10-01 22:03:10'),(52,33,'sub\\\\field','1972-08-23 20:16:08','1974-10-10 23:28:11');
671
- INSERT INTO `users_login` VALUES (373,31,'out\\'swearing','1979-10-07 08:10:08','2006-02-22 16:26:04'),(493,8,'schizophrenic','1979-07-06 07:34:07','1970-08-09 01:21:01');
672
- /*!40000 ALTER TABLE `users_login` ENABLE KEYS */;
673
- UNLOCK TABLES;
674
- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
675
-
676
- EOT
677
- }
678
- before { generate_dump_file(dump_content) }
679
- it do
680
- # create_table_block
681
- expect(create_table_block).to receive(:call) { |mysql_table|
682
- expect(mysql_table.table_name).to eq('users_login')
683
- expect(mysql_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
684
- }.once
685
- expect(create_table_block).to receive(:call).never
686
-
687
- # insert_record_block
688
- [
689
- [ %w(15 46 moodier 2001-10-02\ 08:18:08 1986-06-11\ 22:50:10),
690
- %w(35 6 missあいうえおteer 1991-10-15\ 19:38:07 1970-10-01\ 22:03:10),
691
- %w(52 33 sub\\field 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
692
- [ %w(373 31 out'swearing 1979-10-07\ 08:10:08 2006-02-22\ 16:26:04),
693
- %w(493 8 schizophrenic 1979-07-06\ 07:34:07 1970-08-09\ 01:21:01),]
694
- ].each do |expected_values|
695
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
696
- expect(mysql_table.table_name).to eq('users_login')
697
- expect(values_set).to eq(expected_values)
698
- nil
699
- }.once
700
- end
701
- expect(insert_record_block).to receive(:call).never
702
-
703
- # insert_record_block
704
- [
705
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE},
706
- {state: Flydata::Mysql::MysqlDumpParser::State::INSERT_RECORD},
707
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE,
708
- last_pos: index_after(dump_content, 'UNLOCK TABLES;') + 10}
709
- ].each do |expected_params|
710
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
711
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
712
- expect(state).to eq(expected_params[:state])
713
- if expected_params[:last_pos]
714
- expect(last_pos).to eq(expected_params[:last_pos])
715
- end
716
- expect(binlog_pos).to eq(default_binlog_pos)
717
- expect(substate).to eq(expected_params[:substate])
718
- expected_params[:result]
719
- }.once
720
- end
721
- expect(check_point_block).to receive(:call).never
722
-
723
- binlog_pos = default_parser.parse(
724
- create_table_block, insert_record_block, check_point_block
725
- )
726
- expect(binlog_pos).to eq(default_binlog_pos)
727
- end
728
- end
729
-
730
- context 'when dump contains create table with records' do
731
- let(:dump_content) { <<EOT
732
- #{DUMP_HEADER}
733
-
734
- DROP TABLE IF EXISTS `users_login`;
735
- /*!40101 SET @saved_cs_client = @@character_set_client */;
736
- /*!40101 SET character_set_client = utf8 */;
737
- CREATE TABLE `users_login` (
738
- `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'users id',
739
- `login_count` int(10) unsigned DEFAULT '0' COMMENT 'login count',
740
- `comment` varchar(255) DEFAULT NULL COMMENT 'comment',
741
- `create_time` datetime NOT NULL COMMENT 'create time',
742
- `update_time` datetime NOT NULL COMMENT 'update time',
743
- PRIMARY KEY (`user_id`)
744
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
745
- /*!40101 SET character_set_client = @saved_cs_client */;
746
-
747
- --
748
- -- Dumping data for table `users_login`
749
- --
750
-
751
- LOCK TABLES `users_login` WRITE;
752
- /*!40000 ALTER TABLE `users_login` DISABLE KEYS */;
753
- INSERT INTO `users_login` VALUES (15,46,'moodier','2001-10-02 08:18:08','1986-06-11 22:50:10'),(35,6,NULL,'1991-10-15 19:38:07','1970-10-01 22:03:10'),(52,33,'subfield','1972-08-23 20:16:08','1974-10-10 23:28:11');
754
- /*!40000 ALTER TABLE `users_login` ENABLE KEYS */;
755
- UNLOCK TABLES;
756
- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
757
-
758
- EOT
759
- }
760
- before { generate_dump_file(dump_content) }
761
- it do
762
- # create_table_block
763
- expect(create_table_block).to receive(:call) { |mysql_table|
764
- expect(mysql_table.table_name).to eq('users_login')
765
- expect(mysql_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
766
- }.once
767
- expect(create_table_block).to receive(:call).never
768
-
769
- # insert_record_block
770
- [
771
- [ %w(15 46 moodier 2001-10-02\ 08:18:08 1986-06-11\ 22:50:10),
772
- ['35', '6', nil, '1991-10-15 19:38:07', '1970-10-01 22:03:10'],
773
- %w(52 33 subfield 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
774
- ].each do |expected_values|
775
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
776
- expect(mysql_table.table_name).to eq('users_login')
777
- expect(values_set).to eq(expected_values)
778
- nil
779
- }.once
780
- end
781
- expect(insert_record_block).to receive(:call).never
782
-
783
- # insert_record_block
784
- [
785
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE},
786
- {state: Flydata::Mysql::MysqlDumpParser::State::INSERT_RECORD},
787
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE,
788
- last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
789
- ].each do |expected_params|
790
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
791
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
792
- expect(state).to eq(expected_params[:state])
793
- if expected_params[:last_pos]
794
- expect(last_pos).to eq(expected_params[:last_pos])
795
- end
796
- expect(binlog_pos).to eq(default_binlog_pos)
797
- expect(substate).to eq(expected_params[:substate])
798
- expected_params[:result]
799
- }.once
800
- end
801
- expect(check_point_block).to receive(:call).never
802
-
803
- binlog_pos = default_parser.parse(
804
- create_table_block, insert_record_block, check_point_block
805
- )
806
- expect(binlog_pos).to eq(default_binlog_pos)
807
- end
808
- end
809
-
810
- context 'with resume after creating table' do
811
- let(:dump_content_head) { <<EOT
812
- #{DUMP_HEADER}
813
-
814
- DROP TABLE IF EXISTS `users_login`;
815
- /*!40101 SET @saved_cs_client = @@character_set_client */;
816
- /*!40101 SET character_set_client = utf8 */;
817
- CREATE TABLE `users_login` (
818
- `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'users id',
819
- `login_count` int(10) unsigned DEFAULT '0' COMMENT 'login count',
820
- `comment` varchar(255) DEFAULT NULL COMMENT 'comment',
821
- `create_time` datetime NOT NULL COMMENT 'create time',
822
- `update_time` datetime NOT NULL COMMENT 'update time',
823
- PRIMARY KEY (`user_id`)
824
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
825
- /*!40101 SET character_set_client = @saved_cs_client */;
826
-
827
- EOT
828
- }
829
- let(:dump_content_all) { <<EOT
830
- #{dump_content_head}
831
- --
832
- -- Dumping data for table `users_login`
833
- --
834
-
835
- LOCK TABLES `users_login` WRITE;
836
- /*!40000 ALTER TABLE `users_login` DISABLE KEYS */;
837
- INSERT INTO `users_login` VALUES (15,46,'moodier','2001-10-02 08:18:08','1986-06-11 22:50:10'),(35,6,'missteer','1991-10-15 19:38:07','1970-10-01 22:03:10'),(52,33,'subfield','1972-08-23 20:16:08','1974-10-10 23:28:11');
838
- /*!40000 ALTER TABLE `users_login` ENABLE KEYS */;
839
- UNLOCK TABLES;
840
- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
841
- EOT
842
- }
843
- before do
844
- generate_dump_file(dump_content_head)
845
- default_parser.parse(
846
- Proc.new{},
847
- Proc.new{
848
- raise "Should not be called"
849
- },
850
- Proc.new{ |mysql_table, last_pos, binlog_pos, state, substate|
851
- if mysql_table
852
- @mysql_table = mysql_table
853
- @option = { status: Flydata::Command::Sync::STATUS_PARSING,
854
- table_name: mysql_table.table_name,
855
- last_pos: last_pos,
856
- binlog_pos: binlog_pos,
857
- state: state,
858
- substate: substate,
859
- mysql_table: mysql_table }
860
- end
861
- }
862
- )
863
- expect(@option).to eq({
864
- status: Flydata::Command::Sync::STATUS_PARSING,
865
- table_name: 'users_login',
866
- last_pos: index_after(dump_content_head, 'ENGINE=InnoDB DEFAULT CHARSET=utf8;'),
867
- binlog_pos: default_binlog_pos,
868
- state: Flydata::Mysql::MysqlDumpParser::State::INSERT_RECORD,
869
- substate: nil,
870
- mysql_table: @mysql_table
871
- })
872
- end
873
- it do
874
- generate_dump_file(dump_content_all)
875
- parser_for_resume = MysqlDumpParser.new(file_path, @option)
876
-
877
- # create_table_block
878
- expect(create_table_block).to receive(:call).never
879
-
880
- # insert_record_block
881
- [
882
- [ %w(15 46 moodier 2001-10-02\ 08:18:08 1986-06-11\ 22:50:10),
883
- %w(35 6 missteer 1991-10-15\ 19:38:07 1970-10-01\ 22:03:10),
884
- %w(52 33 subfield 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
885
- ].each do |expected_values|
886
- expect(insert_record_block).to receive(:call) { |mysql_table, values|
887
- expect(mysql_table.table_name).to eq('users_login')
888
- expect(values).to eq(expected_values)
889
- nil
890
- }.once
891
- end
892
- expect(insert_record_block).to receive(:call).never
893
-
894
- # check_point_block
895
- [
896
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE,
897
- last_pos: index_after(dump_content_all, 'UNLOCK TABLES;')}
898
- ].each do |expected_params|
899
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
900
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
901
- expect(state).to eq(expected_params[:state])
902
- if expected_params[:last_pos]
903
- expect(last_pos).to eq(expected_params[:last_pos])
904
- end
905
- expect(binlog_pos).to eq(default_binlog_pos)
906
- expect(substate).to eq(expected_params[:substate])
907
- expected_params[:result]
908
- }.once
909
- end
910
- expect(check_point_block).to receive(:call).never
911
-
912
- binlog_pos = parser_for_resume.parse(
913
- create_table_block, insert_record_block, check_point_block
914
- )
915
- expect(binlog_pos).to eq(default_binlog_pos)
916
- end
917
- end
918
-
919
- context 'with resume during insert records' do
920
- let(:dump_content) { <<EOT
921
- #{DUMP_HEADER}
922
-
923
- DROP TABLE IF EXISTS `users_login`;
924
- /*!40101 SET @saved_cs_client = @@character_set_client */;
925
- /*!40101 SET character_set_client = utf8 */;
926
- CREATE TABLE `users_login` (
927
- `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'users id',
928
- `login_count` int(10) unsigned DEFAULT '0' COMMENT 'login count',
929
- `comment` varchar(255) DEFAULT NULL COMMENT 'comment',
930
- `create_time` datetime NOT NULL COMMENT 'create time',
931
- `update_time` datetime NOT NULL COMMENT 'update time',
932
- PRIMARY KEY (`user_id`)
933
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
934
- /*!40101 SET character_set_client = @saved_cs_client */;
935
-
936
- --
937
- -- Dumping data for table `users_login`
938
- --
939
-
940
- LOCK TABLES `users_login` WRITE;
941
- /*!40000 ALTER TABLE `users_login` DISABLE KEYS */;
942
- INSERT INTO `users_login` VALUES (15,46,'moodier','2001-10-02 08:18:08','1986-06-11 22:50:10'),(35,6,'missteer','1991-10-15 19:38:07','1970-10-01 22:03:10'),(52,33,'subfield','1972-08-23 20:16:08','1974-10-10 23:28:11');
943
- INSERT INTO `users_login` VALUES (194,11,'pandemonium','2008-01-22 22:15:10','1991-04-04 17:30:05'),(230,7,'cloudburst','2010-12-28 11:46:11','1971-06-22 13:08:01');
944
- /*!40000 ALTER TABLE `users_login` ENABLE KEYS */;
945
- UNLOCK TABLES;
946
- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
947
- EOT
948
- }
949
- before do
950
- generate_dump_file(dump_content)
951
-
952
- insert_record_block_for_resume = double('insert_record_block_for_resume')
953
- expect(insert_record_block_for_resume).to receive(:call) { true }.once
954
- expect(insert_record_block_for_resume).to receive(:call) { false }.once
955
-
956
- default_parser.parse(
957
- Proc.new{},
958
- insert_record_block_for_resume,
959
- Proc.new{ |mysql_table, last_pos, binlog_pos, state, substate|
960
- if last_pos == index_after(dump_content, "'1972-08-23 20:16:08','1974-10-10 23:28:11');")
961
- @mysql_table = mysql_table
962
- @option = { status: Flydata::Command::Sync::STATUS_PARSING,
963
- table_name: mysql_table.table_name,
964
- last_pos: last_pos,
965
- binlog_pos: binlog_pos,
966
- state: state,
967
- substate: substate,
968
- mysql_table: mysql_table }
969
- end
970
- }
971
- )
972
- expect(@option).to eq({
973
- status: Flydata::Command::Sync::STATUS_PARSING,
974
- table_name: 'users_login',
975
- last_pos: index_after(dump_content, "'1972-08-23 20:16:08','1974-10-10 23:28:11');"),
976
- binlog_pos: default_binlog_pos,
977
- state: Flydata::Mysql::MysqlDumpParser::State::INSERT_RECORD,
978
- substate: nil,
979
- mysql_table: @mysql_table
980
- })
981
- end
982
- it do
983
- generate_dump_file(dump_content)
984
- parser_for_resume = MysqlDumpParser.new(file_path, @option)
985
-
986
- # create_table_block
987
- expect(create_table_block).to receive(:call).never
988
-
989
- # insert_record_block
990
- [
991
- [ %w(194 11 pandemonium 2008-01-22\ 22:15:10 1991-04-04\ 17:30:05),
992
- %w(230 7 cloudburst 2010-12-28\ 11:46:11 1971-06-22\ 13:08:01),],
993
- ].each do |expected_values|
994
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
995
- expect(mysql_table.table_name).to eq('users_login')
996
- expect(values_set).to eq(expected_values)
997
- nil
998
- }.once
999
- end
1000
- expect(insert_record_block).to receive(:call).never
1001
-
1002
- # check_point_block
1003
- [
1004
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE,
1005
- last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
1006
- ].each do |expected_params|
1007
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
1008
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
1009
- expect(state).to eq(expected_params[:state])
1010
- if expected_params[:last_pos]
1011
- expect(last_pos).to eq(expected_params[:last_pos])
1012
- end
1013
- expect(binlog_pos).to eq(default_binlog_pos)
1014
- expect(substate).to eq(expected_params[:substate])
1015
- expected_params[:result]
1016
- }.once
1017
- end
1018
- expect(check_point_block).to receive(:call).never
1019
-
1020
- binlog_pos = parser_for_resume.parse(
1021
- create_table_block, insert_record_block, check_point_block
1022
- )
1023
- expect(binlog_pos).to eq(default_binlog_pos)
1024
- end
1025
- end
1026
-
1027
- context 'when dump contains contain escape characters' do
1028
- let(:dump_content) { <<EOT
1029
- #{DUMP_HEADER}
1030
-
1031
- DROP TABLE IF EXISTS `users_login`;
1032
- /*!40101 SET @saved_cs_client = @@character_set_client */;
1033
- /*!40101 SET character_set_client = utf8 */;
1034
- CREATE TABLE `users_login` (
1035
- `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'users id',
1036
- `login_count` int(10) unsigned DEFAULT '0' COMMENT 'login count',
1037
- `comment` varchar(255) DEFAULT NULL COMMENT 'comment',
1038
- `create_time` datetime NOT NULL COMMENT 'create time',
1039
- `update_time` datetime NOT NULL COMMENT 'update time',
1040
- PRIMARY KEY (`user_id`)
1041
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1042
- /*!40101 SET character_set_client = @saved_cs_client */;
1043
-
1044
- --
1045
- -- Dumping data for table `users_login`
1046
- --
1047
-
1048
- LOCK TABLES `users_login` WRITE;
1049
- /*!40000 ALTER TABLE `users_login` DISABLE KEYS */;
1050
- INSERT INTO `users_login` VALUES (15,46,'moodier)','2001-10-02 08:18:08','1986-06-11 22:50:10'),(35,6,'miss,teer','1991-10-15 19:38:07','1970-10-01 22:03:10'),(52,33,'subfield\\'','1972-08-23 20:16:08','1974-10-10 23:28:11');
1051
- INSERT INTO `users_login` VALUES (373,31,'outs\\nwearing','1979-10-07 08:10:08','2006-02-22 16:26:04'),(493,8,'schiz\tophrenic','1979-07-06 07:34:07\\'),','1970-08-09,01:21:01,\\')');
1052
- /*!40000 ALTER TABLE `users_login` ENABLE KEYS */;
1053
- UNLOCK TABLES;
1054
- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
1055
-
1056
- EOT
1057
- }
1058
- before { generate_dump_file(dump_content) }
1059
- it do
1060
- # create_table_block
1061
- expect(create_table_block).to receive(:call) { |mysql_table|
1062
- expect(mysql_table.table_name).to eq('users_login')
1063
- expect(mysql_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
1064
- }.once
1065
- expect(create_table_block).to receive(:call).never
1066
-
1067
- # insert_record_block
1068
- [
1069
- [ %w(15 46 moodier\) 2001-10-02\ 08:18:08 1986-06-11\ 22:50:10),
1070
- %w(35 6 miss,teer 1991-10-15\ 19:38:07 1970-10-01\ 22:03:10),
1071
- %w(52 33 subfield' 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
1072
- [ ['373','31',"outs\nwearing",'1979-10-07 08:10:08','2006-02-22 16:26:04'],
1073
- ['493','8',"schiz\tophrenic",'1979-07-06 07:34:07\'),','1970-08-09,01:21:01,\')'] ]
1074
- ].each do |expected_values|
1075
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
1076
- expect(mysql_table.table_name).to eq('users_login')
1077
- expect(values_set).to eq(expected_values)
1078
- nil
1079
- }.once
1080
- end
1081
- expect(insert_record_block).to receive(:call).never
1082
-
1083
- # insert_record_block
1084
- [
1085
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE},
1086
- {state: Flydata::Mysql::MysqlDumpParser::State::INSERT_RECORD},
1087
- {state: Flydata::Mysql::MysqlDumpParser::State::CREATE_TABLE,
1088
- last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
1089
- ].each do |expected_params|
1090
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, binlog_pos, state, substate|
1091
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
1092
- expect(state).to eq(expected_params[:state])
1093
- if expected_params[:last_pos]
1094
- expect(last_pos).to eq(expected_params[:last_pos])
1095
- end
1096
- expect(binlog_pos).to eq(default_binlog_pos)
1097
- expect(substate).to eq(expected_params[:substate])
1098
- expected_params[:result]
1099
- }.once
1100
- end
1101
- expect(check_point_block).to receive(:call).never
1102
-
1103
- binlog_pos = default_parser.parse(
1104
- create_table_block, insert_record_block, check_point_block
1105
- )
1106
- expect(binlog_pos).to eq(default_binlog_pos)
1107
- end
1108
- end
1109
- end
1110
- end
1111
- describe MysqlDumpParser::InsertParser do
1112
- describe '#parse' do
1113
- let(:target_line) { '' }
1114
- let(:parser) { MysqlDumpParser::InsertParser.new(StringIO.new(target_line)) }
1115
- subject { parser.parse }
1116
-
1117
- context 'when single record' do
1118
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'hogehoge','2014-04-15 13:49:14');" }
1119
- it 'should return one element array' do
1120
- expect(subject).to eq([['1','hogehoge','2014-04-15 13:49:14']])
1121
- end
1122
- end
1123
-
1124
- context 'when 2 records' do
1125
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'foo','2014-04-15 13:49:14'),(2,'var','2014-04-15 14:21:05');" }
1126
- it 'should return two element array' do
1127
- expect(subject).to eq([['1','foo','2014-04-15 13:49:14'],['2','var','2014-04-15 14:21:05']])
1128
- end
1129
- end
1130
-
1131
- context 'when data includes carriage return' do
1132
- let(:target_line) { %q|INSERT INTO `test_table` VALUES (1,'abcd\refgh','2014-04-15 13:49:14');| }
1133
- it 'should escape return carriage' do
1134
- expect(subject).to eq([['1',"abcd\refgh",'2014-04-15 13:49:14']])
1135
- end
1136
- end
1137
-
1138
- context 'when data includes new line' do
1139
- let(:target_line) { %q|INSERT INTO `test_table` VALUES (1,'abcd\nefgh','2014-04-15 13:49:14');| }
1140
- it 'should escape new line' do
1141
- expect(subject).to eq([['1',"abcd\nefgh",'2014-04-15 13:49:14']])
1142
- end
1143
- end
1144
-
1145
- context 'when data includes escaped single quotation' do
1146
- let(:target_line) { %q|INSERT INTO `test_table` VALUES (1,'abcd\',\'efgh','2014-04-15 13:49:14');| }
1147
- it 'should escape single quotation' do
1148
- expect(subject).to eq([['1',"abcd','efgh",'2014-04-15 13:49:14']])
1149
- end
1150
- end
1151
-
1152
- context 'when data includes back slash' do
1153
- let(:target_line) { %q|INSERT INTO `test_table` VALUES (1,'abcd\\efgh','2014-04-15 13:49:14');| }
1154
- it 'should escape back slash' do
1155
- expect(subject).to eq([['1',"abcd\\efgh",'2014-04-15 13:49:14']])
1156
- end
1157
- end
1158
-
1159
- context 'when data includes back slash with double quote' do
1160
- # \"\'\' value on insert query shoulde be "''
1161
- let(:target_line) { %q|INSERT INTO `tast_table` VALUES (1,'\"\'\'','2014-04-15 13:49:14');| }
1162
- it 'should escape back slash' do
1163
- expect(subject).to eq([['1',%q|"''| ,'2014-04-15 13:49:14']])
1164
- end
1165
- end
1166
-
1167
- context 'when data includes back slash with double quote another case' do
1168
- # \"\"\"\"\"''\"'' value on insert query shoulde be """""''"''
1169
- let(:target_line) { %q|INSERT INTO `test_table` VALUES (1,'\"\"\"\"\"\'\'\"\'\'','2014-04-15 13:49:14');| }
1170
- it 'should escape back slash' do
1171
- expect(subject).to eq([['1',%q|"""""''"''|,'2014-04-15 13:49:14']])
1172
- end
1173
- end
1174
-
1175
- context 'when data includes mixed escaped characters' do
1176
- let(:target_line) { %q|INSERT INTO `test_table` VALUES (1,'ab\rcd\\e\nf\',\'gh','2014-04-15 13:49:14');| }
1177
- it 'should escape all' do
1178
- expect(subject).to eq([['1',"ab\rcd\\e\nf','gh",'2014-04-15 13:49:14']])
1179
- end
1180
- end
1181
-
1182
- context 'when data includes mixed escaped characters in a row' do
1183
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'ab\\\\ncd\\\\\\nefgh','2014-04-15 13:49:14');" }
1184
- it 'should escape all' do
1185
- expect(subject).to eq([['1',"ab\\ncd\\\nefgh",'2014-04-15 13:49:14']])
1186
- end
1187
- end
1188
-
1189
- context 'when data end with back slash' do
1190
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'D:\\\\download\\\\','2014-04-15 13:49:14');" }
1191
- it 'should escape back slash' do
1192
- expect(subject).to eq([['1',"D:\\download\\",'2014-04-15 13:49:14']])
1193
- end
1194
- end
1195
-
1196
- context 'when comma is the first character of a string' do
1197
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,',9','2014-04-15 13:49:14');" }
1198
- it 'should parse the string correctly' do
1199
- expect(subject).to eq([['1',',9','2014-04-15 13:49:14']])
1200
- end
1201
- end
1202
-
1203
- context 'when comma is the last character of a string' do
1204
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'9,','2014-04-15 13:49:14');" }
1205
- it 'should parse the string correctly' do
1206
- expect(subject).to eq([['1','9,','2014-04-15 13:49:14']])
1207
- end
1208
- end
1209
-
1210
- context 'when a string consists of a comma' do
1211
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,',','2014-04-15 13:49:14');" }
1212
- it 'should parse the string correctly' do
1213
- expect(subject).to eq([['1',',','2014-04-15 13:49:14']])
1214
- end
1215
- end
1216
-
1217
- context 'when two commas are given as a string' do
1218
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,',,','2014-04-15 13:49:14');" }
1219
- it 'should parse the string correctly' do
1220
- expect(subject).to eq([['1',',,','2014-04-15 13:49:14']])
1221
- end
1222
- end
1223
-
1224
- context 'when an empty string value is given' do
1225
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'','2014-04-15 13:49:14');" }
1226
- it 'should parse the string correctly' do
1227
- expect(subject).to eq([['1','','2014-04-15 13:49:14']])
1228
- end
1229
- end
1230
-
1231
- context 'when a value consists of a comma followed by closing bracket' do
1232
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'),ksd','2014-04-15 13:49:14');" }
1233
- it 'should parse the string correctly' do
1234
- expect(subject).to eq([['1','),ksd','2014-04-15 13:49:14']])
1235
- end
1236
- end
1237
-
1238
- context 'when there is a white space before the closing bracket' do
1239
- let(:target_line) { "INSERT INTO `test_table` VALUES (1,'aa','2014-04-15 13:49:14' );" }
1240
- it 'should fail to parse. This is intentional for performance reason' do
1241
- expect{subject}.to raise_error
1242
- end
1243
- end
1244
-
1245
- context 'when an integer that has leading zeros is given' do
1246
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,00013);"}
1247
- it 'should remove the leading zeros' do
1248
- expect(subject).to eq([['1', '13']])
1249
- end
1250
- end
1251
-
1252
- context 'when a decimal that has leading zeros is given' do
1253
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,00013.40);"}
1254
- it 'should remove the leading zeros' do
1255
- expect(subject).to eq([['1', '13.40']])
1256
- end
1257
- end
1258
-
1259
- context 'when a timestamp that has leading zeros is given' do
1260
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,'0004-04-15 13:49:14');"}
1261
- it 'should not remove the leading zeros' do
1262
- expect(subject).to eq([['1', '0004-04-15 13:49:14']])
1263
- end
1264
- end
1265
-
1266
- context 'when a string that has leading zeros is given' do
1267
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,'00000aa');"}
1268
- it 'should not remove the leading zeros' do
1269
- expect(subject).to eq([['1', '00000aa']])
1270
- end
1271
- end
1272
-
1273
- context 'when a string that has leading zeros, numbers and a comma in between is given' do
1274
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,'0003,00033');"}
1275
- it 'should not remove the leading zeros' do
1276
- expect(subject).to eq([['1', '0003,00033']])
1277
- end
1278
- end
1279
-
1280
- context 'when a string that has leading zeros, has only numbers is given' do
1281
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,'00033');"}
1282
- it 'should not remove the leading zeros' do
1283
- expect(subject).to eq([['1', '00033']])
1284
- end
1285
- end
1286
-
1287
- context 'when 0 is given' do
1288
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,0);"}
1289
- it 'should not remove the leading zeros' do
1290
- expect(subject).to eq([['1', '0']])
1291
- end
1292
- end
1293
-
1294
- context 'when 0.00 is given' do
1295
- let(:target_line) {"INSERT INTO `test_table` VALUES (1,0.00);"}
1296
- it 'should not remove the leading zeros' do
1297
- expect(subject).to eq([['1', '0.00']])
1298
- end
1299
- end
1300
- end
1301
- end
1302
- end
1303
-
1304
144
  end