flydata 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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