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,59 @@
|
|
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 'odbc_connection'
|
18
|
+
|
19
|
+
class Database
|
20
|
+
def self.from_connection(con)
|
21
|
+
new(con)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.hash_from_config
|
25
|
+
databases = {}
|
26
|
+
YAML.load_file('database.yml').each do |(dsn,config)|
|
27
|
+
databases[dsn.to_sym] = from_connection(OdbcConnection.new(dsn,config))
|
28
|
+
end
|
29
|
+
|
30
|
+
databases
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(con)
|
34
|
+
@connection = con
|
35
|
+
end
|
36
|
+
|
37
|
+
def num_rows_match(schema,table,query)
|
38
|
+
@connection.run("select * from #{schema}.#{table} where (#{query})").count
|
39
|
+
end
|
40
|
+
|
41
|
+
def truncate_table(schema,name)
|
42
|
+
if @connection.type == 'db2'
|
43
|
+
@connection.run("truncate table #{schema}.#{name} immediate")
|
44
|
+
else
|
45
|
+
@connection.run("truncate table #{schema}.#{name}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def insert_rows(insert_statements)
|
50
|
+
insert_statements.each do |stmt|
|
51
|
+
@connection.run(stmt)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def close
|
56
|
+
#@connection.close
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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 DbNull
|
18
|
+
def db_str
|
19
|
+
'NULL'
|
20
|
+
end
|
21
|
+
|
22
|
+
def equality_test
|
23
|
+
"is null"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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 DbSequence
|
18
|
+
def initialize
|
19
|
+
@sequence = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def db_str
|
23
|
+
@sequence += 1
|
24
|
+
@sequence.to_s
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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 DbString
|
18
|
+
def initialize(str)
|
19
|
+
@string = str
|
20
|
+
end
|
21
|
+
|
22
|
+
def db_str
|
23
|
+
"'#{@string}'"
|
24
|
+
end
|
25
|
+
|
26
|
+
def equality_test
|
27
|
+
" = '#{@string}'"
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,87 @@
|
|
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 'db_sequence'
|
18
|
+
require_relative 'db_null'
|
19
|
+
require_relative 'db_string'
|
20
|
+
require_relative 'table'
|
21
|
+
require_relative 'd_s_l_parser'
|
22
|
+
require_relative 'expectation_checker'
|
23
|
+
require_relative 'console_formatter'
|
24
|
+
|
25
|
+
class Dbexpect
|
26
|
+
|
27
|
+
def initialize(output = STDOUT)
|
28
|
+
@output = ConsoleFormatter.new(output)
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_test(script,databases,command_runner)
|
32
|
+
setup_test(script,databases)
|
33
|
+
run_etl(script,command_runner)
|
34
|
+
great_expectations(script,databases)
|
35
|
+
end
|
36
|
+
|
37
|
+
def great_expectations(script, databases)
|
38
|
+
eval_script(script)
|
39
|
+
|
40
|
+
check_table_expectations(databases)
|
41
|
+
|
42
|
+
if validates_expectations?
|
43
|
+
@output.notify_passed
|
44
|
+
return 0
|
45
|
+
else
|
46
|
+
@output.notify_failed(failed_expectations)
|
47
|
+
return 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def setup_test(script,databases)
|
52
|
+
eval_script(script)
|
53
|
+
@tables.each do |table|
|
54
|
+
table.set_up_for_test(databases)
|
55
|
+
end
|
56
|
+
return 0
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
protected
|
61
|
+
def run_etl(script,command_runner)
|
62
|
+
@commands_to_run.each {|c| command_runner.run(c) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def eval_script(script)
|
66
|
+
parser = DSLParser.new
|
67
|
+
parser.parse(File.read(script))
|
68
|
+
@tables = parser.tables
|
69
|
+
@expectation_tree = parser.expectation_tree
|
70
|
+
@commands_to_run = parser.commands
|
71
|
+
end
|
72
|
+
|
73
|
+
def check_table_expectations(databases)
|
74
|
+
@expectation_checker = ExpectationChecker.new(databases)
|
75
|
+
@expectation_checker.check_expectations(@expectation_tree)
|
76
|
+
end
|
77
|
+
|
78
|
+
def failed_expectations
|
79
|
+
@expectation_checker.failed_expectations
|
80
|
+
end
|
81
|
+
|
82
|
+
def validates_expectations?
|
83
|
+
@expectation_checker.validates_expectations?
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,68 @@
|
|
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 'row'
|
18
|
+
class DefaultingRowSet
|
19
|
+
attr_accessor :defaults
|
20
|
+
attr_accessor :columns_in_order
|
21
|
+
attr_accessor :rows
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@defaults = Hash.new
|
25
|
+
@rows = []
|
26
|
+
|
27
|
+
@columns_in_order = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_default(column,value)
|
31
|
+
add_column(column)
|
32
|
+
@defaults[column] = value
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_row(column_values)
|
36
|
+
column_values.keys.map {|col| add_column(col) }
|
37
|
+
|
38
|
+
defaulted_row = set_defaults_at_time_of_addition(column_values)
|
39
|
+
@rows << Row.new(defaulted_row,@columns_in_order & defaulted_row.keys)
|
40
|
+
@rows.last
|
41
|
+
end
|
42
|
+
|
43
|
+
def insert_statements(schema,name)
|
44
|
+
@rows.collect do |row|
|
45
|
+
row.insert_stmt(schema,name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def where_clauses
|
50
|
+
@rows.map(&:where_clause)
|
51
|
+
end
|
52
|
+
|
53
|
+
def empty?
|
54
|
+
@rows.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
def add_column(column)
|
59
|
+
@columns_in_order << column
|
60
|
+
@columns_in_order.uniq!
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_defaults_at_time_of_addition(row)
|
64
|
+
@defaults.merge(row)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
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
|
+
class ExpectationChecker
|
18
|
+
attr_accessor :failed_expectations
|
19
|
+
def initialize(databases)
|
20
|
+
@databases = databases
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_expectations(expectations)
|
24
|
+
expectations.map {|e| e.validate_expectation(@databases) }
|
25
|
+
|
26
|
+
@failed_expectations = expectations.select {|e| e.failed_validation? }
|
27
|
+
end
|
28
|
+
|
29
|
+
def validates_expectations?
|
30
|
+
@failed_expectations.empty?
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,67 @@
|
|
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 ExpectationTreeNode
|
18
|
+
include Enumerable
|
19
|
+
|
20
|
+
def initialize(desc,children = [], expectations = [])
|
21
|
+
@description = desc
|
22
|
+
@children = children
|
23
|
+
@expectations = expectations
|
24
|
+
end
|
25
|
+
|
26
|
+
def each(&block)
|
27
|
+
@expectations.map(&block)
|
28
|
+
@children.each {|c| c.each(&block) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def select(&block)
|
32
|
+
matching_children = @children.collect {|c| c.select(&block) }.
|
33
|
+
reject {|node| node === EmptyTreeNode }
|
34
|
+
|
35
|
+
matching_expectations = @expectations.select(&block)
|
36
|
+
|
37
|
+
return EmptyTreeNode.new if matching_children.empty? && matching_expectations.empty?
|
38
|
+
|
39
|
+
ExpectationTreeNode.new(@description,matching_children,matching_expectations)
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_child(desc)
|
43
|
+
@children << ExpectationTreeNode.new(desc)
|
44
|
+
@children.last
|
45
|
+
end
|
46
|
+
|
47
|
+
def add(expectations)
|
48
|
+
@expectations += expectations
|
49
|
+
end
|
50
|
+
|
51
|
+
def empty?
|
52
|
+
@expectations.empty? && @children.all?(&:empty?)
|
53
|
+
end
|
54
|
+
|
55
|
+
def traverse(depth = 0, &block)
|
56
|
+
block.call(depth,@description,@expectations)
|
57
|
+
@children.map {|c| c.traverse(depth + 1, &block) }
|
58
|
+
end
|
59
|
+
|
60
|
+
class EmptyTreeNode
|
61
|
+
include Enumerable
|
62
|
+
def each(&block); end
|
63
|
+
def empty?; true; end
|
64
|
+
def traverse(depth = 0, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,45 @@
|
|
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 Expectation
|
18
|
+
def initialize(db_name,schema,table)
|
19
|
+
@schema = schema
|
20
|
+
@table = table
|
21
|
+
@db_name = db_name
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_expectation(databases)
|
25
|
+
database = databases[@db_name]
|
26
|
+
begin
|
27
|
+
num = database.num_rows_match(@schema,@table,where_clause)
|
28
|
+
rescue OdbcConnection::DatabaseException => e
|
29
|
+
@failure = expect_msg + "instead database raised error: #{e.message}"
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
if num != @count
|
34
|
+
@failure = expect_msg + "got #{num}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def failed_validation?
|
39
|
+
@failure
|
40
|
+
end
|
41
|
+
|
42
|
+
def failure_message
|
43
|
+
@failure
|
44
|
+
end
|
45
|
+
end
|