reports_kit 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +6 -5
- data/app/assets/javascripts/reports_kit/lib/chart.js +33 -8
- data/app/assets/javascripts/reports_kit/lib/report.js +27 -26
- data/app/assets/javascripts/reports_kit/lib/table.js +58 -0
- data/app/assets/javascripts/reports_kit/vendor/jquery.tablesorter.min.js +4 -0
- data/app/assets/stylesheets/reports_kit/reports.css.sass +20 -0
- data/config/initializers/mime_types.rb +1 -0
- data/docs/dimensions.md +34 -26
- data/docs/display_options.md +15 -12
- data/docs/filters.md +2 -2
- data/docs/measures.md +4 -3
- data/gemfiles/mysql.gemfile.lock +14 -1
- data/gemfiles/postgresql.gemfile.lock +14 -1
- data/lib/reports_kit.rb +15 -0
- data/lib/reports_kit/cache.rb +37 -0
- data/lib/reports_kit/configuration.rb +13 -1
- data/lib/reports_kit/helper.rb +54 -3
- data/lib/reports_kit/model_configuration.rb +6 -1
- data/lib/reports_kit/order.rb +33 -0
- data/lib/reports_kit/relative_time.rb +42 -0
- data/lib/reports_kit/report_builder.rb +34 -15
- data/lib/reports_kit/reports/abstract_measure.rb +9 -0
- data/lib/reports_kit/reports/adapters/mysql.rb +8 -1
- data/lib/reports_kit/reports/adapters/postgresql.rb +8 -1
- data/lib/reports_kit/reports/composite_measure.rb +43 -0
- data/lib/reports_kit/reports/data/chart_options.rb +5 -0
- data/lib/reports_kit/reports/data/composite_aggregation.rb +96 -0
- data/lib/reports_kit/reports/data/entity.rb +7 -0
- data/lib/reports_kit/reports/data/format_one_dimension.rb +120 -0
- data/lib/reports_kit/reports/data/format_two_dimensions.rb +141 -0
- data/lib/reports_kit/reports/data/generate.rb +72 -25
- data/lib/reports_kit/reports/data/generate_for_properties.rb +75 -0
- data/lib/reports_kit/reports/data/one_dimension.rb +15 -49
- data/lib/reports_kit/reports/data/populate_one_dimension.rb +36 -0
- data/lib/reports_kit/reports/data/populate_two_dimensions.rb +104 -0
- data/lib/reports_kit/reports/data/two_dimensions.rb +15 -110
- data/lib/reports_kit/reports/data/utils.rb +77 -12
- data/lib/reports_kit/reports/data/value.rb +7 -0
- data/lib/reports_kit/reports/dimension.rb +4 -110
- data/lib/reports_kit/reports/dimension_with_measure.rb +137 -0
- data/lib/reports_kit/reports/filter.rb +5 -64
- data/lib/reports_kit/reports/filter_types/base.rb +1 -1
- data/lib/reports_kit/reports/filter_types/boolean.rb +9 -7
- data/lib/reports_kit/reports/filter_types/datetime.rb +7 -5
- data/lib/reports_kit/reports/filter_types/number.rb +2 -0
- data/lib/reports_kit/reports/filter_with_measure.rb +84 -0
- data/lib/reports_kit/reports/generate_autocomplete_results.rb +1 -1
- data/lib/reports_kit/reports/inferrable_configuration.rb +32 -13
- data/lib/reports_kit/reports/measure.rb +48 -12
- data/lib/reports_kit/reports_controller.rb +42 -3
- data/lib/reports_kit/version.rb +1 -1
- data/reports_kit.gemspec +2 -0
- data/spec/fixtures/generate_inputs.yml +146 -21
- data/spec/fixtures/generate_outputs.yml +768 -17
- data/spec/reports_kit/relative_time_spec.rb +29 -0
- data/spec/reports_kit/report_builder_spec.rb +28 -0
- data/spec/reports_kit/reports/data/generate_spec.rb +614 -27
- data/spec/reports_kit/reports/dimension_with_measure_spec.rb +69 -0
- data/spec/reports_kit/reports/{filter_spec.rb → filter_with_measure_spec.rb} +4 -3
- data/spec/spec_helper.rb +7 -2
- data/spec/support/config.rb +11 -0
- data/spec/support/helpers.rb +3 -3
- data/spec/support/models/issue.rb +7 -0
- metadata +53 -4
- data/spec/reports_kit/reports/dimension_spec.rb +0 -54
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReportsKit::RelativeTime do
|
4
|
+
subject { described_class.parse(string) }
|
5
|
+
|
6
|
+
Timecop.freeze(TIMECOP_TIME) do
|
7
|
+
STRINGS_EXPECTED_VALUES = {
|
8
|
+
'2s' => 2.seconds.from_now,
|
9
|
+
'-3s' => 3.seconds.ago,
|
10
|
+
'4m' => 4.minutes.from_now,
|
11
|
+
'5h' => 5.hours.from_now,
|
12
|
+
'-6d' => 6.days.ago,
|
13
|
+
'7w' => 7.weeks.from_now,
|
14
|
+
'8M' => 8.months.from_now,
|
15
|
+
'9y' => 9.years.from_now,
|
16
|
+
'-2M1w' => (2.months + 1.week).ago
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
STRINGS_EXPECTED_VALUES.each do |string, expected_value|
|
21
|
+
context string do
|
22
|
+
let(:string) { string }
|
23
|
+
|
24
|
+
it 'transforms the filter criteria' do
|
25
|
+
expect(subject).to eq(expected_value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReportsKit::ReportBuilder do
|
4
|
+
subject { described_class.new(properties) }
|
5
|
+
|
6
|
+
context 'with a datetime dimension' do
|
7
|
+
let(:properties) do
|
8
|
+
{
|
9
|
+
measure: {
|
10
|
+
key: 'issue',
|
11
|
+
filters: [
|
12
|
+
{
|
13
|
+
key: 'opened_at',
|
14
|
+
criteria: {
|
15
|
+
operator: 'between',
|
16
|
+
value: '-1w - now'
|
17
|
+
}
|
18
|
+
}
|
19
|
+
]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'transforms the filter criteria' do
|
25
|
+
expect(subject.date_range('opened_at')).to include("#{format_criteria_time(1.week.ago)} - #{format_criteria_time(Time.zone.now)}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -13,6 +13,9 @@ describe ReportsKit::Reports::Data::Generate do
|
|
13
13
|
end
|
14
14
|
chart_data
|
15
15
|
end
|
16
|
+
let(:table_data) do
|
17
|
+
subject[:table_data]
|
18
|
+
end
|
16
19
|
|
17
20
|
let(:chart_type) { subject[:type] }
|
18
21
|
let(:chart_options) { subject[:chart_data][:options] }
|
@@ -21,8 +24,10 @@ describe ReportsKit::Reports::Data::Generate do
|
|
21
24
|
context 'with default granularity' do
|
22
25
|
let(:properties) do
|
23
26
|
{
|
24
|
-
measure:
|
25
|
-
|
27
|
+
measure: {
|
28
|
+
key: 'issue',
|
29
|
+
dimensions: %w(opened_at)
|
30
|
+
}
|
26
31
|
}
|
27
32
|
end
|
28
33
|
let!(:issues) do
|
@@ -63,12 +68,12 @@ describe ReportsKit::Reports::Data::Generate do
|
|
63
68
|
key: 'opened_at',
|
64
69
|
criteria: {
|
65
70
|
operator: 'between',
|
66
|
-
value: "#{
|
71
|
+
value: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
|
67
72
|
}
|
68
73
|
}
|
69
|
-
]
|
70
|
-
|
71
|
-
|
74
|
+
],
|
75
|
+
dimensions: %w(opened_at)
|
76
|
+
}
|
72
77
|
}
|
73
78
|
end
|
74
79
|
|
@@ -83,14 +88,95 @@ describe ReportsKit::Reports::Data::Generate do
|
|
83
88
|
]
|
84
89
|
})
|
85
90
|
end
|
91
|
+
|
92
|
+
context 'with zero results' do
|
93
|
+
let(:properties) do
|
94
|
+
{
|
95
|
+
measure: {
|
96
|
+
key: 'tag',
|
97
|
+
filters: [
|
98
|
+
{
|
99
|
+
key: 'created_at',
|
100
|
+
criteria: {
|
101
|
+
operator: 'between',
|
102
|
+
value: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
|
103
|
+
}
|
104
|
+
}
|
105
|
+
],
|
106
|
+
dimensions: %w(created_at)
|
107
|
+
}
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'returns the data' do
|
112
|
+
expect(chart_data).to eq({
|
113
|
+
labels: [
|
114
|
+
format_week_offset(1),
|
115
|
+
format_week_offset(0)
|
116
|
+
],
|
117
|
+
datasets: [
|
118
|
+
{
|
119
|
+
label: 'Tags',
|
120
|
+
data: [0, 0]
|
121
|
+
}
|
122
|
+
]
|
123
|
+
})
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'with multiple measures and datetime filters with different keys' do
|
128
|
+
let!(:tags) do
|
129
|
+
[
|
130
|
+
create(:tag, repo: repo, created_at: now - 1.weeks),
|
131
|
+
create(:tag, repo: repo, created_at: now)
|
132
|
+
]
|
133
|
+
end
|
134
|
+
let(:properties) do
|
135
|
+
{
|
136
|
+
measures: [
|
137
|
+
{
|
138
|
+
key: 'issue',
|
139
|
+
filters: %w(opened_at),
|
140
|
+
dimensions: %w(opened_at)
|
141
|
+
},
|
142
|
+
{
|
143
|
+
key: 'tag',
|
144
|
+
filters: %w(created_at),
|
145
|
+
dimensions: %w(created_at)
|
146
|
+
}
|
147
|
+
],
|
148
|
+
ui_filters: {
|
149
|
+
created_at: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
|
150
|
+
}
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'returns the chart_data' do
|
155
|
+
expect(chart_data).to eq({
|
156
|
+
labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
|
157
|
+
datasets: [
|
158
|
+
{
|
159
|
+
label: "Issues",
|
160
|
+
data: [2, 0, 1]
|
161
|
+
},
|
162
|
+
{
|
163
|
+
label: "Tags",
|
164
|
+
data: [0, 1, 1]
|
165
|
+
}
|
166
|
+
]
|
167
|
+
})
|
168
|
+
end
|
169
|
+
end
|
86
170
|
end
|
87
171
|
end
|
88
172
|
|
89
173
|
context 'with day granularity' do
|
90
174
|
let(:properties) do
|
91
175
|
{
|
92
|
-
measure:
|
93
|
-
|
176
|
+
measure: {
|
177
|
+
key: 'issue',
|
178
|
+
dimensions: [{ key: 'opened_at', granularity: 'day' }]
|
179
|
+
}
|
94
180
|
}
|
95
181
|
end
|
96
182
|
let!(:issues) do
|
@@ -121,8 +207,10 @@ describe ReportsKit::Reports::Data::Generate do
|
|
121
207
|
context 'with an association dimension' do
|
122
208
|
let(:properties) do
|
123
209
|
{
|
124
|
-
measure:
|
125
|
-
|
210
|
+
measure: {
|
211
|
+
key: 'issue',
|
212
|
+
dimensions: %w(repo)
|
213
|
+
}
|
126
214
|
}
|
127
215
|
end
|
128
216
|
let!(:issues) do
|
@@ -151,6 +239,51 @@ describe ReportsKit::Reports::Data::Generate do
|
|
151
239
|
end
|
152
240
|
end
|
153
241
|
|
242
|
+
context 'with a dimension limit' do
|
243
|
+
let(:properties) do
|
244
|
+
{
|
245
|
+
measure: {
|
246
|
+
key: 'issue',
|
247
|
+
dimensions: [{ key: 'repo', limit: 1 }]
|
248
|
+
}
|
249
|
+
}
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'returns the chart_data' do
|
253
|
+
expect(chart_data).to eq({
|
254
|
+
labels: [repo.to_s],
|
255
|
+
datasets: [{ label: 'Issues', data: [2] }]
|
256
|
+
})
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'with a custom aggregation' do
|
261
|
+
let(:properties) do
|
262
|
+
{
|
263
|
+
measure: {
|
264
|
+
key: 'issue',
|
265
|
+
name: 'Average Durations',
|
266
|
+
aggregation: 'average_duration',
|
267
|
+
dimensions: %w(repo)
|
268
|
+
}
|
269
|
+
}
|
270
|
+
end
|
271
|
+
let!(:issues) do
|
272
|
+
[
|
273
|
+
create(:issue, repo: repo, opened_at: now, closed_at: now),
|
274
|
+
create(:issue, repo: repo, opened_at: now - 2.weeks, closed_at: now),
|
275
|
+
create(:issue, repo: repo2, opened_at: now - 2.weeks, closed_at: now)
|
276
|
+
]
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'returns the chart_data' do
|
280
|
+
expect(chart_data).to eq({
|
281
|
+
labels: [repo2.to_s, repo.to_s],
|
282
|
+
datasets: [{ label: 'Average Durations', data: [14, 7] }]
|
283
|
+
})
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
154
287
|
context 'with a belongs_to association filter' do
|
155
288
|
let(:properties) do
|
156
289
|
{
|
@@ -164,9 +297,9 @@ describe ReportsKit::Reports::Data::Generate do
|
|
164
297
|
value: [repo.id]
|
165
298
|
}
|
166
299
|
}
|
167
|
-
]
|
168
|
-
|
169
|
-
|
300
|
+
],
|
301
|
+
dimensions: %w(repo)
|
302
|
+
}
|
170
303
|
}
|
171
304
|
end
|
172
305
|
|
@@ -191,9 +324,9 @@ describe ReportsKit::Reports::Data::Generate do
|
|
191
324
|
value: [tag.id]
|
192
325
|
}
|
193
326
|
}
|
194
|
-
]
|
195
|
-
|
196
|
-
|
327
|
+
],
|
328
|
+
dimensions: %w(repo)
|
329
|
+
}
|
197
330
|
}
|
198
331
|
end
|
199
332
|
let(:tag) { create(:tag) }
|
@@ -223,9 +356,9 @@ describe ReportsKit::Reports::Data::Generate do
|
|
223
356
|
value: [label.id]
|
224
357
|
}
|
225
358
|
}
|
226
|
-
]
|
227
|
-
|
228
|
-
|
359
|
+
],
|
360
|
+
dimensions: %w(repo)
|
361
|
+
}
|
229
362
|
}
|
230
363
|
end
|
231
364
|
let(:label) { create(:label) }
|
@@ -242,11 +375,41 @@ describe ReportsKit::Reports::Data::Generate do
|
|
242
375
|
end
|
243
376
|
end
|
244
377
|
|
378
|
+
context 'with a boolean dimension' do
|
379
|
+
let(:properties) do
|
380
|
+
{
|
381
|
+
measure: {
|
382
|
+
key: 'issue',
|
383
|
+
dimensions: %w(locked)
|
384
|
+
}
|
385
|
+
}
|
386
|
+
end
|
387
|
+
let!(:issues) do
|
388
|
+
[
|
389
|
+
create(:issue, locked: true),
|
390
|
+
create(:issue, locked: false),
|
391
|
+
create(:issue, locked: false)
|
392
|
+
]
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'returns the chart_data' do
|
396
|
+
expect(chart_data).to eq({
|
397
|
+
labels: ['false', 'true'],
|
398
|
+
datasets: [{ label: 'Issues', data: [2, 1] }]
|
399
|
+
})
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
245
403
|
context 'with datetime and association dimensions' do
|
246
404
|
let(:properties) do
|
247
405
|
{
|
248
|
-
measure:
|
249
|
-
|
406
|
+
measure: {
|
407
|
+
key: 'issue',
|
408
|
+
dimensions: [
|
409
|
+
{ key: 'opened_at', label: nil },
|
410
|
+
{ key: 'repo' }
|
411
|
+
]
|
412
|
+
}
|
250
413
|
}
|
251
414
|
end
|
252
415
|
let!(:issues) do
|
@@ -272,32 +435,456 @@ describe ReportsKit::Reports::Data::Generate do
|
|
272
435
|
]
|
273
436
|
})
|
274
437
|
end
|
438
|
+
|
439
|
+
context "with format: 'table'" do
|
440
|
+
subject { described_class.new(properties.merge(format: 'table'), context_record: context_record).perform }
|
441
|
+
|
442
|
+
it 'returns the table_data' do
|
443
|
+
expect(table_data).to eq([
|
444
|
+
[nil, repo.to_s, repo2.to_s],
|
445
|
+
[format_week_offset(2), 1, 0],
|
446
|
+
[format_week_offset(1), 0, 0],
|
447
|
+
[format_week_offset(0), 1, 1]
|
448
|
+
])
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
context "with a data_format_method" do
|
453
|
+
subject { described_class.new(properties.merge(data_format_method: 'add_label_suffix'), context_record: context_record).perform }
|
454
|
+
|
455
|
+
it 'returns the chart_data' do
|
456
|
+
expect(chart_data).to eq({
|
457
|
+
labels: ["#{format_week_offset(2)} Foo", "#{format_week_offset(1)} Foo", "#{format_week_offset(0)} Foo"],
|
458
|
+
datasets: [
|
459
|
+
{
|
460
|
+
label: repo.to_s,
|
461
|
+
data: [1, 0, 1]
|
462
|
+
},
|
463
|
+
{
|
464
|
+
label: repo2.to_s,
|
465
|
+
data: [0, 0, 1]
|
466
|
+
}
|
467
|
+
]
|
468
|
+
})
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
context 'with two measures' do
|
474
|
+
let(:properties) do
|
475
|
+
{
|
476
|
+
measures: [
|
477
|
+
{
|
478
|
+
key: 'issue',
|
479
|
+
dimensions: [{ key: 'created_at', label: nil }]
|
480
|
+
},
|
481
|
+
{
|
482
|
+
key: 'tag',
|
483
|
+
dimensions: %w(created_at)
|
484
|
+
},
|
485
|
+
]
|
486
|
+
}
|
487
|
+
end
|
488
|
+
let!(:issues) do
|
489
|
+
[
|
490
|
+
create(:issue, repo: repo, created_at: now),
|
491
|
+
create(:issue, repo: repo, created_at: now - 2.weeks),
|
492
|
+
create(:issue, repo: repo2, created_at: now)
|
493
|
+
]
|
494
|
+
end
|
495
|
+
let!(:tags) do
|
496
|
+
[
|
497
|
+
create(:tag, repo: repo, created_at: now - 1.week),
|
498
|
+
create(:tag, repo: repo, created_at: now - 2.weeks)
|
499
|
+
]
|
500
|
+
end
|
501
|
+
|
502
|
+
it 'returns the chart_data' do
|
503
|
+
expect(chart_data).to eq({
|
504
|
+
labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
|
505
|
+
datasets: [
|
506
|
+
{
|
507
|
+
label: 'Issues',
|
508
|
+
data: [1, 0, 2]
|
509
|
+
},
|
510
|
+
{
|
511
|
+
label: 'Tags',
|
512
|
+
data: [1, 1, 0]
|
513
|
+
}
|
514
|
+
]
|
515
|
+
})
|
516
|
+
end
|
517
|
+
|
518
|
+
context "with format: 'table'" do
|
519
|
+
subject { described_class.new(properties.merge(format: 'table'), context_record: context_record).perform }
|
520
|
+
|
521
|
+
it 'returns the table_data' do
|
522
|
+
expect(table_data).to eq([
|
523
|
+
[nil, 'Issues', 'Tags'],
|
524
|
+
[format_week_offset(2), 1, 1],
|
525
|
+
[format_week_offset(1), 0, 1],
|
526
|
+
[format_week_offset(0), 2, 0]
|
527
|
+
])
|
528
|
+
end
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
context 'with two dimensions' do
|
533
|
+
context 'with a custom aggregation' do
|
534
|
+
let(:properties) do
|
535
|
+
{
|
536
|
+
measure: {
|
537
|
+
key: 'issue',
|
538
|
+
aggregation: 'average_duration',
|
539
|
+
dimensions: %w(repo created_at)
|
540
|
+
}
|
541
|
+
}
|
542
|
+
end
|
543
|
+
let!(:issues) do
|
544
|
+
[
|
545
|
+
create(:issue, repo: repo, opened_at: now, closed_at: now),
|
546
|
+
create(:issue, repo: repo, opened_at: now - 2.weeks, closed_at: now),
|
547
|
+
create(:issue, repo: repo2, opened_at: now - 2.weeks, closed_at: now)
|
548
|
+
]
|
549
|
+
end
|
550
|
+
|
551
|
+
it 'returns the chart_data' do
|
552
|
+
expect(chart_data).to eq({
|
553
|
+
labels: [repo2.to_s, repo.to_s],
|
554
|
+
datasets: [{ label: format_week_offset(0), data: [14, 7] }]
|
555
|
+
})
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
describe 'composite aggregations' do
|
561
|
+
context 'with two measures' do
|
562
|
+
let(:properties) do
|
563
|
+
{
|
564
|
+
name: name,
|
565
|
+
composite_operator: composite_operator,
|
566
|
+
measures: [
|
567
|
+
{
|
568
|
+
key: 'issue',
|
569
|
+
dimensions: %w(created_at)
|
570
|
+
},
|
571
|
+
{
|
572
|
+
key: 'tag',
|
573
|
+
dimensions: %w(created_at)
|
574
|
+
}
|
575
|
+
]
|
576
|
+
}
|
577
|
+
end
|
578
|
+
let!(:issues) do
|
579
|
+
[
|
580
|
+
create(:issue, repo: repo, created_at: now),
|
581
|
+
create(:issue, repo: repo, created_at: now - 2.weeks),
|
582
|
+
create(:issue, repo: repo2, created_at: now)
|
583
|
+
]
|
584
|
+
end
|
585
|
+
let!(:tags) do
|
586
|
+
[
|
587
|
+
create(:tag, repo: repo, created_at: now),
|
588
|
+
create(:tag, repo: repo, created_at: now - 1.week),
|
589
|
+
create(:tag, repo: repo, created_at: now - 1.week)
|
590
|
+
]
|
591
|
+
end
|
592
|
+
let(:name) { 'My Name' }
|
593
|
+
|
594
|
+
context 'with +' do
|
595
|
+
let(:composite_operator) { '+' }
|
596
|
+
|
597
|
+
it 'returns the chart_data' do
|
598
|
+
expect(chart_data).to eq({
|
599
|
+
labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
|
600
|
+
datasets: [
|
601
|
+
{
|
602
|
+
label: name,
|
603
|
+
data: [1, 2, 3]
|
604
|
+
}
|
605
|
+
]
|
606
|
+
})
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
context 'with %' do
|
611
|
+
let(:composite_operator) { '%' }
|
612
|
+
|
613
|
+
it 'returns the chart_data' do
|
614
|
+
expect(chart_data).to eq({
|
615
|
+
labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
|
616
|
+
datasets: [
|
617
|
+
{
|
618
|
+
label: name,
|
619
|
+
data: [0, 0, 200]
|
620
|
+
}
|
621
|
+
]
|
622
|
+
})
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
context 'with % and a custom value_format_method' do
|
627
|
+
let(:composite_operator) { '%' }
|
628
|
+
let(:properties) do
|
629
|
+
{
|
630
|
+
name: name,
|
631
|
+
composite_operator: composite_operator,
|
632
|
+
value_format_method: 'format_percentage',
|
633
|
+
measures: [
|
634
|
+
{
|
635
|
+
key: 'issue',
|
636
|
+
dimensions: %w(created_at)
|
637
|
+
},
|
638
|
+
{
|
639
|
+
key: 'tag',
|
640
|
+
dimensions: %w(created_at)
|
641
|
+
}
|
642
|
+
]
|
643
|
+
}
|
644
|
+
end
|
645
|
+
|
646
|
+
it 'returns the chart_data' do
|
647
|
+
expect(chart_data).to eq({
|
648
|
+
labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
|
649
|
+
datasets: [
|
650
|
+
{
|
651
|
+
label: name,
|
652
|
+
data: ['0%', '0%', '200%']
|
653
|
+
}
|
654
|
+
]
|
655
|
+
})
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
context 'with a boolean dimension' do
|
660
|
+
let!(:issues) do
|
661
|
+
[
|
662
|
+
create(:issue, locked: true),
|
663
|
+
create(:issue, locked: false),
|
664
|
+
create(:issue, locked: false)
|
665
|
+
]
|
666
|
+
end
|
667
|
+
let(:composite_operator) { '+' }
|
668
|
+
let(:properties) do
|
669
|
+
{
|
670
|
+
name: name,
|
671
|
+
composite_operator: composite_operator,
|
672
|
+
measures: [
|
673
|
+
{
|
674
|
+
key: 'issue',
|
675
|
+
dimensions: %w(locked)
|
676
|
+
},
|
677
|
+
{
|
678
|
+
key: 'issue',
|
679
|
+
dimensions: %w(locked)
|
680
|
+
}
|
681
|
+
]
|
682
|
+
}
|
683
|
+
end
|
684
|
+
|
685
|
+
it 'returns the chart_data' do
|
686
|
+
expect(chart_data).to eq({
|
687
|
+
labels: ['false', 'true'],
|
688
|
+
datasets: [
|
689
|
+
{
|
690
|
+
label: name,
|
691
|
+
data: [4, 2]
|
692
|
+
}
|
693
|
+
]
|
694
|
+
})
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
context 'with a nested composite aggregation' do
|
699
|
+
let(:properties) do
|
700
|
+
{
|
701
|
+
measures: [
|
702
|
+
{
|
703
|
+
name: name,
|
704
|
+
composite_operator: '+',
|
705
|
+
measures: [
|
706
|
+
{
|
707
|
+
key: 'issue',
|
708
|
+
dimensions: %w(created_at)
|
709
|
+
},
|
710
|
+
{
|
711
|
+
key: 'tag',
|
712
|
+
dimensions: %w(created_at)
|
713
|
+
}
|
714
|
+
]
|
715
|
+
},
|
716
|
+
{
|
717
|
+
key: 'issue',
|
718
|
+
dimensions: %w(created_at)
|
719
|
+
},
|
720
|
+
{
|
721
|
+
key: 'tag',
|
722
|
+
dimensions: %w(created_at)
|
723
|
+
}
|
724
|
+
]
|
725
|
+
}
|
726
|
+
end
|
727
|
+
|
728
|
+
it 'returns the chart_data' do
|
729
|
+
expect(chart_data).to eq({
|
730
|
+
labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
|
731
|
+
datasets: [
|
732
|
+
{
|
733
|
+
label: name,
|
734
|
+
data: [1, 2, 3]
|
735
|
+
},
|
736
|
+
{
|
737
|
+
label: 'Issues',
|
738
|
+
data: [1, 0, 2]
|
739
|
+
},
|
740
|
+
{
|
741
|
+
label: 'Tags',
|
742
|
+
data: [0, 2, 1]
|
743
|
+
}
|
744
|
+
]
|
745
|
+
})
|
746
|
+
end
|
747
|
+
|
748
|
+
context 'with ui_filters' do
|
749
|
+
let(:properties) do
|
750
|
+
{
|
751
|
+
measures: [
|
752
|
+
{
|
753
|
+
name: name,
|
754
|
+
composite_operator: '+',
|
755
|
+
measures: [
|
756
|
+
{
|
757
|
+
key: 'issue',
|
758
|
+
filters: %w(created_at),
|
759
|
+
dimensions: %w(created_at)
|
760
|
+
},
|
761
|
+
{
|
762
|
+
key: 'tag',
|
763
|
+
filters: %w(created_at),
|
764
|
+
dimensions: %w(created_at)
|
765
|
+
}
|
766
|
+
]
|
767
|
+
},
|
768
|
+
{
|
769
|
+
key: 'issue',
|
770
|
+
filters: %w(created_at),
|
771
|
+
dimensions: %w(created_at)
|
772
|
+
},
|
773
|
+
{
|
774
|
+
key: 'tag',
|
775
|
+
filters: %w(created_at),
|
776
|
+
dimensions: %w(created_at)
|
777
|
+
}
|
778
|
+
],
|
779
|
+
ui_filters: {
|
780
|
+
created_at: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
|
781
|
+
}
|
782
|
+
}
|
783
|
+
end
|
784
|
+
|
785
|
+
it 'returns the chart_data' do
|
786
|
+
expect(chart_data).to eq({
|
787
|
+
labels: [format_week_offset(1), format_week_offset(0)],
|
788
|
+
datasets: [
|
789
|
+
{
|
790
|
+
label: name,
|
791
|
+
data: [2, 3]
|
792
|
+
},
|
793
|
+
{
|
794
|
+
label: 'Issues',
|
795
|
+
data: [0, 2]
|
796
|
+
},
|
797
|
+
{
|
798
|
+
label: 'Tags',
|
799
|
+
data: [2, 1]
|
800
|
+
}
|
801
|
+
]
|
802
|
+
})
|
803
|
+
end
|
804
|
+
end
|
805
|
+
|
806
|
+
context 'with two dimensions' do
|
807
|
+
let(:properties) do
|
808
|
+
{
|
809
|
+
measures: [
|
810
|
+
{
|
811
|
+
name: name,
|
812
|
+
composite_operator: '+',
|
813
|
+
measures: [
|
814
|
+
{
|
815
|
+
key: 'issue',
|
816
|
+
dimensions: %w(created_at repo)
|
817
|
+
},
|
818
|
+
{
|
819
|
+
key: 'tag',
|
820
|
+
dimensions: %w(created_at repo)
|
821
|
+
}
|
822
|
+
]
|
823
|
+
}
|
824
|
+
]
|
825
|
+
}
|
826
|
+
end
|
827
|
+
|
828
|
+
it 'returns the chart_data' do
|
829
|
+
expect(chart_data).to eq({
|
830
|
+
labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
|
831
|
+
datasets: [
|
832
|
+
{
|
833
|
+
label: repo.to_s,
|
834
|
+
data: [1, 2, 2]
|
835
|
+
},
|
836
|
+
{
|
837
|
+
label: repo2.to_s,
|
838
|
+
data: [0, 0, 1]
|
839
|
+
}
|
840
|
+
]
|
841
|
+
})
|
842
|
+
end
|
843
|
+
end
|
844
|
+
end
|
845
|
+
end
|
275
846
|
end
|
276
847
|
|
277
848
|
# These examples allow for quick comparisons of many types of inputs and outputs.
|
278
849
|
# When making functional modifications, run these to see whether the modifications impact the output in any cases.
|
279
850
|
# If the output effects are desired, run `REWRITE_RESULTS=1 rspec` to write them to the outputs YAML file, then verify that the output
|
280
851
|
# modifications are desired, then commit the result and uncomment the `skip`.
|
281
|
-
describe '
|
852
|
+
describe 'YAML-based output comparisons' do
|
282
853
|
FIXTURES_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'fixtures'))
|
283
854
|
|
284
855
|
let(:inputs) { YAML.load_file("#{FIXTURES_DIRECTORY}/generate_inputs.yml") }
|
285
856
|
let(:outputs_path) { "#{FIXTURES_DIRECTORY}/generate_outputs.yml" }
|
286
857
|
let(:outputs) { YAML.load_file(outputs_path) }
|
287
858
|
|
859
|
+
let!(:repo) { create(:repo, full_name: 'foo/bar1') }
|
860
|
+
let!(:repo2) { create(:repo, full_name: 'foo/bar2') }
|
861
|
+
let!(:issues) do
|
862
|
+
[
|
863
|
+
create(:issue, repo: repo, state: 'open', opened_at: now - 2.weeks),
|
864
|
+
create(:issue, repo: repo, state: 'closed', opened_at: now)
|
865
|
+
]
|
866
|
+
end
|
867
|
+
let!(:labels) do
|
868
|
+
[
|
869
|
+
create(:label, repo: repo),
|
870
|
+
create(:label, repo: repo2),
|
871
|
+
create(:label, repo: repo2)
|
872
|
+
]
|
873
|
+
end
|
874
|
+
|
288
875
|
context 'input examples' do
|
289
876
|
YAML.load_file("#{FIXTURES_DIRECTORY}/generate_inputs.yml").each.with_index do |inputs, index|
|
290
|
-
it
|
291
|
-
expect(described_class.new(inputs).perform).to eq(outputs[index])
|
877
|
+
it "returns the expected output for input ##{index}: #{inputs.to_json}" do
|
878
|
+
expect(described_class.new(inputs).perform.to_yaml).to eq(outputs[index].to_yaml)
|
292
879
|
end
|
293
880
|
end
|
294
881
|
end
|
295
882
|
|
296
883
|
context 'writing the outputs' do
|
297
|
-
# For documentation about this `skip`, see the comment at the top of this `describe` block.
|
298
|
-
skip unless ENV['REWRITE_RESULTS'] == '1'
|
299
|
-
|
300
884
|
it 'writes the outputs' do
|
885
|
+
# For documentation about this `skip`, see the comment at the top of this `describe` block.
|
886
|
+
skip unless ENV['REWRITE_RESULTS'] == '1'
|
887
|
+
|
301
888
|
outputs = inputs.map do |example|
|
302
889
|
described_class.new(example).perform
|
303
890
|
end
|