flydata 0.6.3 → 0.6.4

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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -2
  3. data/VERSION +1 -1
  4. data/bin/fdredshift +78 -0
  5. data/circle.yml +1 -1
  6. data/ext/flydata/{parser/mysql → source_mysql/parser}/.gitignore +0 -0
  7. data/ext/flydata/{parser/mysql → source_mysql/parser}/dump_parser_ext.cpp +3 -3
  8. data/ext/flydata/source_mysql/parser/extconf.rb +3 -0
  9. data/ext/flydata/{parser/mysql → source_mysql/parser}/parser.txt +0 -0
  10. data/ext/flydata/{parser/mysql → source_mysql/parser}/sql_parser.cpp +0 -0
  11. data/ext/flydata/{parser/mysql → source_mysql/parser}/sql_parser.h +0 -0
  12. data/flydata-core/lib/flydata-core/mysql/binlog_pos.rb +34 -32
  13. data/flydata-core/lib/flydata-core/mysql/compatibility_checker.rb +20 -0
  14. data/flydata-core/lib/flydata-core/table_def/mysql_table_def.rb +12 -4
  15. data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +60 -6
  16. data/flydata-core/spec/mysql/binlog_pos_spec.rb +474 -0
  17. data/flydata-core/spec/table_def/mysql_table_def_spec.rb +57 -0
  18. data/flydata-core/spec/table_def/mysql_to_redshift_table_def_spec.rb +174 -20
  19. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_AUTO_INCREMENT_keyword.dump +43 -0
  20. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_not_null_keyword.dump +43 -0
  21. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_unique_keyword.dump +43 -0
  22. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_unsigned_keyword.dump +43 -0
  23. data/flydata-core/spec/table_def/redshift_table_def_spec.rb +41 -8
  24. data/flydata.gemspec +0 -0
  25. data/lib/flydata/cli.rb +11 -5
  26. data/lib/flydata/command/base.rb +14 -1
  27. data/lib/flydata/command/exclusive_runnable.rb +42 -12
  28. data/lib/flydata/command/helper.rb +6 -6
  29. data/lib/flydata/command/sender.rb +4 -3
  30. data/lib/flydata/command/setup.rb +30 -381
  31. data/lib/flydata/command/stop.rb +1 -0
  32. data/lib/flydata/command/sync.rb +273 -301
  33. data/lib/flydata/compatibility_check.rb +24 -117
  34. data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +3 -3
  35. data/lib/flydata/fluent-plugins/mysql/alter_table_query_handler.rb +2 -2
  36. data/lib/flydata/fluent-plugins/mysql/binlog_record_handler.rb +6 -6
  37. data/lib/flydata/fluent-plugins/mysql/truncate_table_query_handler.rb +0 -1
  38. data/lib/flydata/parser.rb +14 -0
  39. data/lib/flydata/{parser_provider.rb → parser/parser_provider.rb} +6 -4
  40. data/lib/flydata/parser/source_table.rb +33 -0
  41. data/lib/flydata/source.rb +105 -0
  42. data/lib/flydata/source/component.rb +21 -0
  43. data/lib/flydata/source/errors.rb +7 -0
  44. data/lib/flydata/source/generate_source_dump.rb +72 -0
  45. data/lib/flydata/source/parse_dump_and_send.rb +52 -0
  46. data/lib/flydata/source/setup.rb +31 -0
  47. data/lib/flydata/source/source_pos.rb +45 -0
  48. data/lib/flydata/source/sync.rb +56 -0
  49. data/lib/flydata/source/sync_generate_table_ddl.rb +43 -0
  50. data/lib/flydata/source_file/setup.rb +17 -0
  51. data/lib/flydata/source_file/sync.rb +14 -0
  52. data/lib/flydata/{command → source_mysql/command}/mysql.rb +2 -1
  53. data/lib/flydata/{command → source_mysql/command}/mysql_command_base.rb +2 -4
  54. data/lib/flydata/{command → source_mysql/command}/mysqlbinlog.rb +2 -1
  55. data/lib/flydata/{command → source_mysql/command}/mysqldump.rb +2 -1
  56. data/lib/flydata/source_mysql/generate_source_dump.rb +53 -0
  57. data/lib/flydata/source_mysql/mysql_compatibility_check.rb +114 -0
  58. data/lib/flydata/source_mysql/parse_dump_and_send.rb +28 -0
  59. data/lib/flydata/{parser/mysql → source_mysql/parser}/.gitignore +0 -0
  60. data/lib/flydata/{parser/mysql → source_mysql/parser}/dump_parser.rb +32 -67
  61. data/lib/flydata/{parser/mysql → source_mysql/parser}/mysql_alter_table.treetop +0 -0
  62. data/lib/flydata/source_mysql/setup.rb +24 -0
  63. data/lib/flydata/source_mysql/source_pos.rb +21 -0
  64. data/lib/flydata/source_mysql/sync.rb +45 -0
  65. data/lib/flydata/source_mysql/sync_generate_table_ddl.rb +40 -0
  66. data/lib/flydata/{mysql → source_mysql}/table_ddl.rb +6 -17
  67. data/lib/flydata/source_zendesk/sync_generate_table_ddl.rb +30 -0
  68. data/lib/flydata/source_zendesk/zendesk_flydata_tabledefs.rb +133 -0
  69. data/lib/flydata/sync_file_manager.rb +132 -73
  70. data/lib/flydata/table_ddl.rb +18 -0
  71. data/spec/flydata/cli_spec.rb +1 -0
  72. data/spec/flydata/command/exclusive_runnable_spec.rb +19 -8
  73. data/spec/flydata/command/sender_spec.rb +1 -1
  74. data/spec/flydata/command/setup_spec.rb +4 -4
  75. data/spec/flydata/command/sync_spec.rb +97 -134
  76. data/spec/flydata/compatibility_check_spec.rb +16 -289
  77. data/spec/flydata/fluent-plugins/mysql/alter_table_query_handler_spec.rb +3 -3
  78. data/spec/flydata/fluent-plugins/mysql/dml_record_handler_spec.rb +1 -1
  79. data/spec/flydata/fluent-plugins/mysql/shared_query_handler_context.rb +4 -2
  80. data/spec/flydata/fluent-plugins/mysql/truncate_query_handler_spec.rb +1 -1
  81. data/spec/flydata/source_mysql/generate_source_dump_spec.rb +69 -0
  82. data/spec/flydata/source_mysql/mysql_compatibility_check_spec.rb +280 -0
  83. data/spec/flydata/{parser/mysql → source_mysql/parser}/alter_table_parser_spec.rb +2 -2
  84. data/spec/flydata/{parser/mysql → source_mysql/parser}/dump_parser_spec.rb +75 -70
  85. data/spec/flydata/source_mysql/sync_generate_table_ddl_spec.rb +137 -0
  86. data/spec/flydata/{mysql → source_mysql}/table_ddl_spec.rb +2 -2
  87. data/spec/flydata/source_spec.rb +140 -0
  88. data/spec/flydata/source_zendesk/sync_generate_table_ddl_spec.rb +33 -0
  89. data/spec/flydata/sync_file_manager_spec.rb +157 -77
  90. data/tmpl/redshift_mysql_data_entry.conf.tmpl +1 -1
  91. metadata +56 -23
  92. data/ext/flydata/parser/mysql/extconf.rb +0 -3
  93. data/lib/flydata/mysql/binlog_position.rb +0 -22
  94. data/spec/flydata/mysql/binlog_position_spec.rb +0 -35
@@ -17,7 +17,7 @@ module Mysql
17
17
  r
18
18
  end
19
19
  before do
20
- parser_class = ParserProvider.parser(:mysql, :mysql_alter_table)
20
+ parser_class = Flydata::Parser::ParserProvider.parser(:mysql, :mysql_alter_table)
21
21
  allow(parser_class).to receive(:new).and_return(parser)
22
22
  allow_any_instance_of(described_class).to receive(:check_empty_binlog)
23
23
  record.delete('table_name')
@@ -56,8 +56,8 @@ module Mysql
56
56
  end
57
57
  context "when event binlog is older than table binlog.pos" do
58
58
  it 'skip sending event' do
59
- expect(sync_fm).to receive(:get_table_binlog_pos).and_return("mysql-bin.000067\t120").once
60
- expect(ParserProvider).not_to receive(:parser)
59
+ expect(sync_fm).to receive(:get_table_source_raw_pos).and_return("mysql-bin.000067\t120").once
60
+ expect(Flydata::Parser::ParserProvider).not_to receive(:parser)
61
61
  expect(subject.process(record)).to eq(nil)
62
62
  end
63
63
  end
@@ -12,7 +12,7 @@ describe DmlRecordHandler do
12
12
  let(:tables) { ['items', 'orders'] }
13
13
  let(:sync_fm) {
14
14
  sfm = double('sync_fm')
15
- allow(sfm).to receive(:get_table_binlog_pos).and_return nil
15
+ allow(sfm).to receive(:get_table_source_raw_pos).and_return nil
16
16
  sfm
17
17
  }
18
18
  let(:context) {
@@ -4,11 +4,13 @@ module Mysql
4
4
  let(:database) { target_database }
5
5
  let(:table) { "foo" }
6
6
  let(:seq) { 200 }
7
+ let(:binlog_pos_string) { "mysql-bin.000065\t120" }
8
+ let(:binlog_pos_object) { FlydataCore::Mysql::BinlogPos.new(binlog_pos_string) }
7
9
  let(:sync_fm) do
8
10
  r = double('sync_fm')
9
- allow(r).to receive(:get_table_binlog_pos).and_return("mysql-bin.000065\t120")
11
+ allow(r).to receive(:get_table_source_raw_pos).and_return(binlog_pos_string)
10
12
  allow(r).to receive(:increment_and_save_table_position).with(table).and_yield(seq).and_return(nil)
11
- allow(r).to receive(:delete_table_binlog_pos).with(table)
13
+ allow(r).to receive(:delete_table_source_pos).with(table)
12
14
  r
13
15
  end
14
16
  let(:table_meta) { double'table_meta' }
@@ -79,7 +79,7 @@ module Mysql
79
79
  context 'when per-table binlog pos exists' do
80
80
  let(:truncate_query) { "TRUNCATE #{table}" }
81
81
  before do
82
- allow(sync_fm).to receive(:get_table_binlog_pos).and_return("mysql-bin.000067\t120")
82
+ allow(sync_fm).to receive(:get_table_source_raw_pos).and_return("mysql-bin.000067\t120")
83
83
  end
84
84
  include_examples "skip processing queries"
85
85
  end
@@ -0,0 +1,69 @@
1
+ require 'flydata/source_mysql/generate_source_dump'
2
+
3
+ module Flydata
4
+ module SourceMysql
5
+
6
+ describe GenerateSourceDump do
7
+ let(:subject_object) { described_class.new(source, dp, options) }
8
+
9
+ let(:source) { double('source') }
10
+ before do
11
+ allow(source).to receive(:de).and_return(de)
12
+ end
13
+ let(:dp) { double('dp') }
14
+ let(:options) { double('options') }
15
+
16
+ let(:de) { {
17
+ "mysql_data_entry_preference" => {
18
+ "host" => "foo",
19
+ "port" => 1234,
20
+ "tables" => all_tables,
21
+ }
22
+ } }
23
+
24
+ let(:all_tables) { %w|a b c d| + partial_tables }
25
+ let(:partial_tables) { %w|e f| }
26
+ let(:file_path) { double('file_path') }
27
+ let(:src_pos_callback) { Proc.new{} }
28
+ let(:db_size_check) { double('db_size_check') }
29
+ let(:size) { double('size') }
30
+
31
+ let(:options_with_partial_tables) {
32
+ prefs = de['mysql_data_entry_preference'].clone
33
+ prefs["tables"] = partial_tables
34
+ prefs
35
+ }
36
+
37
+ describe '#dump_size' do
38
+ subject { subject_object.dump_size(partial_tables) }
39
+
40
+ it 'creates DatabaseSizeCheck object with correct parameter' do
41
+ expect(Parser::DatabaseSizeCheck).to receive(:new).
42
+ with(options_with_partial_tables).and_return(db_size_check)
43
+ expect(db_size_check).to receive(:get_db_bytesize).and_return(size)
44
+
45
+ expect(subject).to eq size
46
+ end
47
+ end
48
+
49
+ describe '#dump' do
50
+ subject { subject_object.dump(partial_tables, file_path, &src_pos_callback) }
51
+
52
+ let(:dump_generator) { double('dump_generator') }
53
+ before do
54
+ allow(dump_generator).to receive(:dump)
55
+ end
56
+
57
+ it 'creates dump_generator with correct parameters' do
58
+ expect(Parser::MysqlDumpGeneratorNoMasterData).to receive(:new).
59
+ with(options_with_partial_tables).and_return(dump_generator)
60
+ expect(dump_generator).to receive(:dump).
61
+ with(file_path, &src_pos_callback)
62
+
63
+ subject
64
+ end
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,280 @@
1
+ require 'spec_helper'
2
+ require 'flydata/source_mysql/mysql_compatibility_check'
3
+
4
+ module Flydata
5
+ module SourceMysql
6
+
7
+ describe MysqlCompatibilityCheck do
8
+ let(:subject_object) { described_class.new(dp_hash, de_hash, options) }
9
+
10
+ let(:dp_hash) { default_data_port }
11
+ let(:de_hash) { default_mysql_cred }
12
+ let(:options) { default_options }
13
+
14
+ let(:default_data_port) do
15
+ {
16
+ "servers"=>["sample-test-site.com"]
17
+ }
18
+ end
19
+
20
+ let(:default_mysql_cred) do
21
+ {
22
+ "host" => "test",
23
+ "port" => 1234,
24
+ "username" => "test",
25
+ "password" => "password",
26
+ "database" => "test_db"
27
+ }
28
+ end
29
+
30
+ let(:default_options) { {} }
31
+
32
+ let(:client) { double('client') }
33
+ before do
34
+ allow(Mysql2::Client).to receive(:new).and_return(client)
35
+ allow(client).to receive(:close)
36
+ end
37
+
38
+ describe "#check" do
39
+ subject { subject_object.check }
40
+
41
+ it "calls all check methods" do
42
+ %w(compatibility56_variable mysql_user_compat mysql_protocol_tcp_compat
43
+ mysql_parameters_compat rds_master_status mysql_binlog_retention
44
+ mysql_table_types writing_permissions).each do |method_name|
45
+ expect(subject_object).to receive("check_#{method_name}".to_sym)
46
+ end
47
+
48
+ subject
49
+ end
50
+ end
51
+
52
+ describe "#check_mysql_user_compat" do
53
+ subject { subject_object.check_mysql_user_compat }
54
+
55
+ context "with all privileges in all databases" do
56
+ before do
57
+ allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT ALL PRIVILEGES ON *.* TO 'test'@'host"}])
58
+ end
59
+ it do
60
+ expect{subject}.to_not raise_error
61
+ end
62
+ end
63
+ context "with missing privileges in one database" do
64
+ before do
65
+ allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT ALL PRIVILEGES ON 'mysql'.* TO 'test'@'host"},
66
+ {"Grants for test"=>"GRANT SELECT, RELOAD, REPLICATION CLIENT ON `test_db`.* TO 'test'@'host"}])
67
+ end
68
+ it do
69
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /test_db': LOCK TABLES, REPLICATION SLAVE/)
70
+ end
71
+ end
72
+ context "with all required privileges in between all and specific databases" do
73
+ before do
74
+ allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"},
75
+ {"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `test_db`.* TO 'test'@'host"},
76
+ {"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `mysql`.* TO 'test'@'host"}])
77
+ end
78
+ it do
79
+ expect{subject}.to_not raise_error
80
+ end
81
+ end
82
+ context "with missing privileges in each database" do
83
+ before do
84
+ allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"},
85
+ {"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `test_db`.* TO 'test'@'host"},
86
+ {"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `mysql`.* TO 'test'@'host"}])
87
+ end
88
+ it do
89
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': RELOAD\n.*test_db': RELOAD/)
90
+ end
91
+ end
92
+ context "with all required privileges in all databases" do
93
+ before do
94
+ allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT SELECT, LOCK TABLES, RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"}])
95
+ end
96
+ it do
97
+ expect{subject}.to_not raise_error
98
+ end
99
+ end
100
+ context "with missing privileges in all databases" do
101
+ before do
102
+ allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"}])
103
+ end
104
+ it do
105
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': SELECT, LOCK TABLES\n.*test_db': SELECT, LOCK TABLES/)
106
+ end
107
+ end
108
+ context "with privileges for other databases only" do
109
+ before do
110
+ allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT REPLICATION CLIENT ON `test_db_01`.* TO 'test'@'host"},
111
+ {"Grants for test"=>"GRANT LOCK TABLES ON `test_db_02`.* TO 'test'@'host"},
112
+ {"Grants for test"=>"GRANT SELECT ON `text_db_03`.* TO 'test'@'host"}])
113
+ end
114
+ it do
115
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': SELECT, RELOAD, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT\n.*test_db': SELECT, RELOAD, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT/)
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ describe "#check_mysql_binlog_retention" do
122
+ subject { subject_object.check_mysql_binlog_retention }
123
+ context "on on-premise mysql server" do
124
+ before do
125
+ allow(subject_object).to receive(:is_rds?).and_return(false)
126
+ end
127
+ context "where retention is below limit" do
128
+ before do
129
+ allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 1}])
130
+ end
131
+ it do
132
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /expire_logs_days/)
133
+ end
134
+ end
135
+ context "where retention is 0" do
136
+ before do
137
+ allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 0}])
138
+ end
139
+ it do
140
+ expect{subject}.to_not raise_error
141
+ end
142
+ end
143
+ context "where retention is above limit" do
144
+ before do
145
+ allow(client).to receive(:query).and_return([{"expire_logs_days"=>11}])
146
+ allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 11}])
147
+ end
148
+ it do
149
+ expect{subject}.to_not raise_error
150
+ end
151
+ end
152
+ end
153
+ context "on RDS" do
154
+ before do
155
+ allow(subject_object).to receive(:is_rds?).and_return(true)
156
+ end
157
+ before do
158
+ allow(client).to receive(:query).with("SELECT @@expire_logs_days").and_return([{"@@expire_logs_days"=>0}])
159
+ end
160
+
161
+
162
+ context "where retention period is nil" do
163
+ before do
164
+ allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>nil}])
165
+ end
166
+ it do
167
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /rds_set_config/)
168
+ end
169
+ end
170
+ context "where retention period is too low" do
171
+ before do
172
+ allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>4}])
173
+ end
174
+ it do
175
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /rds_set_config/)
176
+ end
177
+ end
178
+ context "where retention period is over recommended limit" do
179
+ before do
180
+ allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>120}])
181
+ end
182
+ it do
183
+ expect{subject}.to_not raise_error
184
+ end
185
+ end
186
+ context "where user has no access to rds configuration" do
187
+ before do
188
+ allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_raise(Mysql2::Error, "execute command denied to user")
189
+ end
190
+ it do
191
+ expect{subject}.to_not raise_error
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ describe "#check_mysql_table_types" do
198
+ subject { subject_object.check_mysql_table_types }
199
+
200
+ let(:de_hash) do
201
+ { "host" => "test",
202
+ "port" => 1234,
203
+ "username" => "test",
204
+ "password" => "password",
205
+ "database" => "test_db",
206
+ "tables"=>["normal_table", "engine_table", "view_table"] }
207
+ end
208
+ let(:normal_table) { {"table_name"=>"normal_table", "table_type"=>"BASE TABLE", "engine"=>"InnoDB"} }
209
+ let(:engine_table) { {"table_name"=>"engine_table", "table_type"=>"BASE TABLE", "engine"=>"MEMORY"} }
210
+ let(:blackhole_table) { {"table_name"=>"blackhole_table", "table_type"=>"BASE TABLE", "engine"=>"BLACKHOLE"} }
211
+ let(:view) { {"table_name"=>"view_table", "table_type"=>"VIEW", "engine"=>nil} }
212
+ let(:error) { FlydataCore::MysqlCompatibilityError }
213
+ let(:base_error_msg) { "FlyData does not support VIEW and MEMORY,BLACKHOLE STORAGE ENGINE table. Remove following tables from data entry: %s" }
214
+ before do
215
+ allow(client).to receive(:query).and_return(table_list)
216
+ allow(client).to receive(:escape).and_return("aaa")
217
+ end
218
+ context "where data entry has VIEW and MEMORY engine table" do
219
+ let(:error_msg) { base_error_msg % engine_table['table_name'] + ', ' + view['table_name'] }
220
+ let(:table_list) { [ engine_table, view ] }
221
+ it { expect{subject}.to raise_error(error, /#{error_msg}/) }
222
+ end
223
+ context "where data entry has MEMORY engine table" do
224
+ let(:error_msg) { base_error_msg % engine_table['table_name'] }
225
+ let(:table_list) { [ engine_table ] }
226
+ it { expect{subject}.to raise_error(error, /#{error_msg}/) }
227
+ end
228
+ context "where data entry has BLACKHOLE engine table" do
229
+ let(:error_msg) { base_error_msg % blackhole_table['table_name'] }
230
+ let(:table_list) { [ blackhole_table ] }
231
+ it { expect{subject}.to raise_error(error, /#{error_msg}/) }
232
+ end
233
+ context "where data entry has the VIEW" do
234
+ let(:error_msg) { base_error_msg % view['table_name'] }
235
+ let(:table_list) { [ view ] }
236
+ it { expect{subject}.to raise_error(error, /#{error_msg}/) }
237
+ end
238
+ context "where data entry does not have either VIEW and ENGINE table" do
239
+ let(:table_list) { [ normal_table ] }
240
+ it { expect{subject}.to_not raise_error }
241
+ end
242
+ end
243
+
244
+ describe "#check_rds_master_status" do
245
+ subject { subject_object.check_rds_master_status }
246
+
247
+ let(:master_status) { [] }
248
+
249
+ before do
250
+ allow(client).to receive(:query).and_return(master_status)
251
+ end
252
+
253
+ context 'when host is rds' do
254
+ before do
255
+ de_hash['host'] = 'rdrss.xxyyzz.rds.amazonaws.com'
256
+ end
257
+
258
+ context "where backup retention period is not set" do
259
+ let(:master_status) { [] }
260
+ it { expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /Backup Retention Period/) }
261
+ end
262
+
263
+ context "where backup retention period is set" do
264
+ let(:master_status) do
265
+ [{
266
+ 'File' => 'mysql-bin-changelog.026292',
267
+ 'Position' => '31300',
268
+ 'Binlog_Do_DB' => '',
269
+ 'Binlog_Ignore_DB' => '',
270
+ 'Executed_Gtid_Set' => '',
271
+ }]
272
+ end
273
+ it { expect{subject}.not_to raise_error }
274
+ end
275
+ end
276
+ end
277
+ end
278
+
279
+ end
280
+ end
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
- require 'flydata/parser_provider'
2
+ require 'flydata/parser/parser_provider'
3
3
 
4
4
  describe 'MysqlAlterTableParser' do
5
5
  before do
6
6
  #load parser
7
- @parser_class = Mysql::ParserProvider.parser(:mysql, :mysql_alter_table)
7
+ @parser_class = Flydata::Parser::ParserProvider.parser(:mysql, :mysql_alter_table)
8
8
  end
9
9
 
10
10
  let(:query) { "" }
@@ -3,11 +3,12 @@ require 'spec_helper'
3
3
  require 'open3'
4
4
  require 'mysql2'
5
5
  require 'flydata/command/sync'
6
- require 'flydata/parser/mysql/dump_parser'
6
+ require 'flydata/source_mysql/parser/dump_parser'
7
+ require 'flydata-core/mysql/binlog_pos'
7
8
 
8
9
  module Flydata
9
- module Parser
10
- module Mysql
10
+ module SourceMysql
11
+ module Parser
11
12
  context "Test Dump Generators" do
12
13
  let(:stdin) do
13
14
  s = double(:stdin)
@@ -153,8 +154,9 @@ EOT
153
154
  content[0...content.index(string)].bytesize + string.bytesize + 1
154
155
  end
155
156
 
156
- let(:default_parser) { MysqlDumpParser.new(binlog_pos: default_binlog_pos) }
157
+ let(:default_parser) { MysqlDumpParser.new(source_pos: default_binlog_pos_object) }
157
158
  let(:default_binlog_pos) { {binfile: 'mysql-bin.000267', pos: 120 } }
159
+ let(:default_binlog_pos_object) { FlydataCore::Mysql::BinlogPos.new(default_binlog_pos) }
158
160
  let(:dump_pos_after_binlog_pos) { index_after(DUMP_HEADER, '5.6.13-log') }
159
161
 
160
162
  let(:create_table_block) { double('create_table_block') }
@@ -210,30 +212,30 @@ EOT
210
212
  }
211
213
  before { generate_dump_file(dump_content) }
212
214
  it do
213
- expect(create_table_block).to receive(:call) { |mysql_table|
214
- expect(mysql_table.table_name).to eq('users_login')
215
+ expect(create_table_block).to receive(:call) { |source_table|
216
+ expect(source_table.table_name).to eq('users_login')
215
217
  }.once
216
218
  expect(insert_record_block).to receive(:call).never
217
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
218
- expect(mysql_table).to be_nil
219
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
220
+ expect(source_table).to be_nil
219
221
  expect(last_pos).to eq(dump_pos_after_binlog_pos)
220
222
  expect(binlog_pos).to eq(default_binlog_pos)
221
- expect(state).to eq(MysqlDumpParser::State::CREATE_TABLE)
223
+ expect(state).to eq(Flydata::Parser::State::CREATE_TABLE)
222
224
  expect(substate).to be_nil
223
225
  }
224
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
225
- expect(mysql_table.table_name).to eq('users_login')
226
- expect(mysql_table.columns.keys).to eq([col_name, 'login_count', 'create_time', 'update_time'])
226
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
227
+ expect(source_table.table_name).to eq('users_login')
228
+ expect(source_table.columns.keys).to eq([col_name, 'login_count', 'create_time', 'update_time'])
227
229
  expect(last_pos).to eq(index_after(dump_content, 'ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\'\';'))
228
230
  expect(binlog_pos).to eq(default_binlog_pos)
229
- expect(state).to eq(MysqlDumpParser::State::INSERT_RECORD)
231
+ expect(state).to eq(Flydata::Parser::State::INSERT_RECORD)
230
232
  expect(substate).to be_nil
231
233
  }
232
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
233
- expect(mysql_table.table_name).to eq('users_login')
234
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
235
+ expect(source_table.table_name).to eq('users_login')
234
236
  expect(last_pos).to eq(index_after(dump_content, 'UNLOCK TABLES;'))
235
237
  expect(binlog_pos).to eq(default_binlog_pos)
236
- expect(state).to eq(MysqlDumpParser::State::CREATE_TABLE)
238
+ expect(state).to eq(Flydata::Parser::State::CREATE_TABLE)
237
239
  expect(substate).to be_nil
238
240
  }
239
241
  expect(check_point_block).to receive(:call).never
@@ -302,9 +304,9 @@ EOT
302
304
  before { generate_dump_file(dump_content) }
303
305
  it do
304
306
  # create_table_block
305
- expect(create_table_block).to receive(:call) { |mysql_table|
306
- expect(mysql_table.table_name).to eq('users_login')
307
- expect(mysql_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
307
+ expect(create_table_block).to receive(:call) { |source_table|
308
+ expect(source_table.table_name).to eq('users_login')
309
+ expect(source_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
308
310
  }.once
309
311
  expect(create_table_block).to receive(:call).never
310
312
 
@@ -316,8 +318,8 @@ EOT
316
318
  [ %w(373 31 out'swearing 1979-10-07\ 08:10:08 2006-02-22\ 16:26:04),
317
319
  %w(493 8 schizophrenic 1979-07-06\ 07:34:07 1970-08-09\ 01:21:01),]
318
320
  ].each do |expected_values|
319
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
320
- expect(mysql_table.table_name).to eq('users_login')
321
+ expect(insert_record_block).to receive(:call) { |source_table, values_set|
322
+ expect(source_table.table_name).to eq('users_login')
321
323
  expect(values_set).to eq(expected_values)
322
324
  nil
323
325
  }.once
@@ -326,13 +328,13 @@ EOT
326
328
 
327
329
  # insert_record_block
328
330
  [
329
- {state: MysqlDumpParser::State::CREATE_TABLE},
330
- {state: MysqlDumpParser::State::INSERT_RECORD},
331
- {state: MysqlDumpParser::State::CREATE_TABLE,
331
+ {state: Flydata::Parser::State::CREATE_TABLE},
332
+ {state: Flydata::Parser::State::INSERT_RECORD},
333
+ {state: Flydata::Parser::State::CREATE_TABLE,
332
334
  last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
333
335
  ].each do |expected_params|
334
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
335
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
336
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
337
+ expect(source_table.table_name).to eq('users_login') if source_table
336
338
  expect(state).to eq(expected_params[:state])
337
339
  if expected_params[:last_pos]
338
340
  expect(last_pos).to eq(expected_params[:last_pos])
@@ -384,9 +386,9 @@ EOT
384
386
  before { generate_dump_file(dump_content) }
385
387
  it do
386
388
  # create_table_block
387
- expect(create_table_block).to receive(:call) { |mysql_table|
388
- expect(mysql_table.table_name).to eq('users_login')
389
- expect(mysql_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
389
+ expect(create_table_block).to receive(:call) { |source_table|
390
+ expect(source_table.table_name).to eq('users_login')
391
+ expect(source_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
390
392
  }.once
391
393
  expect(create_table_block).to receive(:call).never
392
394
 
@@ -396,8 +398,8 @@ EOT
396
398
  ['35', '6', nil, '1991-10-15 19:38:07', '1970-10-01 22:03:10'],
397
399
  %w(52 33 subfield 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
398
400
  ].each do |expected_values|
399
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
400
- expect(mysql_table.table_name).to eq('users_login')
401
+ expect(insert_record_block).to receive(:call) { |source_table, values_set|
402
+ expect(source_table.table_name).to eq('users_login')
401
403
  expect(values_set).to eq(expected_values)
402
404
  nil
403
405
  }.once
@@ -406,13 +408,13 @@ EOT
406
408
 
407
409
  # insert_record_block
408
410
  [
409
- {state: MysqlDumpParser::State::CREATE_TABLE},
410
- {state: MysqlDumpParser::State::INSERT_RECORD},
411
- {state: MysqlDumpParser::State::CREATE_TABLE,
411
+ {state: Flydata::Parser::State::CREATE_TABLE},
412
+ {state: Flydata::Parser::State::INSERT_RECORD},
413
+ {state: Flydata::Parser::State::CREATE_TABLE,
412
414
  last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
413
415
  ].each do |expected_params|
414
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
415
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
416
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
417
+ expect(source_table.table_name).to eq('users_login') if source_table
416
418
  expect(state).to eq(expected_params[:state])
417
419
  if expected_params[:last_pos]
418
420
  expect(last_pos).to eq(expected_params[:last_pos])
@@ -472,16 +474,16 @@ EOT
472
474
  Proc.new{
473
475
  raise "Should not be called"
474
476
  },
475
- Proc.new{ |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
476
- if mysql_table
477
- @mysql_table = mysql_table
477
+ Proc.new{ |source_table, last_pos, bytesize, binlog_pos, state, substate|
478
+ if source_table
479
+ @source_table = source_table
478
480
  @option = { status: Flydata::Command::Sync::STATUS_PARSING,
479
- table_name: mysql_table.table_name,
481
+ table_name: source_table.table_name,
480
482
  last_pos: last_pos,
481
483
  binlog_pos: binlog_pos,
482
484
  state: state,
483
485
  substate: substate,
484
- mysql_table: mysql_table }
486
+ source_table: source_table }
485
487
  end
486
488
  }
487
489
  )
@@ -490,15 +492,16 @@ EOT
490
492
  table_name: 'users_login',
491
493
  last_pos: index_after(dump_content_head, 'ENGINE=InnoDB DEFAULT CHARSET=utf8;'),
492
494
  binlog_pos: default_binlog_pos,
493
- state: MysqlDumpParser::State::INSERT_RECORD,
495
+ state: Flydata::Parser::State::INSERT_RECORD,
494
496
  substate: nil,
495
- mysql_table: @mysql_table
497
+ source_table: @source_table
496
498
  })
497
499
  end
498
500
  it do
499
501
  generate_dump_file(dump_content_all)
502
+ @option.delete(:binlog_pos)
503
+ @option.merge!( {source_pos: default_binlog_pos_object} )
500
504
  parser_for_resume = MysqlDumpParser.new(@option)
501
-
502
505
  # create_table_block
503
506
  expect(create_table_block).to receive(:call).never
504
507
 
@@ -508,8 +511,8 @@ EOT
508
511
  %w(35 6 missteer 1991-10-15\ 19:38:07 1970-10-01\ 22:03:10),
509
512
  %w(52 33 subfield 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
510
513
  ].each do |expected_values|
511
- expect(insert_record_block).to receive(:call) { |mysql_table, values|
512
- expect(mysql_table.table_name).to eq('users_login')
514
+ expect(insert_record_block).to receive(:call) { |source_table, values|
515
+ expect(source_table.table_name).to eq('users_login')
513
516
  expect(values).to eq(expected_values)
514
517
  nil
515
518
  }.once
@@ -518,11 +521,11 @@ EOT
518
521
 
519
522
  # check_point_block
520
523
  [
521
- {state: MysqlDumpParser::State::CREATE_TABLE,
524
+ {state: Flydata::Parser::State::CREATE_TABLE,
522
525
  last_pos: index_after(dump_content_all, 'UNLOCK TABLES;')}
523
526
  ].each do |expected_params|
524
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
525
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
527
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
528
+ expect(source_table.table_name).to eq('users_login') if source_table
526
529
  expect(state).to eq(expected_params[:state])
527
530
  if expected_params[:last_pos]
528
531
  expect(last_pos).to eq(expected_params[:last_pos])
@@ -582,16 +585,16 @@ EOT
582
585
  dump_io,
583
586
  Proc.new{},
584
587
  insert_record_block_for_resume,
585
- Proc.new{ |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
588
+ Proc.new{ |source_table, last_pos, bytesize, binlog_pos, state, substate|
586
589
  if last_pos == index_after(dump_content, "'1972-08-23 20:16:08','1974-10-10 23:28:11');")
587
- @mysql_table = mysql_table
590
+ @source_table = source_table
588
591
  @option = { status: Flydata::Command::Sync::STATUS_PARSING,
589
- table_name: mysql_table.table_name,
592
+ table_name: source_table.table_name,
590
593
  last_pos: last_pos,
591
594
  binlog_pos: binlog_pos,
592
595
  state: state,
593
596
  substate: substate,
594
- mysql_table: mysql_table }
597
+ source_table: source_table }
595
598
  end
596
599
  }
597
600
  )
@@ -600,13 +603,15 @@ EOT
600
603
  table_name: 'users_login',
601
604
  last_pos: index_after(dump_content, "'1972-08-23 20:16:08','1974-10-10 23:28:11');"),
602
605
  binlog_pos: default_binlog_pos,
603
- state: MysqlDumpParser::State::INSERT_RECORD,
606
+ state: Flydata::Parser::State::INSERT_RECORD,
604
607
  substate: nil,
605
- mysql_table: @mysql_table
608
+ source_table: @source_table
606
609
  })
607
610
  end
608
611
  it do
609
612
  generate_dump_file(dump_content)
613
+ @option.delete(:binlog_pos)
614
+ @option.merge!({source_pos: default_binlog_pos_object})
610
615
  parser_for_resume = MysqlDumpParser.new(@option)
611
616
 
612
617
  # create_table_block
@@ -617,8 +622,8 @@ EOT
617
622
  [ %w(194 11 pandemonium 2008-01-22\ 22:15:10 1991-04-04\ 17:30:05),
618
623
  %w(230 7 cloudburst 2010-12-28\ 11:46:11 1971-06-22\ 13:08:01),],
619
624
  ].each do |expected_values|
620
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
621
- expect(mysql_table.table_name).to eq('users_login')
625
+ expect(insert_record_block).to receive(:call) { |source_table, values_set|
626
+ expect(source_table.table_name).to eq('users_login')
622
627
  expect(values_set).to eq(expected_values)
623
628
  nil
624
629
  }.once
@@ -627,11 +632,11 @@ EOT
627
632
 
628
633
  # check_point_block
629
634
  [
630
- {state: MysqlDumpParser::State::CREATE_TABLE,
635
+ {state: Flydata::Parser::State::CREATE_TABLE,
631
636
  last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
632
637
  ].each do |expected_params|
633
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
634
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
638
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
639
+ expect(source_table.table_name).to eq('users_login') if source_table
635
640
  expect(state).to eq(expected_params[:state])
636
641
  if expected_params[:last_pos]
637
642
  expect(last_pos).to eq(expected_params[:last_pos])
@@ -684,9 +689,9 @@ EOT
684
689
  before { generate_dump_file(dump_content) }
685
690
  it do
686
691
  # create_table_block
687
- expect(create_table_block).to receive(:call) { |mysql_table|
688
- expect(mysql_table.table_name).to eq('users_login')
689
- expect(mysql_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
692
+ expect(create_table_block).to receive(:call) { |source_table|
693
+ expect(source_table.table_name).to eq('users_login')
694
+ expect(source_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
690
695
  }.once
691
696
  expect(create_table_block).to receive(:call).never
692
697
 
@@ -698,8 +703,8 @@ EOT
698
703
  [ ['373','31',"outs\nwearing",'1979-10-07 08:10:08','2006-02-22 16:26:04'],
699
704
  ['493','8',"schiz\tophrenic",'1979-07-06 07:34:07\'),','1970-08-09,01:21:01,\')'] ]
700
705
  ].each do |expected_values|
701
- expect(insert_record_block).to receive(:call) { |mysql_table, values_set|
702
- expect(mysql_table.table_name).to eq('users_login')
706
+ expect(insert_record_block).to receive(:call) { |source_table, values_set|
707
+ expect(source_table.table_name).to eq('users_login')
703
708
  expect(values_set).to eq(expected_values)
704
709
  nil
705
710
  }.once
@@ -708,13 +713,13 @@ EOT
708
713
 
709
714
  # insert_record_block
710
715
  [
711
- {state: MysqlDumpParser::State::CREATE_TABLE},
712
- {state: MysqlDumpParser::State::INSERT_RECORD},
713
- {state: MysqlDumpParser::State::CREATE_TABLE,
716
+ {state: Flydata::Parser::State::CREATE_TABLE},
717
+ {state: Flydata::Parser::State::INSERT_RECORD},
718
+ {state: Flydata::Parser::State::CREATE_TABLE,
714
719
  last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
715
720
  ].each do |expected_params|
716
- expect(check_point_block).to receive(:call) { |mysql_table, last_pos, bytesize, binlog_pos, state, substate|
717
- expect(mysql_table.table_name).to eq('users_login') if mysql_table
721
+ expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
722
+ expect(source_table.table_name).to eq('users_login') if source_table
718
723
  expect(state).to eq(expected_params[:state])
719
724
  if expected_params[:last_pos]
720
725
  expect(last_pos).to eq(expected_params[:last_pos])