resque-reports 0.3.5 → 0.3.6
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 +5 -13
- data/lib/resque/reports/base_report.rb +37 -27
- data/lib/resque/reports/cache_file.rb +18 -15
- data/lib/resque/reports/common/batched_report.rb +102 -96
- data/lib/resque/reports/extensions/filename_gen.rb +3 -1
- data/lib/resque/reports/extensions/table_building.rb +7 -0
- data/lib/resque/reports/extensions.rb +1 -1
- data/lib/resque/reports/version.rb +1 -1
- data/resque-reports.gemspec +3 -4
- data/spec/resque/reports/base_report_spec.rb +29 -37
- data/spec/resque/reports/csv_report_spec.rb +6 -6
- data/spec/resque/reports/report_job_spec.rb +17 -27
- data/spec/spec_helper.rb +0 -1
- metadata +21 -35
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZWIzNzQwOTcxY2RjOTYxZTk5ZjBlMTY4NjkwNmJjZTU0NjBlZmZlNg==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8dbaf30352c2e435726ec9cc9fe1d6364a850efd
|
4
|
+
data.tar.gz: 6d96fded79937853de430a3c332a56901c0e2ea0
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
NDg4NTgyMDgwMDczNTI4ZDkxNjJlY2JjZmMzMjQ3NTg2YWY2ODZiMzgyMmJh
|
11
|
-
ZDc0ZmNmNGZkYzIyOGFhNWU1NDU3ZmVlNzAwMDAwMzE4ODliOGU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
Mzg2MmYyNDdkYjc5NDg1ZGJkZTVlNzlmYWFkZDQwOWIzYTgwYWMwNTFjZjhh
|
14
|
-
YjBlNDJhOGYyODAyYjVkOTIzZGQ2MWUyMWU1NWVhMzM4MmYyMmQxMjFmZWVj
|
15
|
-
YTg0MTQ4ZjUwMzBjYzA3OWE5N2IyZWU4NjVkM2NlN2JkYTE5Yzc=
|
6
|
+
metadata.gz: 50e199c9d2788226da04fc4e9ef9c6cad4e0c7313a4e7c40654afe18b7ffae7475aa4759e2b6ae7896fb190f48f438cc2104295d282ec5a778666777b8e8dd06
|
7
|
+
data.tar.gz: 1d1233ca179cc4686ce046a08aeefadadb0d49efd86f086b753f195eaf98b05332aa9c687b6b38cd8cfbb81b1ba607e1eba92c43f363aa132153ad54a269a591
|
@@ -76,17 +76,18 @@ module Resque
|
|
76
76
|
protected
|
77
77
|
|
78
78
|
attr_reader :create_block
|
79
|
-
attr_accessor :
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
83
|
-
|
84
|
-
|
85
|
-
alias_method :
|
86
|
-
alias_method :
|
87
|
-
alias_method :encoding, :
|
88
|
-
alias_method :directory, :
|
89
|
-
alias_method :queue, :
|
79
|
+
attr_accessor :_extension,
|
80
|
+
:_encoding,
|
81
|
+
:_directory,
|
82
|
+
:_queue,
|
83
|
+
:_output_filename
|
84
|
+
|
85
|
+
alias_method :super_extension, :_extension
|
86
|
+
alias_method :extension, :_extension=
|
87
|
+
alias_method :encoding, :_encoding=
|
88
|
+
alias_method :directory, :_directory=
|
89
|
+
alias_method :queue, :_queue=
|
90
|
+
alias_method :output_filename, :_output_filename=
|
90
91
|
|
91
92
|
def set_instance(obj)
|
92
93
|
@instance = obj
|
@@ -98,7 +99,7 @@ module Resque
|
|
98
99
|
|
99
100
|
# override for Extenstions::TableBuilding, to use custom encoding
|
100
101
|
def encoded_string(obj)
|
101
|
-
obj.to_s.encode(
|
102
|
+
obj.to_s.encode(_encoding,
|
102
103
|
invalid: :replace,
|
103
104
|
undef: :replace)
|
104
105
|
end
|
@@ -124,7 +125,6 @@ module Resque
|
|
124
125
|
# Constants #
|
125
126
|
#++
|
126
127
|
|
127
|
-
DEFAULT_EXTENSION = 'txt'
|
128
128
|
DEFAULT_QUEUE = :base
|
129
129
|
|
130
130
|
#--
|
@@ -132,17 +132,29 @@ module Resque
|
|
132
132
|
#++
|
133
133
|
|
134
134
|
def_delegators Const::TO_EIGENCLASS,
|
135
|
-
:
|
136
|
-
:
|
137
|
-
:
|
135
|
+
:_directory,
|
136
|
+
:_extension,
|
137
|
+
:_encoding,
|
138
|
+
:_queue,
|
138
139
|
:create_block,
|
139
140
|
:set_instance,
|
140
|
-
:
|
141
|
-
:job_queue
|
141
|
+
:_extension=
|
142
142
|
|
143
143
|
def_delegators :@cache_file, :filename, :exists?, :ready?
|
144
144
|
def_delegator Const::TO_SUPER, :super_extension
|
145
145
|
|
146
|
+
attr_reader :job_id
|
147
|
+
|
148
|
+
def self.build(options = {})
|
149
|
+
in_background = options.delete(:background)
|
150
|
+
force = options.delete(:force)
|
151
|
+
report = new(options)
|
152
|
+
|
153
|
+
in_background ? report.bg_build(force) : report.build(force)
|
154
|
+
|
155
|
+
report
|
156
|
+
end
|
157
|
+
|
146
158
|
#--
|
147
159
|
# Public instance methods
|
148
160
|
#++
|
@@ -156,9 +168,7 @@ module Resque
|
|
156
168
|
create_dispatch(*args)
|
157
169
|
else
|
158
170
|
if args && (attrs_hash = args.first) && attrs_hash.is_a?(Hash)
|
159
|
-
attrs_hash.each
|
160
|
-
send("#{name}=", value)
|
161
|
-
end
|
171
|
+
attrs_hash.each { |name, value| send("#{name}=", value) }
|
162
172
|
end
|
163
173
|
end
|
164
174
|
|
@@ -182,20 +192,20 @@ module Resque
|
|
182
192
|
args_json = [*@args, force].to_json
|
183
193
|
|
184
194
|
# Check report if it already in progress and tring return its job_id...
|
185
|
-
job_id = ReportJob.enqueued?(report_class, args_json).try(:meta_id)
|
195
|
+
@job_id = ReportJob.enqueued?(report_class, args_json).try(:meta_id)
|
186
196
|
|
187
197
|
# ...and start new job otherwise
|
188
|
-
job_id
|
198
|
+
@job_id ||= ReportJob.enqueue_to(_queue || DEFAULT_QUEUE, report_class, args_json).try(:meta_id)
|
189
199
|
end
|
190
200
|
|
191
201
|
protected
|
192
202
|
|
193
203
|
def init_cache_file
|
194
|
-
|
204
|
+
self._extension = super_extension || DEFAULT_EXTENSION
|
195
205
|
|
196
|
-
@cache_file = CacheFile.new(
|
197
|
-
generate_filename(@args,
|
198
|
-
coding:
|
206
|
+
@cache_file = CacheFile.new(_directory,
|
207
|
+
generate_filename(@args, _extension),
|
208
|
+
coding: _encoding)
|
199
209
|
end
|
200
210
|
|
201
211
|
# Method specifies how to output report data
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'tempfile'
|
1
2
|
# coding: utf-8
|
2
3
|
module Resque
|
3
4
|
module Reports
|
@@ -33,17 +34,29 @@ module Resque
|
|
33
34
|
def open(force = false)
|
34
35
|
prepare_cache_dir
|
35
36
|
|
36
|
-
force ?
|
37
|
+
(force ? clear : return) if File.exists?(@filename)
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
with_tempfile do |tempfile|
|
40
|
+
yield tempfile
|
41
|
+
|
42
|
+
tempfile.close
|
43
|
+
FileUtils.cp(tempfile.path, @filename)
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
47
|
+
def clear
|
48
|
+
FileUtils.rm_f(@filename)
|
49
|
+
end
|
50
|
+
|
45
51
|
protected
|
46
52
|
|
53
|
+
def with_tempfile
|
54
|
+
yield(tempfile = Tempfile.new(Digest::MD5.hexdigest(@filename), :encoding => @coding))
|
55
|
+
ensure
|
56
|
+
tempfile.close unless tempfile.closed?
|
57
|
+
tempfile.try(:unlink)
|
58
|
+
end
|
59
|
+
|
47
60
|
def prepare_cache_dir
|
48
61
|
FileUtils.mkdir_p @dir # create folder if not exists
|
49
62
|
|
@@ -67,16 +80,6 @@ module Resque
|
|
67
80
|
.map { |fname| File.join(@dir, fname) if File.extname(fname) == @ext }
|
68
81
|
.compact
|
69
82
|
end
|
70
|
-
|
71
|
-
def remove_unfinished_on_error
|
72
|
-
yield
|
73
|
-
rescue => error
|
74
|
-
# remove everything that was written due to it inconsistance
|
75
|
-
FileUtils.rm_f @filename
|
76
|
-
|
77
|
-
# don't suppress any errors here
|
78
|
-
raise error
|
79
|
-
end
|
80
83
|
end
|
81
84
|
end
|
82
85
|
end
|
@@ -5,119 +5,125 @@ module Resque
|
|
5
5
|
module BatchedReport
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
included do
|
9
|
+
BATCH_SIZE = 10_000
|
10
|
+
end
|
11
|
+
|
12
|
+
# Internal: Подключение используемое для выполнения запросов
|
13
|
+
#
|
14
|
+
# Returns connection adapter
|
15
|
+
def connection
|
16
|
+
ActiveRecord::Base.connection
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal: Выполняет запрос отчета пачками и выполняет block для каждой пачки
|
20
|
+
# Переопредленный метод из Resque::Reports
|
21
|
+
#
|
22
|
+
# Returns Nothing
|
23
|
+
def data_each(force = false)
|
24
|
+
0.step(data_size, batch_size) do |batch_offset|
|
25
|
+
connection.execute(batched_query(batch_offset)).each do |element|
|
26
|
+
yield element
|
20
27
|
end
|
21
28
|
end
|
29
|
+
end
|
22
30
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
# Internal: Возвращает общее кол-во строк в отчете
|
32
|
+
# Переопредленный метод из Resque::Reports
|
33
|
+
#
|
34
|
+
# Returns Fixnum
|
35
|
+
def data_size
|
36
|
+
@data_size ||= connection.execute(count_query)[0]['count'].to_i
|
37
|
+
end
|
30
38
|
|
31
|
-
|
39
|
+
protected
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
41
|
+
# Internal: Возвращает отфильтрованный запрос отчета
|
42
|
+
#
|
43
|
+
# Returns Arel::SelectManager
|
44
|
+
def query
|
45
|
+
filter base_query
|
46
|
+
end
|
39
47
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
48
|
+
# Internal: Полезный метод для хранения Arel::Table объектов для запроса отчета
|
49
|
+
#
|
50
|
+
# Returns Hash, {:table_name => #<Arel::Table @name="table_name">, ...}
|
51
|
+
def tables
|
52
|
+
return @tables if defined? @tables
|
45
53
|
|
46
|
-
|
54
|
+
tables = models.map(&:arel_table)
|
47
55
|
|
48
|
-
|
49
|
-
|
56
|
+
@tables = tables.reduce({}) { |a, e| a.store(e.name, e) && a }.with_indifferent_access
|
57
|
+
end
|
50
58
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
59
|
+
# Internal: Полезный метод для join'а необходимых таблиц через Arel
|
60
|
+
#
|
61
|
+
# Returns Arel
|
62
|
+
def join_tables(source_table, *joins)
|
63
|
+
joins.inject(source_table) { |query, joined| query.join(joined[:table]).on(joined[:on]) }
|
64
|
+
end
|
59
65
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
+
# Internal: Размер пачки отчета
|
67
|
+
#
|
68
|
+
# Returns Fixnum
|
69
|
+
def batch_size
|
70
|
+
BATCH_SIZE
|
71
|
+
end
|
66
72
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
+
# Internal: Модели используемые в отчете
|
74
|
+
#
|
75
|
+
# Returns Array of Arel::Table
|
76
|
+
def models
|
77
|
+
fail NotImplementedError
|
78
|
+
end
|
73
79
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
+
# Internal: Основной запрос отчета (Arel)
|
81
|
+
#
|
82
|
+
# Returns Arel::SelectManager
|
83
|
+
def base_query
|
84
|
+
fail NotImplementedError
|
85
|
+
end
|
80
86
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
+
# Internal: Поля запрашиваемые отчетом
|
88
|
+
#
|
89
|
+
# Returns String (SQL)
|
90
|
+
def select
|
91
|
+
fail NotImplementedError
|
92
|
+
end
|
87
93
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
+
# Internal: Порядок строк отчета
|
95
|
+
#
|
96
|
+
# Returns String (SQL)
|
97
|
+
def order
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
alias_method :order_by, :order
|
94
101
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
102
|
+
# Internal: Фильтры отчета
|
103
|
+
#
|
104
|
+
# Returns Arel::SelectManager
|
105
|
+
def filter(query)
|
106
|
+
query
|
107
|
+
end
|
101
108
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
109
|
+
# Internal: Запрос количества строк в отчете
|
110
|
+
#
|
111
|
+
# Returns String (SQL)
|
112
|
+
def count_query
|
113
|
+
query.project(Arel.sql('COUNT(*) as count')).to_sql
|
114
|
+
end
|
108
115
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
116
|
+
# Internal: Запрос пачки строк отчета
|
117
|
+
#
|
118
|
+
# offset - Numeric, число строк на которое сдвигается запрос
|
119
|
+
#
|
120
|
+
# Returns String (SQL)
|
121
|
+
def batched_query(offset)
|
122
|
+
query.project(Arel.sql(select))
|
123
|
+
.take(batch_size)
|
124
|
+
.skip(offset)
|
125
|
+
.order(order_by)
|
126
|
+
.to_sql
|
121
127
|
end
|
122
128
|
end
|
123
129
|
end
|
@@ -14,10 +14,12 @@ module Resque
|
|
14
14
|
# end
|
15
15
|
module FilenameGen
|
16
16
|
|
17
|
+
DEFAULT_EXTENSION = 'txt'
|
18
|
+
|
17
19
|
private
|
18
20
|
|
19
21
|
def generate_filename(args, fextension)
|
20
|
-
"#{ hash(self.class.to_s, *args) }.#{ fextension }"
|
22
|
+
"#{ hash(self.class.to_s, *args) }.#{ fextension || DEFAULT_EXTENSION }"
|
21
23
|
end
|
22
24
|
|
23
25
|
def hash(*args)
|
@@ -28,6 +28,13 @@ module Resque
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def column(name, value, options = {})
|
31
|
+
if options[:skip_if].present?
|
32
|
+
if options[:skip_if].is_a?(Symbol)
|
33
|
+
return if @instance.send(options.delete(:skip_if))
|
34
|
+
elsif options[:skip_if].respond_to?(:call)
|
35
|
+
return if options.delete(:skip_if).call
|
36
|
+
end
|
37
|
+
end
|
31
38
|
add_column_header(name) || add_column_cell(value, options)
|
32
39
|
end
|
33
40
|
|
@@ -32,7 +32,7 @@ module Resque
|
|
32
32
|
base.send :include, EventCallbacks # event callbacks and handlers
|
33
33
|
base.send :include, EventTemplates # template events handling methods
|
34
34
|
base.send :include, Encodings # encoding constants
|
35
|
-
base.send :include, EnqueueToFix #
|
35
|
+
base.send :include, EnqueueToFix # enqueue task to exact queue
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/resque-reports.gemspec
CHANGED
@@ -18,12 +18,11 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ['lib']
|
20
20
|
|
21
|
-
gem.add_dependency 'resque-integration', '>= 0.
|
21
|
+
gem.add_dependency 'resque-integration', '>= 0.4.4'
|
22
22
|
gem.add_dependency 'activesupport' # избавиться от зависимости
|
23
23
|
|
24
|
-
gem.add_development_dependency
|
25
|
-
gem.add_development_dependency
|
24
|
+
gem.add_development_dependency 'bundler', '~> 1.3'
|
25
|
+
gem.add_development_dependency 'rake'
|
26
26
|
gem.add_development_dependency 'rspec', '>= 2.14.0'
|
27
|
-
gem.add_development_dependency 'rspec-given', '~> 3.0'
|
28
27
|
gem.add_development_dependency 'simplecov'
|
29
28
|
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
require 'stringio'
|
4
4
|
|
5
|
-
require 'resque-reports'
|
6
|
-
|
7
5
|
class MyTypeReport < Resque::Reports::BaseReport
|
8
6
|
extension :type
|
9
7
|
|
@@ -51,15 +49,15 @@ describe 'Resque::Reports::BaseReport successor' do
|
|
51
49
|
let(:dummy) { Resque::Reports::Extensions::Dummy.new }
|
52
50
|
|
53
51
|
describe '#extension' do
|
54
|
-
before { File.
|
52
|
+
before { allow(File).to receive(:exists?).and_return(true) }
|
55
53
|
|
56
|
-
it { File.extname(my_report.filename).
|
54
|
+
it { expect(File.extname(my_report.filename)).to eq '.type' }
|
57
55
|
end
|
58
56
|
|
59
57
|
describe '#source' do
|
60
|
-
before { my_report.
|
58
|
+
before { allow(my_report).to receive(:select_data).and_return([dummy]) }
|
61
59
|
|
62
|
-
it { my_report.
|
60
|
+
it { expect(my_report).to receive(:select_data) }
|
63
61
|
|
64
62
|
after { my_report.build true }
|
65
63
|
end
|
@@ -68,32 +66,32 @@ describe 'Resque::Reports::BaseReport successor' do
|
|
68
66
|
subject { my_report.instance_variable_get(:@cache_file) }
|
69
67
|
let(:tmpdir) { File.join(Dir.tmpdir, 'resque-reports') }
|
70
68
|
|
71
|
-
it { subject.instance_variable_get(:@dir).
|
69
|
+
it { expect(subject.instance_variable_get(:@dir)).to eq tmpdir }
|
72
70
|
end
|
73
71
|
|
74
72
|
describe '#create' do
|
75
|
-
it { my_report.instance_variable_get(:@main_param).
|
73
|
+
it { expect(my_report.instance_variable_get(:@main_param)).to eq 'test' }
|
76
74
|
end
|
77
75
|
|
78
76
|
describe '#encoding' do
|
79
77
|
subject { my_report.instance_variable_get(:@cache_file) }
|
80
78
|
let(:utf_coding) { Resque::Reports::Extensions::Encodings::UTF8 }
|
81
79
|
|
82
|
-
it { subject.instance_variable_get(:@coding).
|
80
|
+
it { expect(subject.instance_variable_get(:@coding)).to eq utf_coding }
|
83
81
|
end
|
84
82
|
|
85
83
|
describe '#write' do
|
86
84
|
subject { MyReport.new('#write test') }
|
87
85
|
|
88
86
|
before do
|
89
|
-
subject.
|
90
|
-
subject.
|
91
|
-
subject.
|
87
|
+
allow(subject).to receive(:data_each) { |&block| block.call(dummy) }
|
88
|
+
allow(subject).to receive(:build_table_row).and_return(['row'])
|
89
|
+
allow(subject).to receive(:build_table_header).and_return(['header'])
|
92
90
|
|
93
91
|
subject.write(io)
|
94
92
|
end
|
95
93
|
|
96
|
-
it { io.string.
|
94
|
+
it { expect(io.string).to eq "header\r\nrow\r\n" }
|
97
95
|
end
|
98
96
|
|
99
97
|
describe '#bg_build' do
|
@@ -102,13 +100,10 @@ describe 'Resque::Reports::BaseReport successor' do
|
|
102
100
|
context 'when report is building twice' do
|
103
101
|
subject { MyReport.new('#bg_build test') }
|
104
102
|
|
105
|
-
before { job_class.
|
103
|
+
before { allow(job_class).to receive(:enqueue_to).and_return('job_id') }
|
106
104
|
|
107
105
|
it do
|
108
|
-
job_class
|
109
|
-
.should_receive(:enqueue_to).twice
|
110
|
-
#.with(:my_type_reports, 'MyReport', '["#bg_build test",true]')
|
111
|
-
|
106
|
+
expect(job_class).to receive(:enqueue_to).twice
|
112
107
|
end
|
113
108
|
|
114
109
|
after do
|
@@ -119,44 +114,41 @@ describe 'Resque::Reports::BaseReport successor' do
|
|
119
114
|
context 'when report is building' do
|
120
115
|
subject { MyReport.new('#bg_build test') }
|
121
116
|
|
122
|
-
before { job_class.
|
117
|
+
before { allow(job_class).to receive(:enqueue_to).and_return('job_id') }
|
123
118
|
|
124
|
-
it
|
125
|
-
job_class
|
126
|
-
.should_receive(:enqueue_to)
|
127
|
-
#.with(:my_type_reports, 'MyReport', '["#bg_build test",true]')
|
128
|
-
end
|
119
|
+
it { expect(job_class).to receive(:enqueue_to) }
|
129
120
|
|
130
|
-
after
|
121
|
+
after { subject.bg_build true }
|
131
122
|
end
|
132
123
|
|
133
124
|
context 'when report is not build yet' do
|
134
125
|
subject { MyReport.new('#bg_build test') }
|
135
126
|
|
136
127
|
before do
|
137
|
-
job_class.
|
128
|
+
allow(job_class).to receive(:enqueued?).and_return(double('Meta', meta_id: 'enqueued_job_id'))
|
138
129
|
end
|
139
130
|
|
140
|
-
it { subject.bg_build(true).
|
131
|
+
it { expect(subject.bg_build(true)).to eq 'enqueued_job_id' }
|
141
132
|
end
|
142
133
|
end
|
143
134
|
|
144
135
|
describe '#build' do
|
145
|
-
|
146
|
-
|
147
|
-
it { subject.should_receive(:decorate_second).exactly(3).times }
|
136
|
+
context 'when report decorated' do
|
137
|
+
subject { MyReport.new('#build test') }
|
148
138
|
|
149
|
-
|
139
|
+
it { expect(subject).to receive(:decorate_second).exactly(3).times }
|
150
140
|
|
141
|
+
after { subject.build true }
|
142
|
+
end
|
151
143
|
context 'when report was built' do
|
152
144
|
subject { MyReport.new('was built test') }
|
153
145
|
|
154
146
|
before { subject.build true }
|
155
147
|
|
156
|
-
|
148
|
+
it { expect(subject).to be_exists }
|
157
149
|
it do
|
158
|
-
File.read(subject.filename)
|
159
|
-
.
|
150
|
+
expect(File.read(subject.filename))
|
151
|
+
.to eq <<-REPORT.gsub(/^ {12}/, '')
|
160
152
|
First one|Second\r
|
161
153
|
one|one - is second\r
|
162
154
|
was built test|was built test - is second\r
|
@@ -168,7 +160,7 @@ describe 'Resque::Reports::BaseReport successor' do
|
|
168
160
|
describe '#data_each' do
|
169
161
|
subject { MyReport.new('#data_each test') }
|
170
162
|
|
171
|
-
it { subject.
|
163
|
+
it { expect(subject).to receive(:data_each) }
|
172
164
|
|
173
165
|
after { subject.write(io) }
|
174
166
|
end
|
@@ -176,7 +168,7 @@ describe 'Resque::Reports::BaseReport successor' do
|
|
176
168
|
describe '#build_table_header' do
|
177
169
|
subject { MyReport.new('#build_table_header test') }
|
178
170
|
|
179
|
-
it { subject.
|
171
|
+
it { expect(subject).to receive(:build_table_header) }
|
180
172
|
|
181
173
|
after { subject.write(io) }
|
182
174
|
end
|
@@ -184,7 +176,7 @@ describe 'Resque::Reports::BaseReport successor' do
|
|
184
176
|
describe '#build_table_row' do
|
185
177
|
subject { MyReport.new('#build_table_row test') }
|
186
178
|
|
187
|
-
it { subject.
|
179
|
+
it { expect(subject).to receive(:build_table_row).twice }
|
188
180
|
|
189
181
|
after { subject.write(io) }
|
190
182
|
end
|
@@ -57,7 +57,7 @@ describe 'Resque::Reports::CsvReport successor' do
|
|
57
57
|
subject { MyCsvDefaultsReport.new }
|
58
58
|
|
59
59
|
it 'sets csv_options defaults' do
|
60
|
-
subject.options.
|
60
|
+
expect(subject.options).to eq MyCsvReport::DEFAULT_CSV_OPTIONS
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -69,7 +69,7 @@ describe 'Resque::Reports::CsvReport successor' do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
it 'merges csv_options with defaults' do
|
72
|
-
subject.options.
|
72
|
+
expect(subject.options).to eq my_options
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
@@ -78,12 +78,12 @@ describe 'Resque::Reports::CsvReport successor' do
|
|
78
78
|
context 'when report was built' do
|
79
79
|
subject { MyCsvReport.new('was built test') }
|
80
80
|
|
81
|
-
|
81
|
+
after { subject.build true }
|
82
82
|
|
83
|
-
|
83
|
+
it { expect(subject).to be_exists }
|
84
84
|
it do
|
85
|
-
File.read(subject.filename)
|
86
|
-
.
|
85
|
+
expect(File.read(subject.filename))
|
86
|
+
.to eq <<-CSV.gsub(/^ {12}/, '')
|
87
87
|
First one,Second,Third
|
88
88
|
decorated: one,was built test - is second,3'rd row element is: 3
|
89
89
|
CSV
|
@@ -32,10 +32,10 @@ describe Resque::Reports::ReportJob do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
describe '.execute' do
|
35
|
-
before { Reports::MyCsvReport.
|
35
|
+
before { allow(Reports::MyCsvReport).to receive(:new).and_return(my_report) }
|
36
36
|
|
37
37
|
context 'when building report' do
|
38
|
-
before { my_report.
|
38
|
+
before { allow(my_report).to receive(:build).and_return(nil) }
|
39
39
|
|
40
40
|
it do
|
41
41
|
expect(Reports::MyCsvReport)
|
@@ -60,24 +60,24 @@ describe Resque::Reports::ReportJob do
|
|
60
60
|
|
61
61
|
context 'when events are firing' do
|
62
62
|
before do
|
63
|
-
described_class.
|
64
|
-
described_class.get_meta.
|
63
|
+
allow(described_class).to receive(:get_meta).and_return({})
|
64
|
+
allow(described_class.get_meta).to receive(:save).and_return(true)
|
65
65
|
end
|
66
66
|
|
67
67
|
context 'when progress total is zero' do
|
68
68
|
before do
|
69
|
-
my_report.
|
70
|
-
my_report.
|
69
|
+
allow(my_report).to receive(:select_data).and_return([])
|
70
|
+
allow(my_report).to receive(:data_size).and_return(0)
|
71
71
|
end
|
72
72
|
|
73
|
-
it { described_class.
|
73
|
+
it { expect(described_class).to_not receive(:at) }
|
74
74
|
|
75
75
|
after { described_class.execute(*exec_params) }
|
76
76
|
end
|
77
77
|
|
78
78
|
context 'when works default handlers' do
|
79
79
|
context 'when error occurs' do
|
80
|
-
before { my_report.
|
80
|
+
before { allow(my_report).to receive(:build_table_row) { fail 'Custom error' } }
|
81
81
|
|
82
82
|
it do
|
83
83
|
expect { described_class.execute(*exec_params) }
|
@@ -86,7 +86,7 @@ describe Resque::Reports::ReportJob do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
context 'when progress is changed' do
|
89
|
-
it { described_class.
|
89
|
+
it { expect(described_class).to receive(:at).with(2, 2, nil) }
|
90
90
|
|
91
91
|
after { described_class.execute(*exec_params) }
|
92
92
|
end
|
@@ -95,28 +95,21 @@ describe Resque::Reports::ReportJob do
|
|
95
95
|
context 'when works custom handlers' do
|
96
96
|
context 'when error occurs' do
|
97
97
|
before do
|
98
|
-
my_report.
|
99
|
-
my_report.
|
98
|
+
allow(my_report).to receive(:error_message) { |e| fail "Boom! #{e.message}" }
|
99
|
+
allow(my_report).to receive(:build_table_row) { fail 'Custom error' }
|
100
100
|
end
|
101
101
|
|
102
|
-
it
|
103
|
-
expect { described_class.execute(*exec_params) }
|
104
|
-
.to raise_error('Boom! Custom error')
|
105
|
-
end
|
102
|
+
it { expect { described_class.execute(*exec_params) }.to raise_error('Boom! Custom error') }
|
106
103
|
end
|
107
104
|
|
108
105
|
context 'when progress is changed' do
|
109
106
|
before do
|
110
|
-
my_report.
|
107
|
+
allow(my_report).to receive(:progress_message) do |progress, total|
|
111
108
|
"my progress: #{progress} / #{total}"
|
112
109
|
end
|
113
110
|
end
|
114
111
|
|
115
|
-
it
|
116
|
-
described_class
|
117
|
-
.should_receive(:at)
|
118
|
-
.with(2, 2, 'my progress: 2 / 2')
|
119
|
-
end
|
112
|
+
it { expect(described_class).to receive(:at).with(2, 2, 'my progress: 2 / 2') }
|
120
113
|
|
121
114
|
after { described_class.execute(*exec_params) }
|
122
115
|
end
|
@@ -125,14 +118,11 @@ describe Resque::Reports::ReportJob do
|
|
125
118
|
context 'when task is performed by resque' do
|
126
119
|
context 'when error occurs' do
|
127
120
|
before do
|
128
|
-
my_report.
|
129
|
-
my_report.
|
121
|
+
allow(my_report).to receive(:error_message) { |e| fail "Boom! #{e.message}" }
|
122
|
+
allow(my_report).to receive(:build_table_row) { fail 'Custom error' }
|
130
123
|
end
|
131
124
|
|
132
|
-
it
|
133
|
-
expect { described_class.execute(*exec_params) }
|
134
|
-
.to raise_error('Boom! Custom error')
|
135
|
-
end
|
125
|
+
it { expect { described_class.execute(*exec_params) }.to raise_error('Boom! Custom error') }
|
136
126
|
end
|
137
127
|
end
|
138
128
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,111 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-reports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergey D.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: resque-integration
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.4.4
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.4.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 2.14.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 2.14.0
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rspec-given
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ~>
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '3.0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ~>
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '3.0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: simplecov
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
|
-
- -
|
87
|
+
- - ">="
|
102
88
|
- !ruby/object:Gem::Version
|
103
89
|
version: '0'
|
104
90
|
type: :development
|
105
91
|
prerelease: false
|
106
92
|
version_requirements: !ruby/object:Gem::Requirement
|
107
93
|
requirements:
|
108
|
-
- -
|
94
|
+
- - ">="
|
109
95
|
- !ruby/object:Gem::Version
|
110
96
|
version: '0'
|
111
97
|
description: Make your custom reports to CSV in background using Resque with simple
|
@@ -116,9 +102,9 @@ executables: []
|
|
116
102
|
extensions: []
|
117
103
|
extra_rdoc_files: []
|
118
104
|
files:
|
119
|
-
- .gitignore
|
120
|
-
- .rspec
|
121
|
-
- .rubocop.yml
|
105
|
+
- ".gitignore"
|
106
|
+
- ".rspec"
|
107
|
+
- ".rubocop.yml"
|
122
108
|
- Gemfile
|
123
109
|
- MIT-LICENSE
|
124
110
|
- README
|
@@ -155,12 +141,12 @@ require_paths:
|
|
155
141
|
- lib
|
156
142
|
required_ruby_version: !ruby/object:Gem::Requirement
|
157
143
|
requirements:
|
158
|
-
- -
|
144
|
+
- - ">="
|
159
145
|
- !ruby/object:Gem::Version
|
160
146
|
version: '0'
|
161
147
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
148
|
requirements:
|
163
|
-
- -
|
149
|
+
- - ">="
|
164
150
|
- !ruby/object:Gem::Version
|
165
151
|
version: '0'
|
166
152
|
requirements: []
|