1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
129
130
131
132
133
134
135
136
137
138
139
140
141
|
require 'spec_helper'
describe Gitlab::Cache::RequestStoreWrap, :request_store do
let(:klass) do
Class.new do
extend Gitlab::Cache::RequestStoreWrap
attr_accessor :id, :name, :result, :extra
def self.name
'ExpensiveAlgorithm'
end
def initialize(id, name, result, extra = nil)
self.id = id
self.name = name
self.result = result
self.extra = nil
end
request_store_wrap def compute(arg)
result << arg
end
request_store_wrap def repute(arg)
result << arg
end
def dispute(arg)
result << arg
end
request_store_wrap(:dispute) { extra }
end
end
let(:algorithm) { klass.new('id', 'name', []) }
context 'when RequestStore is active' do
it 'does not compute twice for the same argument' do
result = algorithm.compute(true)
expect(result).to eq([true])
expect(algorithm.compute(true)).to eq(result)
expect(algorithm.result).to eq(result)
end
it 'computes twice for the different argument' do
algorithm.compute(true)
result = algorithm.compute(false)
expect(result).to eq([true, false])
expect(algorithm.result).to eq(result)
end
it 'computes twice for the different class name' do
algorithm.compute(true)
allow(klass).to receive(:name).and_return('CheapAlgo')
result = algorithm.compute(true)
expect(result).to eq([true, true])
expect(algorithm.result).to eq(result)
end
it 'computes twice for the different method' do
algorithm.compute(true)
result = algorithm.repute(true)
expect(result).to eq([true, true])
expect(algorithm.result).to eq(result)
end
it 'computes twice if RequestStore starts over' do
algorithm.compute(true)
RequestStore.end!
RequestStore.clear!
RequestStore.begin!
result = algorithm.compute(true)
expect(result).to eq([true, true])
expect(algorithm.result).to eq(result)
end
context 'when request_store_wrap_key is provided' do
before do
klass.request_store_wrap_key do
[id, name]
end
end
it 'computes twice for the different keys, id' do
algorithm.compute(true)
algorithm.id = 'ad'
result = algorithm.compute(true)
expect(result).to eq([true, true])
expect(algorithm.result).to eq(result)
end
it 'computes twice for the different keys, name' do
algorithm.compute(true)
algorithm.name = 'same'
result = algorithm.compute(true)
expect(result).to eq([true, true])
expect(algorithm.result).to eq(result)
end
it 'uses extra method cache key if provided' do
algorithm.dispute(true) # miss
algorithm.extra = true
algorithm.dispute(true) # miss
result = algorithm.dispute(true) # hit
expect(result).to eq([true, true])
expect(algorithm.result).to eq(result)
end
end
end
context 'when RequestStore is inactive' do
before do
RequestStore.end!
end
it 'computes only once if it is the same instance for the same key' do
algorithm.compute(true)
result = algorithm.compute(true)
expect(result).to eq([true])
expect(algorithm.result).to eq(result)
end
it 'computes twice for different instances even if keys are the same' do
algorithm.compute(true)
result = klass.new('id', 'name', algorithm.result).compute(true)
expect(result).to eq([true, true])
expect(algorithm.result).to eq(result)
end
end
end
|