flydata 0.3.5 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/flydata +1 -0
  4. data/flydata-core/lib/flydata-core/core_ext/module.rb +1 -1
  5. data/flydata-core/lib/flydata-core/core_ext/object.rb +1 -1
  6. data/flydata.gemspec +21 -5
  7. data/lib/flydata.rb +5 -8
  8. data/lib/flydata/api/data_entry.rb +2 -0
  9. data/lib/flydata/api/data_port.rb +2 -0
  10. data/lib/flydata/api/redshift_cluster.rb +2 -0
  11. data/lib/flydata/api_client.rb +3 -0
  12. data/lib/flydata/cli.rb +13 -2
  13. data/lib/flydata/command/base.rb +6 -0
  14. data/lib/flydata/command/conf.rb +3 -0
  15. data/lib/flydata/command/crontab.rb +3 -0
  16. data/lib/flydata/command/encrypt.rb +3 -0
  17. data/lib/flydata/command/kill_all.rb +3 -0
  18. data/lib/flydata/command/login.rb +2 -0
  19. data/lib/flydata/command/restart.rb +3 -0
  20. data/lib/flydata/command/routine.rb +3 -0
  21. data/lib/flydata/command/sender.rb +2 -0
  22. data/lib/flydata/command/setlogdel.rb +4 -1
  23. data/lib/flydata/command/setup.rb +7 -2
  24. data/lib/flydata/command/start.rb +3 -0
  25. data/lib/flydata/command/status.rb +3 -0
  26. data/lib/flydata/command/stop.rb +3 -0
  27. data/lib/flydata/command/sync.rb +10 -3
  28. data/lib/flydata/command/version.rb +2 -0
  29. data/lib/flydata/{command_logger.rb → command_loggable.rb} +0 -0
  30. data/lib/flydata/compatibility_check.rb +1 -1
  31. data/lib/flydata/credentials.rb +2 -0
  32. data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +8 -9
  33. data/lib/flydata/fluent-plugins/mysql/alter_table_query_handler.rb +1 -1
  34. data/lib/flydata/fluent-plugins/mysql/binlog_query_dispatcher.rb +1 -1
  35. data/lib/flydata/fluent-plugins/mysql/binlog_query_handler.rb +1 -1
  36. data/lib/flydata/fluent-plugins/mysql/binlog_record_dispatcher.rb +2 -2
  37. data/lib/flydata/fluent-plugins/mysql/binlog_record_handler.rb +1 -1
  38. data/lib/flydata/fluent-plugins/mysql/ddl_query_handler.rb +1 -1
  39. data/lib/flydata/fluent-plugins/mysql/dml_record_handler.rb +1 -1
  40. data/lib/flydata/helpers.rb +0 -10
  41. data/lib/flydata/heroku.rb +3 -0
  42. data/lib/flydata/output/forwarder.rb +1 -1
  43. data/lib/flydata/parser/mysql/dump_parser.rb +29 -31
  44. data/lib/flydata/sync_file_manager.rb +230 -232
  45. data/spec/fly_data_model_spec.rb +1 -0
  46. data/spec/flydata/api/data_entry_spec.rb +1 -0
  47. data/spec/flydata/api_client_spec.rb +18 -0
  48. data/spec/flydata/cli_spec.rb +1 -0
  49. data/spec/flydata/command/base_spec.rb +44 -0
  50. data/spec/flydata/command/conf_spec.rb +21 -0
  51. data/spec/flydata/command/crontab_spec.rb +17 -0
  52. data/spec/flydata/command/encrypt_spec.rb +28 -0
  53. data/spec/flydata/command/kill_all_spec.rb +17 -0
  54. data/spec/flydata/command/login_spec.rb +21 -0
  55. data/spec/flydata/command/restart_spec.rb +17 -0
  56. data/spec/flydata/command/routine_spec.rb +29 -0
  57. data/spec/flydata/command/sender_spec.rb +7 -2
  58. data/spec/flydata/command/setlogdel_spec.rb +18 -0
  59. data/spec/flydata/command/setup_spec.rb +44 -0
  60. data/spec/flydata/command/start_spec.rb +17 -0
  61. data/spec/flydata/command/status_spec.rb +17 -0
  62. data/spec/flydata/command/stop_spec.rb +17 -0
  63. data/spec/flydata/command/sync_spec.rb +1 -0
  64. data/spec/flydata/command/version_spec.rb +14 -0
  65. data/spec/flydata/fluent-plugins/in_mysql_binlog_flydata_spec.rb +1 -1
  66. data/spec/flydata/parser/mysql/dump_parser_spec.rb +23 -73
  67. data/spec/flydata/sync_file_manager_spec.rb +150 -152
  68. metadata +19 -4
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'stringio'
3
+ require 'fly_data_model'
3
4
 
4
5
  if defined? ActiveModel
5
6
  # TestUserModel model
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'flydata/api/data_entry'
2
3
 
3
4
  module Flydata
4
5
  module Api
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'flydata/api_client'
3
+
4
+ module Flydata
5
+ describe ApiClient do
6
+ subject { described_class.instance }
7
+ let(:resource) { double('resource') }
8
+ let(:response) { JSON.parse('{"success":true}') }
9
+
10
+ describe "#post" do
11
+ it do
12
+ expect(RestClient::Resource).to receive(:new).and_return(resource)
13
+ expect(resource).to receive(:post).with(nil, accept: :json).and_return(response.to_json)
14
+ expect(subject.post('/user')).to eq(response)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'flydata/cli'
2
3
 
3
4
  module Flydata
4
5
  describe Cli do
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/base'
3
+
4
+ module Flydata
5
+ module Command
6
+
7
+ describe Base do
8
+ subject { described_class.new }
9
+ let(:data_entries) {
10
+ [{"id"=>4, "data_port_id"=>1, "name"=>"flydata_sync_mysql_2", "log_path"=>nil, "created_at"=>"2015-03-02T03:06:25.000Z", "updated_at"=>"2015-03-02T03:08:02.000Z", "log_deletion"=>nil, "display_name"=>"synctest", "heroku_resource_id"=>nil, "heroku_log_type"=>nil, "log_file_type"=>nil, "log_file_delimiter"=>nil, "enabled"=>true, "type"=>"RedshiftMysqlDataEntry", "tag_name"=>"flydata.c5c0eb3d_dp1.flydata_sync_mysql_2", "tag_name_dev"=>"flydata.c5c0eb3d_dp1.flydata_sync_mysql_2.dev", "data_port_key"=>"c5c0eb3d", "schema_name"=>"", "table_name"=>"", "redshift_schema_name"=>"", "redshift_table_name"=>"", "mysql_data_entry_preference"=>{"host"=>"ubertas.flydata.co", "port"=>3306, "username"=>"mak", "password"=>password, "database"=>"mak_development", "tables"=>"items,orders", "tables_append_only"=>""}}]
11
+ }
12
+ let(:flydata) { double('flydata') }
13
+ let(:path) { '/data_entries' }
14
+ let(:response_body) { data_entries }
15
+ let(:response) { double('response') }
16
+ let(:response_code) { 200 }
17
+ before do
18
+ allow(response).to receive(:code).and_return(response_code)
19
+ allow(flydata).to receive(:get).with(path).and_return(response_body)
20
+ allow(flydata).to receive(:response).and_return(response)
21
+ allow(subject).to receive(:flydata).and_return(flydata)
22
+ end
23
+
24
+ describe '#retrieve_data_entries' do
25
+ context "when MySQL password from server is encrypted" do
26
+ let(:password) { "8xRe5otrYkrnV5vQhufa6g==" }
27
+ let(:response_body) { data_entries }
28
+ before do
29
+ # instantiate response_body with the encrypted password
30
+ response_body
31
+ end
32
+ # override password which data_entries referes to
33
+ let(:password) { 'flydata' }
34
+ it "returns a data entry list with plain MySQL passwords" do
35
+ expect(subject.retrieve_data_entries).to eq(data_entries)
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/conf'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Conf do
7
+ subject { described_class.new }
8
+ let(:de) { {'name' => 'foo'} }
9
+ let(:data_entries) { [de] }
10
+ describe "#run" do
11
+ it do
12
+ expect(subject).to receive(:retrieve_data_entries).and_return(data_entries)
13
+ expect(Flydata::Preference::DataEntryPreference).to receive(:copy_template).with(de).and_return(false)
14
+ expect(Flydata::Preference::DataEntryPreference).to receive(:configurable?).with(de).and_return(false)
15
+
16
+ subject.run
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/crontab'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Crontab do
7
+ subject { described_class.new }
8
+ let(:cron) { double("cron") }
9
+
10
+ it do
11
+ expect(Flydata::Cron).to receive(:new).and_return(cron)
12
+ expect(cron).to receive(:update)
13
+ subject.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/encrypt'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Encrypt do
7
+ subject { described_class.new }
8
+ let(:flydata) { double('flydata') }
9
+ let(:data_port) { double('data_port') }
10
+ let(:key) { 'abcd' }
11
+ let(:dp) { {'key' => key} }
12
+ let(:password) { 'P@ssword' }
13
+ let(:encrypted_password) { '@#$@#' }
14
+
15
+ before do
16
+ expect(subject).to receive(:flydata).and_return(flydata)
17
+ expect(flydata).to receive(:data_port).and_return(data_port)
18
+ expect(data_port).to receive(:get).and_return(dp)
19
+ expect(subject).to receive(:ask).and_return(password)
20
+ end
21
+ it "loads without an error" do
22
+ expect(Flydata::Util::Encryptor).to receive(:encrypt).with(password, key).and_return(encrypted_password)
23
+
24
+ subject.run
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/kill_all'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Kill_all do
7
+ subject { described_class.new }
8
+ let(:sender) { double("sender") }
9
+
10
+ it do
11
+ expect(Flydata::Command::Sender).to receive(:new).and_return(sender)
12
+ expect(sender).to receive(:kill_all)
13
+ subject.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/login'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Login do
7
+ subject { described_class.new }
8
+ let(:ask_text) { "answer" }
9
+ let(:flydata) { double('flydata') }
10
+
11
+ before do
12
+ allow(subject).to receive(:flydata).and_return(flydata)
13
+ allow(subject).to receive(:ask).and_return(ask_text)
14
+ end
15
+ it do
16
+ expect(flydata).to receive(:post)
17
+ expect(subject.run).to eq true
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/restart'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Restart do
7
+ subject { described_class.new }
8
+ let(:sender) { double("sender") }
9
+
10
+ it do
11
+ expect(Flydata::Command::Sender).to receive(:new).and_return(sender)
12
+ expect(sender).to receive(:restart)
13
+ subject.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/routine'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Routine do
7
+ subject { described_class.new }
8
+ let(:flydata) { double('flydata') }
9
+ let(:credentials) { double('credentials') }
10
+ let(:path) { '/tmp' }
11
+
12
+ before do
13
+ expect(subject).to receive(:flydata).and_return(flydata)
14
+ expect(flydata).to receive(:credentials).and_return(credentials)
15
+ expect(credentials).to receive(:authenticated?).and_return(true)
16
+ expect(subject).to receive(:retrieve_log_paths).and_return([path])
17
+ end
18
+ let(:log_monitor) { double('log_monitor') }
19
+ let(:setup) { double('setup') }
20
+ it "loads without an error" do
21
+ expect(Flydata::LogMonitor).to receive(:new).with(path).and_return(log_monitor)
22
+ expect(log_monitor).to receive(:setup).and_return(setup)
23
+ expect(setup).to receive(:rotate)
24
+
25
+ subject.run
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,9 +1,11 @@
1
1
  require 'spec_helper'
2
- require 'slop'
2
+ require 'flydata/command/sender'
3
3
 
4
4
  module Flydata
5
5
  module Command
6
6
  describe Sender do
7
+ let(:flydata) { double("flydata") }
8
+ let(:data_port) { double("data_port") }
7
9
  let(:opts) do
8
10
  slop = Sender.slop_start
9
11
  slop.parse(args)
@@ -16,7 +18,10 @@ module Flydata
16
18
  expect(subject).to receive(:wait_until_server_ready)
17
19
  expect(subject).to receive(:wait_until_client_ready)
18
20
  allow(Kernel).to receive(:sleep)
19
- allow_any_instance_of(Flydata::Api::DataPort).to receive(:get).and_return("Wibble")
21
+ allow(subject).to receive(:flydata).and_return(flydata)
22
+ allow(flydata).to receive(:data_port).and_return(data_port)
23
+ allow(data_port).to receive(:get).and_return("Wibble")
24
+
20
25
  allow_any_instance_of(Flydata::AgentCompatibilityCheck).to receive(:check).and_return(true)
21
26
  Flydata::Command::Sync.any_instance.should_receive(:try_mysql_sync).and_return("Wobble")
22
27
  end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/setlogdel'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Setlogdel do
7
+ subject { described_class.new }
8
+ let(:login) { double("login") }
9
+
10
+ it "loads without an error" do
11
+ expect(Flydata::Command::Login).to receive(:new).and_return(login)
12
+ expect(login).to receive(:run)
13
+ expect(subject).to receive(:retrieve_data_entries).and_return([])
14
+ subject.run
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/setup'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Setup do
7
+ subject { described_class.new }
8
+ let(:sender) { double("sender") }
9
+ let(:de) { {'type' => 'RedshiftMysqlDataEntry'} }
10
+ let(:data_entries) { [ de ] }
11
+ let(:flydata) { double('flydata') }
12
+ let(:data_port) { double('data_port') }
13
+ let(:dp) { double('dp') }
14
+ let(:conf) { double('conf') }
15
+ let(:sync_fm) { double('sync_fm') }
16
+ let(:credentials) { double('credentials') }
17
+ let(:login) { double('login') }
18
+
19
+ before do
20
+ allow(subject).to receive(:retrieve_data_entries).and_return(data_entries)
21
+ allow(subject).to receive(:flydata).and_return(flydata)
22
+ expect(flydata).to receive(:data_port).and_return(data_port)
23
+ allow(flydata).to receive(:flydata_api_host).and_return('localhost')
24
+ expect(flydata).to receive(:credentials).and_return(credentials)
25
+ expect(credentials).to receive(:authenticated?).and_return(false)
26
+ expect(data_port).to receive(:get).and_return(dp)
27
+ expect(sender).to receive(:process_exist?).and_return(true)
28
+ expect(sender).to receive(:stop)
29
+ expect(sync_fm).to receive(:binlog_path).and_return('/tmp')
30
+ expect(conf).to receive(:copy_templates)
31
+ expect(login).to receive(:run)
32
+ expect(sender).to receive(:restart)
33
+ end
34
+ it do
35
+ expect(Flydata::Command::Conf).to receive(:new).and_return(conf)
36
+ expect(Flydata::SyncFileManager).to receive(:new).with(de).and_return(sync_fm)
37
+ expect(Flydata::Command::Login).to receive(:new).and_return(login)
38
+ expect(Flydata::Command::Sender).to receive(:new).and_return(sender).twice
39
+
40
+ subject.initial_run
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/start'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Start do
7
+ subject { described_class.new }
8
+ let(:sender) { double("sender") }
9
+
10
+ it do
11
+ expect(Flydata::Command::Sender).to receive(:new).and_return(sender)
12
+ expect(sender).to receive(:start)
13
+ subject.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/status'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Status do
7
+ subject { described_class.new }
8
+ let(:sender) { double("sender") }
9
+
10
+ it do
11
+ expect(Flydata::Command::Sender).to receive(:new).and_return(sender)
12
+ expect(sender).to receive(:status)
13
+ subject.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/stop'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Stop do
7
+ subject { described_class.new }
8
+ let(:sender) { double("sender") }
9
+
10
+ it do
11
+ expect(Flydata::Command::Sender).to receive(:new).and_return(sender)
12
+ expect(sender).to receive(:stop)
13
+ subject.run
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,6 @@
1
1
  # coding: utf-8
2
2
  require 'spec_helper'
3
+ require 'flydata/command/sync'
3
4
 
4
5
  module Flydata
5
6
  module Command
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'flydata/command/version'
3
+
4
+ module Flydata
5
+ module Command
6
+ describe Version do
7
+ subject { described_class.new }
8
+
9
+ it do
10
+ subject.run
11
+ end
12
+ end
13
+ end
14
+ end
@@ -526,7 +526,7 @@ EOT
526
526
  # Need to make sure no event is sent... how do I do that
527
527
  let(:sync_fm) { double('sync_fm') }
528
528
  before do
529
- Flydata::FileUtil::SyncFileManager.any_instance.should_receive(:get_new_table_list).with(TEST_TABLES.split(","), "pos").and_return([TEST_TABLE])
529
+ Flydata::SyncFileManager.any_instance.should_receive(:get_new_table_list).with(TEST_TABLES.split(","), "pos").and_return([TEST_TABLE])
530
530
 
531
531
  Test.configure_plugin(plugin, TEST_CONFIG)
532
532
  plugin.event_listener(rotate_event)
@@ -82,83 +82,33 @@ module Flydata
82
82
  end
83
83
  end
84
84
  end
85
- describe MysqlDumpGeneratorMasterData do
86
- let(:status) { double(:status) }
87
- let(:dump_io) { File.open(file_path, 'r', encoding: "utf-8") }
88
- let(:default_dump_generator) { MysqlDumpGeneratorMasterData.new(default_conf) }
89
-
90
- describe '#initialize' do
91
- context 'with password' do
92
- subject { default_dump_generator.instance_variable_get(:@dump_cmd) }
93
- it { is_expected.to eq('mysqldump -h localhost -P 3306 -uadmin -p"pass" --default-character-set=utf8 --protocol=tcp --skip-lock-tables ' +
94
- '--single-transaction --hex-blob --flush-logs --master-data=2 dev users groups') }
95
- end
96
- context 'without password' do
97
- let (:dump_generator) do
98
- MysqlDumpGeneratorMasterData.new(default_conf.merge({'password' => ''}))
99
- end
100
- subject { dump_generator.instance_variable_get(:@dump_cmd) }
101
- it { is_expected.to eq('mysqldump -h localhost -P 3306 -uadmin --default-character-set=utf8 --protocol=tcp --skip-lock-tables ' +
102
- '--single-transaction --hex-blob --flush-logs --master-data=2 dev users groups') }
103
- end
104
- end
85
+ end
105
86
 
106
- describe '#dump' do
107
- context 'when exit status is not 0' do
108
- before do
109
- `touch #{file_path}`
110
- expect(status).to receive(:exitstatus).and_return 1
111
- expect(Open3).to receive(:capture3).and_return(
112
- ['(dummy std out)', '(dummy std err)', status]
113
- )
114
- end
115
- it do
116
- expect{ default_dump_generator.dump(file_path) }.to raise_error
117
- expect(File.exists?(file_path)).to be_falsey
118
- end
119
- end
120
- context 'when exit status is 0 but no file' do
121
- before do
122
- expect(status).to receive(:exitstatus).and_return 0
123
- expect(Open3).to receive(:capture3).and_return(
124
- ['(dummy std out)', '(dummy std err)', status]
125
- )
126
- end
127
- it do
128
- expect{ default_dump_generator.dump(file_path) }.to raise_error
129
- expect(File.exists?(file_path)).to be_falsey
130
- end
131
- end
132
- context 'when exit status is 0 but file size is 0' do
133
- before do
134
- `touch #{file_path}`
135
- expect(status).to receive(:exitstatus).and_return 0
136
- expect(Open3).to receive(:capture3).and_return(
137
- ['(dummy std out)', '(dummy std err)', status]
138
- )
139
- end
140
- it do
141
- expect{ default_dump_generator.dump(file_path) }.to raise_error
142
- expect(File.exists?(file_path)).to be_truthy
143
- end
144
- end
145
- context 'when exit status is 0' do
146
- before do
147
- `echo "something..." > #{file_path}`
148
- expect(status).to receive(:exitstatus).and_return 0
149
- expect(Open3).to receive(:capture3).and_return(
150
- ['(dummy std out)', '(dummy std err)', status]
151
- )
152
- end
153
- it do
154
- expect(default_dump_generator.dump(file_path)).to be_truthy
155
- expect(File.exists?(file_path)).to be_truthy
156
- end
87
+ describe FdMysqlClient do
88
+ let(:db_opts) do
89
+ {
90
+ host: 'localhost',
91
+ port: 3306,
92
+ username: 'admin',
93
+ password: 'pass',
94
+ database: 'dev'
95
+ }
96
+ end
97
+ describe '#query' do
98
+ module DummyMysqlClient
99
+ def initialize(opts = {})
157
100
  end
158
- after :each do
159
- File.delete(file_path) if File.exists?(file_path)
101
+ def query(sql, opts = {})
102
+ raise Mysql2::Error.new("Timeout waiting for a response from the last query. (waited 600 seconds)")
160
103
  end
161
104
  end
105
+ it 'raises appropriate error when query times out' do
106
+ described_class.instance_eval { include DummyMysqlClient }
107
+ sql = "FLUSH LOCAL TABLES"
108
+ test_client = described_class.new(db_opts)
109
+ expect{test_client.query(sql)}.to raise_error(RuntimeError, /query timed out when running/)
110
+ expect(test_client.last_query).to eq(sql)
111
+ end
162
112
  end
163
113
  end
164
114