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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +41 -0
- data/COPYING +674 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.txt +2 -0
- data/README.md +106 -0
- data/Rakefile +65 -0
- data/VERSION +1 -0
- data/bin/dbexpect +33 -0
- data/bin/great-expectations +28 -0
- data/bin/ready-rig +27 -0
- data/database.yml +9 -0
- data/lib/dbexpect.rb +19 -0
- data/lib/dbexpect/command_runner.rb +21 -0
- data/lib/dbexpect/console_formatter.rb +40 -0
- data/lib/dbexpect/d_s_l_parser.rb +124 -0
- data/lib/dbexpect/database.rb +59 -0
- data/lib/dbexpect/db_null.rb +25 -0
- data/lib/dbexpect/db_sequence.rb +26 -0
- data/lib/dbexpect/db_string.rb +29 -0
- data/lib/dbexpect/dbexpect.rb +87 -0
- data/lib/dbexpect/defaulting_row_set.rb +68 -0
- data/lib/dbexpect/expectation_checker.rb +32 -0
- data/lib/dbexpect/expectation_tree_node.rb +67 -0
- data/lib/dbexpect/expectations/expectation.rb +45 -0
- data/lib/dbexpect/expectations/row_count_expectation.rb +32 -0
- data/lib/dbexpect/expectations/row_expectation.rb +32 -0
- data/lib/dbexpect/odbc_connection.rb +47 -0
- data/lib/dbexpect/row.rb +43 -0
- data/lib/dbexpect/table.rb +71 -0
- data/spec/dbexpect_integration_spec.rb +131 -0
- data/spec/defaulting_row_set_spec.rb +37 -0
- data/spec/expectation_checker_spec.rb +47 -0
- data/spec/expectations/row_expectation_spec.rb +51 -0
- data/spec/fixtures/basic_test_expected_inserts.sql +6 -0
- data/spec/fixtures/cleanup_db.sql +2 -0
- data/spec/fixtures/expected_output.txt +11 -0
- data/spec/fixtures/sample_db.sql +12 -0
- data/spec/fixtures/sample_project/database.yml +9 -0
- data/spec/fixtures/sample_project/defaults/defaults.rb +5 -0
- data/spec/fixtures/sample_project/tests/basic_test.rb +41 -0
- data/spec/fixtures/sample_project/tests/test2.rb +3 -0
- data/spec/spec_helper.rb +28 -0
- 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
|
data/lib/dbexpect/row.rb
ADDED
@@ -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
|