dbexpect 0.11.0

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 (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