Skip to content

Commit 9c630be

Browse files
committed
Adjust behaviour to new decisions:
options default: {} API: options is not nullable specific option is additive specific option is nullable empty hash does not change anything (additive) get empty options -> {} manifest: options and specific option is not nullable
1 parent f62163e commit 9c630be

File tree

9 files changed

+101
-59
lines changed

9 files changed

+101
-59
lines changed

app/actions/route_update.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ class RouteUpdate
33
def update(route:, message:)
44
Route.db.transaction do
55
if message.requested?(:options)
6-
route.options = if message.options.nil?
7-
nil
8-
elsif route.options.nil?
6+
route.options = if route.options.nil?
97
message.options
108
else
11-
route.options.merge(message.options)
9+
route.options.symbolize_keys.merge(message.options).compact
1210
end
1311
end
1412

app/messages/route_options_message.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class RouteOptionsMessage < BaseMessage
66
VALID_ROUTE_OPTIONS = %i[lb_algo].freeze
77
VALID_LOADBALANCING_ALGORITHMS = %w[round-robin least-connections].freeze
88

9-
register_allowed_keys %i[lb_algo]
9+
register_allowed_keys VALID_ROUTE_OPTIONS
1010
validates_with NoAdditionalKeysValidator
1111
validates :lb_algo,
1212
inclusion: { in: VALID_LOADBALANCING_ALGORITHMS, message: "'%<value>s' is not a supported load-balancing algorithm" },

app/messages/validators.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ def validate(record)
242242

243243
class OptionsValidator < ActiveModel::Validator
244244
def validate(record)
245+
# If the options key is provided, it must not be nil
246+
if record.respond_to?(:options) && record.options.nil?
247+
record.errors.add(:options, message: "'options' must not be explicitly set to null")
248+
return
249+
end
250+
245251
# Empty option hashes are allowed, so we skip further validation
246252
record.options.blank? && return
247253

db/migrations/20241105000000_add_options_to_route.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
up do
33
alter_table(:routes) do
44
# rubocop:disable Migration/IncludeStringSize
5-
add_column :options, String, text: true, default: nil
5+
add_column :options, String, text: true, default: '{}'
66
# rubocop:enable Migration/IncludeStringSize
77
end
88
end

lib/cloud_controller/app_manifest/manifest_route.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def self.parse(route, options=nil)
2828
def valid?
2929
if @attrs[:options] && !@attrs[:options].empty?
3030
return false if @attrs[:options].keys.any? { |key| RouteOptionsMessage::VALID_ROUTE_OPTIONS.exclude?(key) }
31+
# validation for loadbalancing algorithm
3132
return false if @attrs[:options][:lb_algo] && RouteOptionsMessage::VALID_LOADBALANCING_ALGORITHMS.exclude?(@attrs[:options][:lb_algo])
3233
end
3334

spec/unit/actions/route_update_spec.rb

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ module VCAP::CloudController
3636
metadata: {
3737
labels: new_labels,
3838
annotations: new_annotations
39-
},
40-
options: {
41-
lb_algo: 'round-robin'
4239
}
4340
}
4441
end
@@ -136,98 +133,94 @@ module VCAP::CloudController
136133
end
137134
end
138135
end
136+
139137
describe '#update options' do
140-
context 'when the route has no existing metadata' do
141-
context 'when no metadata is specified' do
138+
context 'when the route has no existing options' do
139+
context 'when no options are specified' do
142140
let(:body) do
143141
{}
144142
end
145143

146-
it 'adds no metadata' do
144+
it 'adds no options' do
147145
expect(message).to be_valid
148146
subject.update(route:, message:)
149147
route.reload
150-
expect(route.labels.size).to eq(0)
151-
expect(route.annotations.size).to eq(0)
148+
expect(route.options).to eq({})
152149
end
153150
end
154151

155-
context 'when metadata is specified' do
156-
it 'updates the route metadata' do
152+
context 'when an option is specified' do
153+
let(:body) do
154+
{
155+
options: {
156+
lb_algo: 'round-robin'
157+
}
158+
}
159+
end
160+
161+
it 'adds the route option' do
157162
expect(message).to be_valid
158163
subject.update(route:, message:)
159164

160165
route.reload
161-
expect(route).to have_labels(
162-
{ prefix: 'doordash.com', key_name: 'potato', value: 'mashed' },
163-
{ prefix: nil, key_name: 'fruit', value: 'strawberries' },
164-
{ prefix: nil, key_name: 'cuisine', value: 'thai' }
165-
)
166-
expect(route).to have_annotations(
167-
{ key_name: 'potato', value: 'idaho' }
168-
)
169166
expect(route[:options]).to eq('{"lb_algo":"round-robin"}')
170167
end
171168
end
172169
end
173170

174-
context 'when the route has existing metadata' do
171+
context 'when the route has existing options' do
175172
before do
176-
VCAP::CloudController::LabelsUpdate.update(route, old_labels, VCAP::CloudController::RouteLabelModel)
177-
VCAP::CloudController::AnnotationsUpdate.update(route, old_annotations, VCAP::CloudController::RouteAnnotationModel)
178173
route[:options] = '{"lb_algo": "round-robin"}'
179174
end
180175

181-
context 'when no metadata is specified' do
176+
context 'when no options are specified' do
182177
let(:body) do
183178
{}
184179
end
185180

186-
it 'adds no metadata' do
181+
it 'modifies nothing' do
187182
expect(message).to be_valid
188183
subject.update(route:, message:)
189184
route.reload
190-
expect(route).to have_labels(
191-
{ prefix: nil, key_name: 'fruit', value: 'peach' },
192-
{ prefix: nil, key_name: 'clothing', value: 'blouse' }
193-
)
194-
expect(route).to have_annotations(
195-
{ key_name: 'potato', value: 'celandine' },
196-
{ key_name: 'beet', value: 'formanova' }
197-
)
198185
expect(route.options).to include({ 'lb_algo' => 'round-robin' })
199186
end
200187
end
201188

202-
context 'when metadata is specified' do
189+
context 'when an option is specified' do
203190
let(:body) do
204191
{
205-
metadata: {
206-
labels: new_labels.merge(fruit: nil, newstuff: 'here'),
207-
annotations: new_annotations.merge(beet: nil, asparagus: 'crunchy')
192+
options: {
193+
lb_algo: 'least-connections'
208194
}
209195
}
210196
end
211197

212-
it 'updates some, deletes nils, leaves unspecified fields alone' do
198+
it 'updates the option' do
213199
expect(message).to be_valid
214200
subject.update(route:, message:)
215201
route.reload
216202

217-
expect(route).to have_labels(
218-
{ prefix: 'doordash.com', key_name: 'potato', value: 'mashed' },
219-
{ prefix: nil, key_name: 'clothing', value: 'blouse' },
220-
{ prefix: nil, key_name: 'newstuff', value: 'here' },
221-
{ prefix: nil, key_name: 'cuisine', value: 'thai' }
222-
)
223-
expect(route).to have_annotations(
224-
{ key_name: 'potato', value: 'idaho' },
225-
{ key_name: 'asparagus', value: 'crunchy' }
226-
)
203+
expect(route.options).to include({ 'lb_algo' => 'least-connections' })
204+
end
205+
end
206+
207+
context 'when the option value is set to null' do
208+
let(:body) do
209+
{
210+
options: {
211+
lb_algo: nil
212+
}
213+
}
214+
end
215+
216+
it 'removes this option' do
217+
expect(message).to be_valid
218+
subject.update(route:, message:)
219+
route.reload
220+
expect(route.options).to eq({})
227221
end
228222
end
229223
end
230224
end
231-
232225
end
233226
end

spec/unit/lib/cloud_controller/app_manifest/manifest_route_spec.rb

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,16 @@ module VCAP::CloudController
117117
end
118118
end
119119

120+
context 'when options is set to null' do
121+
let(:route) { 'http://example.com' }
122+
123+
it 'is invalid' do
124+
options = nil
125+
manifest_route = ManifestRoute.parse(route, options)
126+
expect(manifest_route.valid?).to be(false)
127+
end
128+
end
129+
120130
context 'when there is an invalid loadbalancing-algorithm' do
121131
let(:route) { 'http://example.com' }
122132
let(:options) { { 'loadbalancing-algorithm': 'invalid' } }
@@ -140,7 +150,7 @@ module VCAP::CloudController
140150
],
141151
port: nil,
142152
path: '/path',
143-
options: nil
153+
options: {}
144154
})
145155
end
146156

@@ -153,7 +163,7 @@ module VCAP::CloudController
153163
],
154164
port: nil,
155165
path: '/path',
156-
options: nil
166+
options: {}
157167
})
158168
end
159169

@@ -167,7 +177,7 @@ module VCAP::CloudController
167177
],
168178
port: nil,
169179
path: '/path',
170-
options: nil
180+
options: {}
171181
})
172182
end
173183

@@ -181,7 +191,7 @@ module VCAP::CloudController
181191
],
182192
port: 1234,
183193
path: '',
184-
options: nil
194+
options: {}
185195
})
186196
end
187197

spec/unit/messages/manifest_routes_update_message_spec.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,22 @@ module VCAP::CloudController
225225
end
226226
end
227227

228+
context 'when a route contains route-options: null' do
229+
let(:body) do
230+
{ 'routes' =>
231+
[
232+
{ 'route' => 'existing.example.com',
233+
'options' => nil }
234+
] }
235+
end
236+
237+
it 'returns true' do
238+
msg = ManifestRoutesUpdateMessage.new(body)
239+
240+
expect(msg.valid?).to be(false)
241+
end
242+
end
243+
228244
context 'when a route contains invalid route options' do
229245
let(:body) do
230246
{ 'routes' =>
@@ -241,6 +257,24 @@ module VCAP::CloudController
241257
end
242258
end
243259

260+
context 'when a route contains a route option key: null' do
261+
let(:body) do
262+
{ 'routes' =>
263+
[
264+
{ 'route' => 'existing.example.com',
265+
'options' => {
266+
'loadbalancing-algorithm' => nil
267+
} }
268+
] }
269+
end
270+
271+
it 'returns true' do
272+
msg = ManifestRoutesUpdateMessage.new(body)
273+
274+
expect(msg.valid?).to be(false)
275+
end
276+
end
277+
244278
context 'when a route contains a valid loadbalancing-algorithm' do
245279
let(:body) do
246280
{ 'routes' =>

spec/unit/messages/route_update_message_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ module VCAP::CloudController
2828
expect(message).to be_valid
2929
end
3030

31-
it 'accepts options: nil to unset options' do
31+
it 'does not accept options: nil' do
3232
message = RouteUpdateMessage.new(params.merge(options: nil))
33-
expect(message).to be_valid
33+
expect(message).not_to be_valid
3434
end
3535

3636
it 'accepts lb_algo: nil to unset load-balancing algorithm' do

0 commit comments

Comments
 (0)