tabstabs 2.0.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 +7 -0
- data/.gitignore +20 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +421 -0
- data/Rakefile +5 -0
- data/lib/tabs_tabs.rb +26 -0
- data/lib/tabs_tabs/config.rb +65 -0
- data/lib/tabs_tabs/helpers.rb +27 -0
- data/lib/tabs_tabs/metrics/counter.rb +69 -0
- data/lib/tabs_tabs/metrics/counter/stats.rb +51 -0
- data/lib/tabs_tabs/metrics/task.rb +72 -0
- data/lib/tabs_tabs/metrics/task/token.rb +89 -0
- data/lib/tabs_tabs/metrics/value.rb +91 -0
- data/lib/tabs_tabs/metrics/value/stats.rb +55 -0
- data/lib/tabs_tabs/resolution.rb +65 -0
- data/lib/tabs_tabs/resolutionable.rb +48 -0
- data/lib/tabs_tabs/resolutions/day.rb +40 -0
- data/lib/tabs_tabs/resolutions/hour.rb +40 -0
- data/lib/tabs_tabs/resolutions/minute.rb +40 -0
- data/lib/tabs_tabs/resolutions/month.rb +40 -0
- data/lib/tabs_tabs/resolutions/week.rb +40 -0
- data/lib/tabs_tabs/resolutions/year.rb +40 -0
- data/lib/tabs_tabs/storage.rb +105 -0
- data/lib/tabs_tabs/tabs_tabs.rb +117 -0
- data/lib/tabs_tabs/version.rb +3 -0
- data/spec/lib/tabs_tabs/config_spec.rb +60 -0
- data/spec/lib/tabs_tabs/metrics/counter/stats_spec.rb +42 -0
- data/spec/lib/tabs_tabs/metrics/counter_spec.rb +196 -0
- data/spec/lib/tabs_tabs/metrics/task/token_spec.rb +18 -0
- data/spec/lib/tabs_tabs/metrics/task_spec.rb +103 -0
- data/spec/lib/tabs_tabs/metrics/value/stats_spec.rb +61 -0
- data/spec/lib/tabs_tabs/metrics/value_spec.rb +160 -0
- data/spec/lib/tabs_tabs/resolution_spec.rb +52 -0
- data/spec/lib/tabs_tabs/resolutionable_spec.rb +53 -0
- data/spec/lib/tabs_tabs/resolutions/day_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/hour_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/minute_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/month_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/week_spec.rb +24 -0
- data/spec/lib/tabs_tabs/resolutions/year_spec.rb +23 -0
- data/spec/lib/tabs_tabs/storage_spec.rb +138 -0
- data/spec/lib/tabs_tabs_spec.rb +223 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/custom_resolutions.rb +40 -0
- data/tabs_tabs.gemspec +31 -0
- metadata +213 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Metrics::Value::Stats do
|
4
|
+
|
5
|
+
let(:period) { (Time.now - 2.days..Time.now) }
|
6
|
+
let(:resolution) { :hour }
|
7
|
+
let(:values) do
|
8
|
+
[
|
9
|
+
{ "timestamp" => Time.now - 30.hours, "count" => 10, "sum" => 145, "min" => 11, "max" => 204, "avg" => 14.5 },
|
10
|
+
{ "timestamp" => Time.now - 20.hours, "count" => 15, "sum" => 288, "min" => 10, "max" => 199, "avg" => 19.2 },
|
11
|
+
{ "timestamp" => Time.now - 10.hours, "count" => 25, "sum" => 405, "min" => 12, "max" => 210, "avg" => 16.2 }
|
12
|
+
]
|
13
|
+
end
|
14
|
+
let(:stats) { TabsTabs::Metrics::Value::Stats.new(period, resolution, values) }
|
15
|
+
|
16
|
+
it "is enumerable" do
|
17
|
+
expect(stats).to respond_to :each
|
18
|
+
expect(TabsTabs::Metrics::Value::Stats.ancestors).to include Enumerable
|
19
|
+
end
|
20
|
+
|
21
|
+
it "#count returns the total count for the entire set" do
|
22
|
+
expect(stats.count).to eq 50
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sum returns the sum for the entire set" do
|
26
|
+
expect(stats.sum).to eq 838
|
27
|
+
end
|
28
|
+
|
29
|
+
it "min returns the min for the entire set" do
|
30
|
+
expect(stats.min).to eq 10
|
31
|
+
end
|
32
|
+
|
33
|
+
it "max returns the max for the entire set" do
|
34
|
+
expect(stats.max).to eq 210
|
35
|
+
end
|
36
|
+
|
37
|
+
it "avg returns the average for the entire set" do
|
38
|
+
expect(stats.avg).to eq 16.76
|
39
|
+
end
|
40
|
+
|
41
|
+
it "avg returns 0 if set is empty" do
|
42
|
+
stats = TabsTabs::Metrics::Value::Stats.new(period, resolution, [])
|
43
|
+
expect(stats.avg).to be_zero
|
44
|
+
end
|
45
|
+
|
46
|
+
context "override decimal precision" do
|
47
|
+
before do
|
48
|
+
@precision = TabsTabs.config.decimal_precision
|
49
|
+
TabsTabs.config.decimal_precision = 1
|
50
|
+
end
|
51
|
+
|
52
|
+
after do
|
53
|
+
TabsTabs.config.decimal_precision = @precision
|
54
|
+
end
|
55
|
+
|
56
|
+
it "allows you to override decimal precision" do
|
57
|
+
expect(stats.avg).to eq 16.8
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Metrics::Value do
|
4
|
+
|
5
|
+
include TabsTabs::Storage
|
6
|
+
|
7
|
+
let(:metric) { TabsTabs.create_metric("foo", "value") }
|
8
|
+
let(:now) { Time.utc(2000, 1, 1, 0, 0) }
|
9
|
+
|
10
|
+
describe ".record" do
|
11
|
+
|
12
|
+
before { Timecop.freeze(now) }
|
13
|
+
|
14
|
+
it "sets the expected values for the period" do
|
15
|
+
metric.record(17)
|
16
|
+
metric.record(42)
|
17
|
+
time = Time.utc(now.year, now.month, now.day, now.hour)
|
18
|
+
stats = metric.stats(((now - 2.hours)..(now + 4.hours)), :hour)
|
19
|
+
expect(stats).to include({ "timestamp"=>time, "count"=>2, "min"=>17, "max"=>42, "sum"=>59, "avg"=>29.5})
|
20
|
+
end
|
21
|
+
|
22
|
+
it "applys the value to the specified timestamp if one is supplied" do
|
23
|
+
time = Time.utc(now.year, now.month, now.day, now.hour) - 2.hours
|
24
|
+
metric.record(42, time)
|
25
|
+
stats = metric.stats(((now - 3.hours)..now), :hour)
|
26
|
+
expect(stats).to include({ "timestamp"=>time, "count"=>1, "min"=>42, "max"=>42, "sum"=>42, "avg"=>42})
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe ".stats" do
|
32
|
+
|
33
|
+
before do
|
34
|
+
Timecop.freeze(now)
|
35
|
+
end
|
36
|
+
|
37
|
+
after do
|
38
|
+
Timecop.return
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_span(time_unit)
|
42
|
+
metric.record(5)
|
43
|
+
Timecop.freeze(now + 1.send(time_unit))
|
44
|
+
metric.record(25)
|
45
|
+
Timecop.freeze(now + 3.send(time_unit))
|
46
|
+
metric.record(10)
|
47
|
+
Timecop.freeze(now + 6.send(time_unit))
|
48
|
+
metric.record(15)
|
49
|
+
metric.record(20)
|
50
|
+
Timecop.freeze(now)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns an instance of Tabs::Metrics::Value::Stats" do
|
54
|
+
create_span(:minutes)
|
55
|
+
stats = metric.stats(now..(now + 7.minutes), :minute)
|
56
|
+
expect(stats).to be_a_kind_of TabsTabs::Metrics::Value::Stats
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns the expected results for an minutely metric" do
|
60
|
+
create_span(:minutes)
|
61
|
+
stats = metric.stats(now..(now + 7.minutes), :minute)
|
62
|
+
expect(stats).to include({ "timestamp" => (now + 3.minutes), "count"=>1, "min"=>10, "max"=>10, "sum"=>10, "avg"=>10})
|
63
|
+
expect(stats).to include({ "timestamp" => (now + 6.minutes), "count"=>2, "min"=>15, "max"=>20, "sum"=>35, "avg"=>17.5})
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns the expected results for an hourly metric" do
|
67
|
+
create_span(:hours)
|
68
|
+
stats = metric.stats(now..(now + 7.hours), :hour)
|
69
|
+
expect(stats).to include({ "timestamp" => (now + 3.hours), "count"=>1, "min"=>10, "max"=>10, "sum"=>10, "avg"=>10})
|
70
|
+
expect(stats).to include({ "timestamp" => (now + 6.hours), "count"=>2, "min"=>15, "max"=>20, "sum"=>35, "avg"=>17.5})
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns the expected results for a daily metric" do
|
74
|
+
create_span(:days)
|
75
|
+
stats = metric.stats(now..(now + 7.days), :day)
|
76
|
+
expect(stats).to include({ "timestamp" => (now + 3.days), "count"=>1, "min"=>10, "max"=>10, "sum"=>10, "avg"=>10})
|
77
|
+
expect(stats).to include({ "timestamp" => (now + 6.days), "count"=>2, "min"=>15, "max"=>20, "sum"=>35, "avg"=>17.5})
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns the expected results for a weekly metric" do
|
81
|
+
create_span(:weeks)
|
82
|
+
stats = metric.stats(now..(now + 7.weeks), :week)
|
83
|
+
second_week_stats = stats.detect{|s| s["timestamp"] == (now + 1.week).beginning_of_week }
|
84
|
+
expect(second_week_stats["count"]).to eq(1)
|
85
|
+
expect(stats).to include({ "timestamp" => (now + 3.weeks).beginning_of_week, "count"=>1, "min"=>10, "max"=>10, "sum"=>10, "avg"=>10})
|
86
|
+
expect(stats).to include({ "timestamp" => (now + 6.weeks).beginning_of_week, "count"=>2, "min"=>15, "max"=>20, "sum"=>35, "avg"=>17.5})
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns the expected results for a monthly metric" do
|
90
|
+
create_span(:months)
|
91
|
+
stats = metric.stats(now..(now + 7.months), :month)
|
92
|
+
expect(stats).to include({ "timestamp" => (now + 3.months), "count"=>1, "min"=>10, "max"=>10, "sum"=>10, "avg"=>10})
|
93
|
+
expect(stats).to include({ "timestamp" => (now + 6.months), "count"=>2, "min"=>15, "max"=>20, "sum"=>35, "avg"=>17.5})
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns the expected results for a yearly metric" do
|
97
|
+
create_span(:years)
|
98
|
+
stats = metric.stats(now..(now + 7.years), :year)
|
99
|
+
expect(stats).to include({ "timestamp" => (now + 3.years), "count"=>1, "min"=>10, "max"=>10, "sum"=>10, "avg"=>10})
|
100
|
+
expect(stats).to include({ "timestamp" => (now + 6.years), "count"=>2, "min"=>15, "max"=>20, "sum"=>35, "avg"=>17.5})
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe ".drop!" do
|
105
|
+
|
106
|
+
before do
|
107
|
+
3.times { metric.record(rand(30)) }
|
108
|
+
@count_keys = (TabsTabs::Resolution.all.map do |res|
|
109
|
+
smembers("stat:value:foo:keys:#{res}")
|
110
|
+
end).flatten
|
111
|
+
metric.drop!
|
112
|
+
end
|
113
|
+
|
114
|
+
it "deletes all resolution count keys" do
|
115
|
+
@count_keys.each do |key|
|
116
|
+
expect(exists(key)).to be_false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it "deletes all resolution key collection keys" do
|
121
|
+
TabsTabs::Resolution.all.each do |res|
|
122
|
+
expect(exists("stat:value:foo:keys:#{res}")).to be_falsey
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
describe ".drop_by_resolution!" do
|
129
|
+
before do
|
130
|
+
Timecop.freeze(now)
|
131
|
+
2.times { metric.record(rand(30)) }
|
132
|
+
metric.drop_by_resolution!(:minute)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "deletes all metrics for a resolution" do
|
136
|
+
stats = metric.stats((now - 1.minute)..(now + 1.minute), :minute)
|
137
|
+
expect(stats.sum).to eq(0)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "expiration of value metrics" do
|
142
|
+
let(:expires_setting){ 6.hours }
|
143
|
+
let(:now){ Time.utc(2050, 1, 1, 0, 0) }
|
144
|
+
|
145
|
+
before do
|
146
|
+
TabsTabs::Config.set_expirations({minute: expires_setting })
|
147
|
+
end
|
148
|
+
|
149
|
+
after do
|
150
|
+
TabsTabs::Config.reset_expirations
|
151
|
+
end
|
152
|
+
|
153
|
+
it "sets an expiration when recording a value" do
|
154
|
+
metric.record(17, now)
|
155
|
+
redis_expire_date = Time.now + TabsTabs::Storage.ttl(metric.storage_key(:minute, now))
|
156
|
+
expire_date = now + expires_setting + TabsTabs::Resolutions::Minute.to_seconds
|
157
|
+
expect(redis_expire_date).to be_within(2.seconds).of(expire_date)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require File.expand_path("../../../support/custom_resolutions", __FILE__)
|
3
|
+
|
4
|
+
describe TabsTabs::Resolution do
|
5
|
+
|
6
|
+
describe "#register" do
|
7
|
+
it "registers a new resolution" do
|
8
|
+
TabsTabs::Resolution.register(WellFormedResolution)
|
9
|
+
expect(TabsTabs::Resolution.all).to include WellFormedResolution.name
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with a custom resolution" do
|
13
|
+
it "does not return nil" do
|
14
|
+
expect(WellFormedResolution.serialize(Time.now)).to_not be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it "gets stats for custom resolution" do
|
18
|
+
TabsTabs::Resolution.register(WellFormedResolution)
|
19
|
+
Timecop.freeze(Time.now)
|
20
|
+
|
21
|
+
TabsTabs.increment_counter("foo")
|
22
|
+
expect(TabsTabs.get_stats("foo", (Time.now - 5.seconds..Time.now), :seconds).values.size).to eq(6)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises an error when method not implemented" do
|
26
|
+
expect{BadlyFormedResolution.normalize}.to raise_error(RuntimeError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "disregards already registered resolutions" do
|
30
|
+
expect { TabsTabs::Resolution.register(TabsTabs::Resolutions::Minute) }.to_not raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#unregister" do
|
36
|
+
it "unregisters a single resolution" do
|
37
|
+
TabsTabs::Resolution.unregister(:minute)
|
38
|
+
expect(TabsTabs::Resolution.all).to_not include(:minute)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "unregisters an array of resolutions" do
|
42
|
+
TabsTabs::Resolution.unregister([:minute, :hour])
|
43
|
+
expect(TabsTabs::Resolution.all).to_not include(:hour)
|
44
|
+
expect(TabsTabs::Resolution.all).to_not include(:minute)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "disregards passing in an unrecognized resolution" do
|
48
|
+
expect { TabsTabs::Resolution.unregister(:invalid_resolution) }.to_not raise_error
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Resolutionable do
|
4
|
+
|
5
|
+
module TestResolution
|
6
|
+
include TabsTabs::Resolutionable
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def name
|
10
|
+
:test
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_seconds
|
14
|
+
1000
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "interface exceptions" do
|
20
|
+
|
21
|
+
["serialize", "deserialize", "from_seconds", "add", "normalize"].each do |method|
|
22
|
+
it "are raised when the #{method} method is not implemented" do
|
23
|
+
expect { TestResolution.send(method) }.to raise_error(RuntimeError)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#expire" do
|
30
|
+
let(:expires_setting){ 1.day }
|
31
|
+
|
32
|
+
before do
|
33
|
+
TabsTabs::Config.register_resolution(TestResolution)
|
34
|
+
TabsTabs::Config.set_expirations(test: expires_setting)
|
35
|
+
end
|
36
|
+
|
37
|
+
after do
|
38
|
+
TabsTabs::Config.reset_expirations
|
39
|
+
TabsTabs::Config.unregister_resolutions(:test)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "sets the expiration for the given key" do
|
43
|
+
now = Time.utc(2050, 1, 1, 0, 0, 0)
|
44
|
+
TabsTabs::Storage.set("foo", "bar")
|
45
|
+
TestResolution.expire("foo", now)
|
46
|
+
redis_expire_date = Time.now + TabsTabs::Storage.ttl("foo")
|
47
|
+
expire_date = now + expires_setting + TestResolution.to_seconds
|
48
|
+
expect(redis_expire_date).to be_within(2.seconds).of(expire_date)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Resolutions::Day do
|
4
|
+
let(:timestamp){ Time.new(2000, 1, 1, 12, 15) }
|
5
|
+
|
6
|
+
context "#normalize" do
|
7
|
+
it "should normalize the date to year, month, day" do
|
8
|
+
expect(subject.normalize(timestamp)).to eq(timestamp.utc.change(hour: 0))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "#serialize" do
|
13
|
+
it "should return YYYY-MM-DD" do
|
14
|
+
expect(subject.serialize(timestamp)).to eq("2000-01-01")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "#deserialize" do
|
19
|
+
it "should convert string into date" do
|
20
|
+
expect(subject.deserialize("2000-01-01")).to eq(timestamp.utc.change(hour: 0))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Resolutions::Hour do
|
4
|
+
let(:timestamp){ Time.utc(2000, 1, 1, 14, 12) }
|
5
|
+
|
6
|
+
context "#normalize" do
|
7
|
+
it "should normalize the date to year, month, day, hour" do
|
8
|
+
expect(subject.normalize(timestamp)).to eq(timestamp.change(min: 0))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "#serialize" do
|
13
|
+
it "should return YYYY-MM-DD-HH" do
|
14
|
+
expect(subject.serialize(timestamp)).to eq("2000-01-01-14")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "#deserialize" do
|
19
|
+
it "should convert string into date" do
|
20
|
+
expect(subject.deserialize("2000-01-01-14")).to eq(timestamp.change(min: 0))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Resolutions::Minute do
|
4
|
+
let(:timestamp){ Time.utc(2000, 1, 1, 14, 12, 44) }
|
5
|
+
|
6
|
+
context "#normalize" do
|
7
|
+
it "should normalize the date to year, month, day, hour, minute" do
|
8
|
+
expect(subject.normalize(timestamp)).to eq(timestamp.change(sec: 0))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "#serialize" do
|
13
|
+
it "should return YYYY-MM-DD-HH-MM" do
|
14
|
+
expect(subject.serialize(timestamp)).to eq("2000-01-01-14-12")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "#deserialize" do
|
19
|
+
it "should convert string into date" do
|
20
|
+
expect(subject.deserialize("2000-01-01-14-12")).to eq(timestamp.change(sec: 0))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Resolutions::Month do
|
4
|
+
let(:timestamp){ Time.utc(2000, 1, 15) }
|
5
|
+
|
6
|
+
context "#normalize" do
|
7
|
+
it "should normalize the date to year, month" do
|
8
|
+
expect(subject.normalize(timestamp)).to eq(timestamp.change(day: 1))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "#serialize" do
|
13
|
+
it "should return YYYY-MM" do
|
14
|
+
expect(subject.serialize(timestamp)).to eq("2000-01")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "#deserialize" do
|
19
|
+
it "should convert string into date" do
|
20
|
+
expect(subject.deserialize("2000-01")).to eq(timestamp.change(day: 1))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TabsTabs::Resolutions::Week do
|
4
|
+
let(:timestamp){ Time.utc(2000, 1, 1) }
|
5
|
+
let(:beginning_of_week_timestamp){ Time.utc(1999, 12, 27) }
|
6
|
+
|
7
|
+
context "#normalize" do
|
8
|
+
it "should roll to the beginning of the week" do
|
9
|
+
expect(subject.normalize(timestamp)).to eq(beginning_of_week_timestamp)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#serialize" do
|
14
|
+
it "should return YYYY-MM-DD based on beginning of the week" do
|
15
|
+
expect(subject.serialize(timestamp)).to eq("1999-12-27")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "#deserialize" do
|
20
|
+
it "should convert beginning of week string into date" do
|
21
|
+
expect(subject.deserialize("1999-12-27")).to eq(beginning_of_week_timestamp)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|