slacker 1.0.14 → 1.0.15
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.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/README.markdown +22 -22
- data/Rakefile +11 -11
- data/bin/slacker +32 -32
- data/bin/slacker_new +34 -34
- data/lib/slacker.rb +180 -175
- data/lib/slacker/application.rb +224 -214
- data/lib/slacker/command_line_formatter.rb +61 -61
- data/lib/slacker/configuration.rb +59 -59
- data/lib/slacker/formatter.rb +14 -14
- data/lib/slacker/query_result_matcher.rb +178 -178
- data/lib/slacker/rspec_ext.rb +57 -57
- data/lib/slacker/rspec_monkey.rb +7 -7
- data/lib/slacker/sql.rb +39 -39
- data/lib/slacker/sql_preprocessor.rb +23 -23
- data/lib/slacker/string_helper.rb +16 -16
- data/lib/slacker/version.rb +3 -3
- data/lib/slacker_new/project/data/sample_1/my_table_expected_power_results.csv +11 -11
- data/lib/slacker_new/project/data/sample_1/my_table_initial_data.csv +11 -11
- data/lib/slacker_new/project/data/sample_1/numbers_expected_output.csv +3 -3
- data/lib/slacker_new/project/database.yml +9 -9
- data/lib/slacker_new/project/lib/helpers/my_helper.rb +1 -1
- data/lib/slacker_new/project/spec/sample_1.rb +66 -66
- data/lib/slacker_new/project/sql/sample_1/my_table_on_power.sql.erb +1 -1
- data/lib/slacker_new/project/sql/sample_1/play_with_numbers.sql.erb +16 -16
- data/lib/slacker_new/project/sql/sample_1/sysobjects_with_params.sql.erb +1 -1
- data/slacker.gemspec +27 -27
- data/spec/application_spec.rb +13 -13
- data/spec/query_result_matcher_spec.rb +268 -268
- data/spec/rspec_ext_spec.rb +87 -87
- data/spec/slacker_spec.rb +59 -59
- data/spec/spec_helper.rb +19 -9
- data/spec/test_files/matcher/test_1.csv +3 -3
- data/spec/test_files/test_slacker_project/data/test_1.csv +3 -3
- data/spec/test_files/test_slacker_project/sql/nest/nested_1.sql.erb +1 -1
- data/spec/test_files/test_slacker_project/sql/no_params.sql.erb +2 -2
- data/spec/test_files/test_slacker_project/sql/params.sql.erb +1 -1
- metadata +24 -24
data/lib/slacker/application.rb
CHANGED
@@ -1,215 +1,225 @@
|
|
1
|
-
require 'logger'
|
2
|
-
require 'rspec/core'
|
3
|
-
require '
|
4
|
-
require 'slacker/
|
5
|
-
require 'slacker/
|
6
|
-
require '
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
set
|
15
|
-
set
|
16
|
-
set
|
17
|
-
set
|
18
|
-
set
|
19
|
-
set
|
20
|
-
set
|
21
|
-
set
|
22
|
-
set
|
23
|
-
set
|
24
|
-
set
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
a['
|
129
|
-
a['
|
130
|
-
a['
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
RSpec
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
#
|
181
|
-
config.
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
config.
|
195
|
-
config.
|
196
|
-
|
197
|
-
config.
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
1
|
+
require 'logger'
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'slacker/rspec_monkey'
|
5
|
+
require 'slacker/rspec_ext'
|
6
|
+
require 'slacker/string_helper'
|
7
|
+
require 'odbc'
|
8
|
+
|
9
|
+
module Slacker
|
10
|
+
class Application
|
11
|
+
attr_reader :target_folder_structure, :temp_folders
|
12
|
+
|
13
|
+
SQL_OPTIONS = <<EOF
|
14
|
+
set textsize 2147483647;
|
15
|
+
set language us_english;
|
16
|
+
set dateformat mdy;
|
17
|
+
set datefirst 7;
|
18
|
+
set lock_timeout -1;
|
19
|
+
set quoted_identifier on;
|
20
|
+
set arithabort on;
|
21
|
+
set ansi_null_dflt_on on;
|
22
|
+
set ansi_warnings on;
|
23
|
+
set ansi_padding on;
|
24
|
+
set ansi_nulls on;
|
25
|
+
set concat_null_yields_null on;
|
26
|
+
EOF
|
27
|
+
|
28
|
+
def initialize(configuration)
|
29
|
+
@configuration = configuration
|
30
|
+
@temp_folders = ['debug/passed_examples', 'debug/failed_examples']
|
31
|
+
@target_folder_structure = ['data', 'debug/passed_examples', 'debug/failed_examples', 'sql', 'spec', 'lib', 'lib/helpers']
|
32
|
+
@error_message = ''
|
33
|
+
@database = ODBC::Database.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def print_connection_message
|
37
|
+
puts "#{@configuration.db_name} (#{@configuration.db_server})" if @configuration.console_enabled
|
38
|
+
end
|
39
|
+
|
40
|
+
# Customize RSpec and run it
|
41
|
+
def run
|
42
|
+
begin
|
43
|
+
error = catch :error_exit do
|
44
|
+
print_connection_message
|
45
|
+
create_temp_folders
|
46
|
+
test_folder_structure
|
47
|
+
cleanup_folders
|
48
|
+
configure
|
49
|
+
run_rspec
|
50
|
+
false # Return false to be stored in error (effectively indicating no error).
|
51
|
+
end
|
52
|
+
ensure
|
53
|
+
cleanup_after_run
|
54
|
+
end
|
55
|
+
|
56
|
+
if @configuration.console_enabled
|
57
|
+
puts @error_message if error
|
58
|
+
else
|
59
|
+
raise @error_message if error
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return true if no error occurred, otherwise false.
|
63
|
+
!error
|
64
|
+
end
|
65
|
+
|
66
|
+
def run_rspec
|
67
|
+
RSpec::Core::Runner.disable_autorun!
|
68
|
+
|
69
|
+
RSpec::Core::Runner.run(@configuration.rspec_args,
|
70
|
+
@configuration.error_stream,
|
71
|
+
@configuration.output_stream)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Configure Slacker
|
75
|
+
def configure
|
76
|
+
configure_db
|
77
|
+
configure_rspec
|
78
|
+
configure_misc
|
79
|
+
end
|
80
|
+
|
81
|
+
def cleanup_after_run
|
82
|
+
@database.disconnect if (@database && @database.connected?)
|
83
|
+
end
|
84
|
+
|
85
|
+
def cleanup_folders
|
86
|
+
cleanup_folder('debug/passed_examples')
|
87
|
+
cleanup_folder('debug/failed_examples')
|
88
|
+
end
|
89
|
+
|
90
|
+
def cleanup_folder(folder)
|
91
|
+
folder_path = get_path(folder)
|
92
|
+
Dir.new(folder_path).each{|file_name| File.delete("#{folder_path}/#{file_name}") if File.file?("#{folder_path}/#{file_name}")}
|
93
|
+
end
|
94
|
+
|
95
|
+
# Get a path relative to the current path
|
96
|
+
def get_path(path)
|
97
|
+
@configuration.expand_path(path)
|
98
|
+
end
|
99
|
+
|
100
|
+
def configure_misc
|
101
|
+
# Add the lib folder to the load path
|
102
|
+
$:.push get_path('lib')
|
103
|
+
# Mixin the helper modules
|
104
|
+
mixin_helpers
|
105
|
+
end
|
106
|
+
|
107
|
+
# Mix in the helper modules
|
108
|
+
def mixin_helpers
|
109
|
+
helpers_dir = get_path('lib/helpers')
|
110
|
+
$:.push helpers_dir
|
111
|
+
Dir.new(helpers_dir).each do |file_name|
|
112
|
+
if file_name =~ /\.rb$/
|
113
|
+
require file_name
|
114
|
+
module_class = Slacker::StringHelper.constantize(Slacker::StringHelper.camelize(file_name.gsub(/\.rb$/,'')))
|
115
|
+
RSpec.configure do |config|
|
116
|
+
config.include(module_class)
|
117
|
+
end
|
118
|
+
Slacker.mixin_module(module_class)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Configure database connection
|
124
|
+
def configure_db
|
125
|
+
drv = ODBC::Driver.new
|
126
|
+
drv.name = 'Driver1'
|
127
|
+
drv.attrs.tap do |a|
|
128
|
+
a['Driver'] = '{SQL Server}'
|
129
|
+
a['Server']= @configuration.db_server
|
130
|
+
a['Database']= @configuration.db_name
|
131
|
+
a['Uid'] = @configuration.db_user
|
132
|
+
a['Pwd'] = @configuration.db_password
|
133
|
+
a['TDS_Version'] = '7.0' #Used by the linux driver
|
134
|
+
end
|
135
|
+
|
136
|
+
begin
|
137
|
+
@database.drvconnect(drv)
|
138
|
+
rescue ODBC::Error => e
|
139
|
+
throw_error("#{e.class}: #{e.message}")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Run a script against the currently configured database
|
144
|
+
def query_script(sql)
|
145
|
+
results = []
|
146
|
+
begin
|
147
|
+
st = @database.run(sql)
|
148
|
+
begin
|
149
|
+
if st.ncols > 0
|
150
|
+
rows = []
|
151
|
+
st.each_hash(false, true){|row| rows << row}
|
152
|
+
results << rows
|
153
|
+
end
|
154
|
+
end while(st.more_results)
|
155
|
+
ensure
|
156
|
+
st.drop unless st.nil?
|
157
|
+
end
|
158
|
+
results.count > 1 ? results : results.first
|
159
|
+
end
|
160
|
+
|
161
|
+
# Customize RSpec
|
162
|
+
def configure_rspec
|
163
|
+
before_proc = lambda do |example|
|
164
|
+
# Initialize the example's SQL
|
165
|
+
example.metadata[:sql] = ''
|
166
|
+
Slacker.query_script(example, 'begin transaction;', 'Initiate the example script')
|
167
|
+
Slacker.query_script(example, SQL_OPTIONS, 'Set default options')
|
168
|
+
end
|
169
|
+
|
170
|
+
after_proc = lambda do |example|
|
171
|
+
Slacker.query_script(example, 'if @@trancount > 0 rollback transaction;', 'Rollback the changes made by the example script')
|
172
|
+
end
|
173
|
+
|
174
|
+
# Reset RSpec through a monkey-patched method
|
175
|
+
RSpec.slacker_reset
|
176
|
+
|
177
|
+
RSpec.configure do |config|
|
178
|
+
|
179
|
+
# Expose the current example to the ExampleGroup extension
|
180
|
+
# This is necessary in order to have this work with RSpec 3
|
181
|
+
config.expose_current_running_example_as :example
|
182
|
+
|
183
|
+
# Global "before" hooks to begin a transaction
|
184
|
+
config.before(:each) do
|
185
|
+
before_proc.call(example)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Global "after" hooks to rollback a transaction
|
189
|
+
config.after(:each) do
|
190
|
+
after_proc.call(example)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Slacker's RSpec extension module
|
194
|
+
config.include(Slacker::RSpecExt)
|
195
|
+
config.extend(Slacker::RSpecExt)
|
196
|
+
|
197
|
+
config.output_stream = @configuration.output_stream
|
198
|
+
config.error_stream = @configuration.error_stream
|
199
|
+
|
200
|
+
config.add_formatter(Slacker::CommandLineFormatter)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Tests the current folder's structure
|
205
|
+
def test_folder_structure()
|
206
|
+
target_folder_structure.each do |dir|
|
207
|
+
if !File.directory?(get_path(dir))
|
208
|
+
throw_error("Cannot find directory \"#{get_path(dir)}\"")
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Create temporary folders if they don't exist
|
214
|
+
def create_temp_folders()
|
215
|
+
temp_folders.each do |dir|
|
216
|
+
FileUtils.mkdir_p(dir)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def throw_error(msg)
|
221
|
+
@error_message = msg
|
222
|
+
throw :error_exit, true
|
223
|
+
end
|
224
|
+
end
|
215
225
|
end
|
@@ -1,61 +1,61 @@
|
|
1
|
-
require 'slacker/formatter'
|
2
|
-
require 'rspec/core/formatters/progress_formatter'
|
3
|
-
|
4
|
-
module Slacker
|
5
|
-
class CommandLineFormatter < RSpec::Core::Formatters::ProgressFormatter
|
6
|
-
include Slacker::Formatter
|
7
|
-
RSpec::Core::Formatters.register self, :example_passed, :example_failed
|
8
|
-
|
9
|
-
def initialize(output)
|
10
|
-
super(output)
|
11
|
-
@failed_examples_count = 0
|
12
|
-
@passed_examples_count = 0
|
13
|
-
end
|
14
|
-
|
15
|
-
def example_passed(notification)
|
16
|
-
super(notification)
|
17
|
-
process_example_debug_output(notification, false)
|
18
|
-
end
|
19
|
-
|
20
|
-
def example_failed(notification)
|
21
|
-
super(notification)
|
22
|
-
process_example_debug_output(notification, true)
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def process_example_debug_output(notification, example_failed)
|
28
|
-
if example_failed
|
29
|
-
@failed_examples_count += 1
|
30
|
-
debug_output(notification, Slacker.configuration.expand_path('debug/failed_examples'), @failed_examples_count, example_failed)
|
31
|
-
else
|
32
|
-
@passed_examples_count += 1
|
33
|
-
debug_output(notification, Slacker.configuration.expand_path('debug/passed_examples'), @passed_examples_count, example_failed)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def debug_output(notification, out_folder, file_number, example_failed)
|
38
|
-
# Write out the SQL
|
39
|
-
File.open("#{out_folder}/example_#{'%03d' % file_number}.sql", 'w') do |out_file|
|
40
|
-
out_file.write(get_formatted_example_sql(notification, example_failed))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def get_formatted_example_sql(notification, example_failed)
|
45
|
-
example = notification.example
|
46
|
-
sql = <<EOF
|
47
|
-
-- Example "#{example.metadata[:full_description]}"
|
48
|
-
-- #{example.metadata[:location]}
|
49
|
-
-- Executed at #{example.execution_result.started_at}
|
50
|
-
|
51
|
-
#{example.metadata[:sql]}
|
52
|
-
|
53
|
-
-- SLACKER RESULTS
|
54
|
-
-- *******************************************
|
55
|
-
#{example_failed ? example_failure_text(notification).split("\n").collect{|line| '-- ' + line}.join("\n") : '-- Example Passed OK'}
|
56
|
-
-- *******************************************
|
57
|
-
EOF
|
58
|
-
sql.strip
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
1
|
+
require 'slacker/formatter'
|
2
|
+
require 'rspec/core/formatters/progress_formatter'
|
3
|
+
|
4
|
+
module Slacker
|
5
|
+
class CommandLineFormatter < RSpec::Core::Formatters::ProgressFormatter
|
6
|
+
include Slacker::Formatter
|
7
|
+
RSpec::Core::Formatters.register self, :example_passed, :example_failed
|
8
|
+
|
9
|
+
def initialize(output)
|
10
|
+
super(output)
|
11
|
+
@failed_examples_count = 0
|
12
|
+
@passed_examples_count = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def example_passed(notification)
|
16
|
+
super(notification)
|
17
|
+
process_example_debug_output(notification, false)
|
18
|
+
end
|
19
|
+
|
20
|
+
def example_failed(notification)
|
21
|
+
super(notification)
|
22
|
+
process_example_debug_output(notification, true)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def process_example_debug_output(notification, example_failed)
|
28
|
+
if example_failed
|
29
|
+
@failed_examples_count += 1
|
30
|
+
debug_output(notification, Slacker.configuration.expand_path('debug/failed_examples'), @failed_examples_count, example_failed)
|
31
|
+
else
|
32
|
+
@passed_examples_count += 1
|
33
|
+
debug_output(notification, Slacker.configuration.expand_path('debug/passed_examples'), @passed_examples_count, example_failed)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def debug_output(notification, out_folder, file_number, example_failed)
|
38
|
+
# Write out the SQL
|
39
|
+
File.open("#{out_folder}/example_#{'%03d' % file_number}.sql", 'w') do |out_file|
|
40
|
+
out_file.write(get_formatted_example_sql(notification, example_failed))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_formatted_example_sql(notification, example_failed)
|
45
|
+
example = notification.example
|
46
|
+
sql = <<EOF
|
47
|
+
-- Example "#{example.metadata[:full_description]}"
|
48
|
+
-- #{example.metadata[:location]}
|
49
|
+
-- Executed at #{example.execution_result.started_at}
|
50
|
+
|
51
|
+
#{example.metadata[:sql]}
|
52
|
+
|
53
|
+
-- SLACKER RESULTS
|
54
|
+
-- *******************************************
|
55
|
+
#{example_failed ? example_failure_text(notification).split("\n").collect{|line| '-- ' + line}.join("\n") : '-- Example Passed OK'}
|
56
|
+
-- *******************************************
|
57
|
+
EOF
|
58
|
+
sql.strip
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|