dbexpect 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +41 -0
  4. data/COPYING +674 -0
  5. data/Gemfile +20 -0
  6. data/Gemfile.lock +45 -0
  7. data/LICENSE.txt +2 -0
  8. data/README.md +106 -0
  9. data/Rakefile +65 -0
  10. data/VERSION +1 -0
  11. data/bin/dbexpect +33 -0
  12. data/bin/great-expectations +28 -0
  13. data/bin/ready-rig +27 -0
  14. data/database.yml +9 -0
  15. data/lib/dbexpect.rb +19 -0
  16. data/lib/dbexpect/command_runner.rb +21 -0
  17. data/lib/dbexpect/console_formatter.rb +40 -0
  18. data/lib/dbexpect/d_s_l_parser.rb +124 -0
  19. data/lib/dbexpect/database.rb +59 -0
  20. data/lib/dbexpect/db_null.rb +25 -0
  21. data/lib/dbexpect/db_sequence.rb +26 -0
  22. data/lib/dbexpect/db_string.rb +29 -0
  23. data/lib/dbexpect/dbexpect.rb +87 -0
  24. data/lib/dbexpect/defaulting_row_set.rb +68 -0
  25. data/lib/dbexpect/expectation_checker.rb +32 -0
  26. data/lib/dbexpect/expectation_tree_node.rb +67 -0
  27. data/lib/dbexpect/expectations/expectation.rb +45 -0
  28. data/lib/dbexpect/expectations/row_count_expectation.rb +32 -0
  29. data/lib/dbexpect/expectations/row_expectation.rb +32 -0
  30. data/lib/dbexpect/odbc_connection.rb +47 -0
  31. data/lib/dbexpect/row.rb +43 -0
  32. data/lib/dbexpect/table.rb +71 -0
  33. data/spec/dbexpect_integration_spec.rb +131 -0
  34. data/spec/defaulting_row_set_spec.rb +37 -0
  35. data/spec/expectation_checker_spec.rb +47 -0
  36. data/spec/expectations/row_expectation_spec.rb +51 -0
  37. data/spec/fixtures/basic_test_expected_inserts.sql +6 -0
  38. data/spec/fixtures/cleanup_db.sql +2 -0
  39. data/spec/fixtures/expected_output.txt +11 -0
  40. data/spec/fixtures/sample_db.sql +12 -0
  41. data/spec/fixtures/sample_project/database.yml +9 -0
  42. data/spec/fixtures/sample_project/defaults/defaults.rb +5 -0
  43. data/spec/fixtures/sample_project/tests/basic_test.rb +41 -0
  44. data/spec/fixtures/sample_project/tests/test2.rb +3 -0
  45. data/spec/spec_helper.rb +28 -0
  46. metadata +186 -0
@@ -0,0 +1,32 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ require_relative 'expectation'
18
+ class RowCountExpectation < Expectation
19
+ def initialize(db_name,schema,table,count)
20
+ @count = count
21
+ super(db_name,schema,table)
22
+ end
23
+
24
+ def where_clause
25
+ "1=1"
26
+ end
27
+
28
+ def expect_msg
29
+ "Expected #{@schema}.#{@table} to contain #{@count} rows, "
30
+ end
31
+
32
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ require_relative 'expectation'
18
+ class RowExpectation < Expectation
19
+ def initialize(db_name,schema,table,row_data)
20
+ @row = row_data
21
+ @count = 1
22
+ super(db_name,schema,table)
23
+ end
24
+
25
+ def where_clause
26
+ @row.where_clause
27
+ end
28
+
29
+ def expect_msg
30
+ "Expected #{@schema}.#{@table} to contain a row where #{where_clause}, "
31
+ end
32
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ require 'rubygems'
18
+ require 'yaml'
19
+ require 'odbc'
20
+
21
+ class OdbcConnection
22
+ class DatabaseException < Exception; end
23
+
24
+ attr_accessor :type
25
+ def initialize(dsn,db_config)
26
+ @connection = ODBC.connect(
27
+ db_config['database'],
28
+ db_config['username'],
29
+ db_config['password']
30
+ )
31
+
32
+ @type = db_config['type']
33
+ end
34
+
35
+ def run(stmt)
36
+ return [] if stmt.empty?
37
+ begin
38
+ query = @connection.run(stmt)
39
+ res = query.to_a
40
+ query.drop
41
+ rescue ODBC::Error => e
42
+ raise DatabaseException.new(e.message)
43
+ end
44
+ res
45
+ end
46
+
47
+ end
@@ -0,0 +1,43 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ class Row
18
+ attr_accessor :row
19
+ def initialize(row,column_order)
20
+ @row = row
21
+ @column_order = column_order
22
+ end
23
+
24
+ def insert_stmt(schema,name)
25
+ stmt = <<SQL
26
+ INSERT INTO #{schema}.#{name} (#{columns})
27
+ VALUES #{row_values}
28
+ SQL
29
+ end
30
+
31
+ def row_values
32
+ '(' + @column_order.map {|col| row[col].db_str }.join(',') + ')'
33
+ end
34
+
35
+ def where_clause
36
+ @column_order.map {|col| "#{col} #{row[col].equality_test}" }.join(' AND ')
37
+ end
38
+
39
+ def columns
40
+ @column_order.join(',')
41
+ end
42
+
43
+ end
@@ -0,0 +1,71 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ require_relative 'defaulting_row_set'
18
+ require_relative 'expectation_checker'
19
+ require_relative 'expectations/row_count_expectation'
20
+ require_relative 'expectations/row_expectation'
21
+
22
+ class Table
23
+
24
+ def initialize(db_name,schema,name)
25
+ @schema = schema
26
+ @name = name
27
+ @db_name = db_name
28
+
29
+ @expected_row_factory = DefaultingRowSet.new
30
+ @fixture_rows = DefaultingRowSet.new
31
+
32
+ @dirty = false
33
+ end
34
+
35
+ def set_default(column,value)
36
+ @fixture_rows.set_default(column, value)
37
+ end
38
+
39
+ def set_expected_default(column,value)
40
+ @expected_row_factory.set_default(column,value)
41
+ end
42
+
43
+ def add_fixture_row(column_values)
44
+ @fixture_rows.add_row(column_values)
45
+ end
46
+
47
+ def add_expected_row(column_values)
48
+ new_expectation(@expected_row_factory.add_row(column_values))
49
+ end
50
+
51
+ def new_expectation(row)
52
+ RowExpectation.new(@db_name,@schema,@name,row)
53
+ end
54
+
55
+ attr_writer :dirty
56
+ def set_up_for_test(databases)
57
+ database = databases[@db_name]
58
+
59
+ raise "Could not find #{@db_name} in #{databases.inspect}" unless database
60
+
61
+ unless @dirty
62
+ database.truncate_table(@schema,@name)
63
+ end
64
+ database.insert_rows(@fixture_rows.insert_statements(@schema,@name))
65
+ end
66
+
67
+ def row_count_check(count)
68
+ RowCountExpectation.new(@db_name,@schema,@name,count)
69
+ end
70
+
71
+ end
@@ -0,0 +1,131 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
18
+ require 'rubygems'
19
+ require 'odbc'
20
+ require 'pry'
21
+ require 'tempfile'
22
+
23
+ describe "Dbexpect" do
24
+ before :each do
25
+ @databases = Database.hash_from_config
26
+ @src_db = @databases[:dbexpect_src].instance_variable_get :@connection
27
+ @tgt_db = @databases[:dbexpect_tgt].instance_variable_get :@connection
28
+
29
+ @src_db.run(File.read('spec/fixtures/sample_db.sql'))
30
+ @tgt_db.run(File.read('spec/fixtures/sample_db.sql'))
31
+
32
+ @output = StringIO.new
33
+
34
+ @test_script = 'spec/fixtures/sample_project/tests/basic_test.rb'
35
+ @test_script2 = 'spec/fixtures/sample_project/tests/test2.rb'
36
+
37
+ @it = Dbexpect.new(@output)
38
+ end
39
+
40
+ def tempfile(content)
41
+ f = Tempfile.new('tempfile')
42
+ f.write content
43
+ f.close
44
+ f.path
45
+ end
46
+
47
+ after :each do
48
+ @tgt_db.run(File.read('spec/fixtures/cleanup_db.sql'))
49
+ @src_db.run(File.read('spec/fixtures/cleanup_db.sql'))
50
+ end
51
+
52
+ describe "setting up a database for a test" do
53
+ before :each do
54
+ @it.setup_test(@test_script,@databases)
55
+ end
56
+
57
+ it "should truncate the source tables and add the fixture rows" do
58
+
59
+ @src_db.run('select * from source.src_table').to_a.should ==
60
+ [
61
+ ["default string", 7, nil],
62
+ ["overridden string", 1, "not null"] ]
63
+ end
64
+
65
+ it "should truncate the expected rows tables" do
66
+ @tgt_db.run('select * from target.tgt_table').to_a.should ==
67
+ []
68
+ end
69
+ end
70
+
71
+ describe "validating expectations" do
72
+ before :each do
73
+ end
74
+
75
+ it "should fail if zero expected rows exist" do
76
+ @output.rewind
77
+ @it.great_expectations(@test_script,@databases).should == 1
78
+ @output.rewind
79
+ @output.read.should == File.read('spec/fixtures/expected_output.txt')
80
+ end
81
+
82
+ it "should pass if exactly correct" do
83
+ @tgt_db.run(File.read('spec/fixtures/basic_test_expected_inserts.sql'))
84
+ @it.great_expectations(@test_script,@databases).should == 0
85
+ end
86
+
87
+ it "should whine if more rows than we want" do
88
+ @tgt_db.run(File.read('spec/fixtures/basic_test_expected_inserts.sql'))
89
+ @tgt_db.run(File.read('spec/fixtures/basic_test_expected_inserts.sql'))
90
+ @it.great_expectations(@test_script,@databases).should == 1
91
+ end
92
+
93
+ it "should be happy if row counts are correct" do
94
+ @tgt_db.run(File.read('spec/fixtures/basic_test_expected_inserts.sql'))
95
+ @it.great_expectations(tempfile("expect_total_rows table(:dbexpect_tgt,:target,:tgt_table), 5"),
96
+ @databases).should == 0
97
+ end
98
+
99
+ it "should whine if row counts are off" do
100
+ @tgt_db.run(File.read('spec/fixtures/basic_test_expected_inserts.sql'))
101
+ @it.great_expectations(tempfile("expect_total_rows table(:dbexpect_tgt,:target,:tgt_table), 10"),
102
+ @databases).should == 1
103
+ end
104
+ end
105
+
106
+ describe "both setting up sources and validating expectations" do
107
+ before :each do
108
+ @command_runner = mock("CommandRunner")
109
+ @command_runner.should_receive(:run).once.with("echo 400")
110
+ end
111
+
112
+ it "should put data in the database" do
113
+ @it.run_test(@test_script,@databases,@command_runner)
114
+ @src_db.run('select * from source.src_table').to_a.should ==
115
+ [
116
+ ["default string", 7, nil],
117
+ ["overridden string", 1, "not null"] ]
118
+ end
119
+
120
+ it "should give us back reasonable pass/fails" do
121
+ @it.run_test(@test_script,@databases,@command_runner).should == 1
122
+ @output.rewind
123
+ @output.read.should == File.read('spec/fixtures/expected_output.txt')
124
+ end
125
+
126
+ it "should not hold state between test runs" do
127
+ @it.run_test(@test_script,@databases,@command_runner)
128
+ @it.run_test(tempfile("expect_total_rows table(:dbexpect_tgt,:target,:tgt_table), 0"),@databases,@command_runner).should == 0
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
18
+
19
+ describe DefaultingRowSet do
20
+ before :each do
21
+ @it = DefaultingRowSet.new
22
+ end
23
+
24
+ describe "generating insert statements" do
25
+ it "should output column/values in the order they were added" do
26
+ @it.set_default(:columnZ,"hello")
27
+ @it.set_default(:column5,"hello")
28
+ @it.set_default(:columnA,"hello")
29
+
30
+ @it.add_row(
31
+ :column01 => 'new',
32
+ :columnZ => 'not hello')
33
+
34
+ @it.rows.first.columns.should == 'columnZ,column5,columnA,column01'
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright 2012 C3 Business Solutions
2
+ #
3
+ # This file is part of dbexpect.
4
+ #
5
+ # dbexpect is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # dbexpect is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with dbexpect. If not, see <http://www.gnu.org/licenses/>.
17
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
18
+
19
+ describe ExpectationChecker do
20
+ describe "validating expectations against the database" do
21
+ before :each do
22
+ @expectations = ExpectationTreeNode.new('root')
23
+ @db = mock
24
+
25
+ @it = ExpectationChecker.new(@db)
26
+ end
27
+
28
+ def stub_expectation(failure_msg)
29
+ m = mock(:failed_validation? => !failure_msg.nil?, :failure_message => failure_msg)
30
+ m.should_receive(:validate_expectation).with(@db)
31
+ [m]
32
+ end
33
+
34
+ it "should gather failure messages for failed expectations" do
35
+ @expectations.add stub_expectation('failure 1')
36
+ @expectations.add stub_expectation(nil)
37
+ @expectations.add stub_expectation('failure 2')
38
+
39
+ @it.check_expectations(@expectations)
40
+ @it.failed_expectations.collect(&:failure_message).should == [
41
+ "failure 1",
42
+ "failure 2"
43
+ ]
44
+ end
45
+
46
+ end
47
+ end