11package ratelimits
22
33import (
4+ "context"
5+ "errors"
46 "net/netip"
57 "os"
68 "path/filepath"
79 "strings"
810 "testing"
911 "time"
1012
13+ "github.com/prometheus/client_golang/prometheus"
14+ io_prometheus_client "github.com/prometheus/client_model/go"
15+
1116 "github.com/letsencrypt/boulder/config"
1217 "github.com/letsencrypt/boulder/identifier"
18+ blog "github.com/letsencrypt/boulder/log"
19+ "github.com/letsencrypt/boulder/metrics"
1320 "github.com/letsencrypt/boulder/test"
1421)
1522
@@ -26,11 +33,11 @@ func loadAndParseDefaultLimits(path string) (Limits, error) {
2633 return parseDefaultLimits (fromFile )
2734}
2835
29- // loadAndParseOverrideLimits is a helper that calls both loadOverrides and
30- // parseOverrideLimits to handle a YAML file.
36+ // loadAndParseOverrideLimitsFromFile is a helper that calls both
37+ // loadOverridesFromFile and parseOverrideLimits to handle a YAML file.
3138//
3239// TODO(#7901): Update the tests to test these functions individually.
33- func loadAndParseOverrideLimits (path string ) (Limits , error ) {
40+ func loadAndParseOverrideLimitsFromFile (path string ) (Limits , error ) {
3441 fromFile , err := loadOverridesFromFile (path )
3542 if err != nil {
3643 return nil , err
@@ -148,25 +155,25 @@ func TestValidateLimit(t *testing.T) {
148155 }
149156}
150157
151- func TestLoadAndParseOverrideLimits (t * testing.T ) {
158+ func TestLoadAndParseOverrideLimitsFromFile (t * testing.T ) {
152159 // Load a single valid override limit with Id formatted as 'enum:RegId'.
153- l , err := loadAndParseOverrideLimits ("testdata/working_override.yml" )
160+ l , err := loadAndParseOverrideLimitsFromFile ("testdata/working_override.yml" )
154161 test .AssertNotError (t , err , "valid single override limit" )
155162 expectKey := joinWithColon (NewRegistrationsPerIPAddress .EnumString (), "64.112.117.1" )
156163 test .AssertEquals (t , l [expectKey ].Burst , int64 (40 ))
157164 test .AssertEquals (t , l [expectKey ].Count , int64 (40 ))
158165 test .AssertEquals (t , l [expectKey ].Period .Duration , time .Second )
159166
160167 // Load single valid override limit with a 'domainOrCIDR' Id.
161- l , err = loadAndParseOverrideLimits ("testdata/working_override_regid_domainorcidr.yml" )
168+ l , err = loadAndParseOverrideLimitsFromFile ("testdata/working_override_regid_domainorcidr.yml" )
162169 test .AssertNotError (t , err , "valid single override limit with Id of regId:domainOrCIDR" )
163170 expectKey = joinWithColon (CertificatesPerDomain .EnumString (), "example.com" )
164171 test .AssertEquals (t , l [expectKey ].Burst , int64 (40 ))
165172 test .AssertEquals (t , l [expectKey ].Count , int64 (40 ))
166173 test .AssertEquals (t , l [expectKey ].Period .Duration , time .Second )
167174
168175 // Load multiple valid override limits with 'regId' Ids.
169- l , err = loadAndParseOverrideLimits ("testdata/working_overrides.yml" )
176+ l , err = loadAndParseOverrideLimitsFromFile ("testdata/working_overrides.yml" )
170177 test .AssertNotError (t , err , "multiple valid override limits" )
171178 expectKey1 := joinWithColon (NewRegistrationsPerIPAddress .EnumString (), "64.112.117.1" )
172179 test .AssertEquals (t , l [expectKey1 ].Burst , int64 (40 ))
@@ -190,7 +197,7 @@ func TestLoadAndParseOverrideLimits(t *testing.T) {
190197 identifier .NewDNS ("example.com" ),
191198 })
192199
193- l , err = loadAndParseOverrideLimits ("testdata/working_overrides_regid_fqdnset.yml" )
200+ l , err = loadAndParseOverrideLimitsFromFile ("testdata/working_overrides_regid_fqdnset.yml" )
194201 test .AssertNotError (t , err , "multiple valid override limits with 'fqdnSet' Ids" )
195202 test .AssertEquals (t , l [entryKey1 ].Burst , int64 (40 ))
196203 test .AssertEquals (t , l [entryKey1 ].Count , int64 (40 ))
@@ -206,46 +213,92 @@ func TestLoadAndParseOverrideLimits(t *testing.T) {
206213 test .AssertEquals (t , l [entryKey4 ].Period .Duration , time .Second * 4 )
207214
208215 // Path is empty string.
209- _ , err = loadAndParseOverrideLimits ("" )
216+ _ , err = loadAndParseOverrideLimitsFromFile ("" )
210217 test .AssertError (t , err , "path is empty string" )
211218 test .Assert (t , os .IsNotExist (err ), "path is empty string" )
212219
213220 // Path to file which does not exist.
214- _ , err = loadAndParseOverrideLimits ("testdata/file_does_not_exist.yml" )
221+ _ , err = loadAndParseOverrideLimitsFromFile ("testdata/file_does_not_exist.yml" )
215222 test .AssertError (t , err , "a file that does not exist " )
216223 test .Assert (t , os .IsNotExist (err ), "test file should not exist" )
217224
218225 // Burst cannot be 0.
219- _ , err = loadAndParseOverrideLimits ("testdata/busted_override_burst_0.yml" )
226+ _ , err = loadAndParseOverrideLimitsFromFile ("testdata/busted_override_burst_0.yml" )
220227 test .AssertError (t , err , "single override limit with burst=0" )
221228 test .AssertContains (t , err .Error (), "invalid burst" )
222229
223230 // Id cannot be empty.
224- _ , err = loadAndParseOverrideLimits ("testdata/busted_override_empty_id.yml" )
231+ _ , err = loadAndParseOverrideLimitsFromFile ("testdata/busted_override_empty_id.yml" )
225232 test .AssertError (t , err , "single override limit with empty id" )
226233 test .Assert (t , ! os .IsNotExist (err ), "test file should exist" )
227234
228235 // Name cannot be empty.
229- _ , err = loadAndParseOverrideLimits ("testdata/busted_override_empty_name.yml" )
236+ _ , err = loadAndParseOverrideLimitsFromFile ("testdata/busted_override_empty_name.yml" )
230237 test .AssertError (t , err , "single override limit with empty name" )
231238 test .Assert (t , ! os .IsNotExist (err ), "test file should exist" )
232239
233240 // Name must be a string representation of a valid Name enumeration.
234- _ , err = loadAndParseOverrideLimits ("testdata/busted_override_invalid_name.yml" )
241+ _ , err = loadAndParseOverrideLimitsFromFile ("testdata/busted_override_invalid_name.yml" )
235242 test .AssertError (t , err , "single override limit with invalid name" )
236243 test .Assert (t , ! os .IsNotExist (err ), "test file should exist" )
237244
238245 // Multiple entries, second entry has a bad name.
239- _ , err = loadAndParseOverrideLimits ("testdata/busted_overrides_second_entry_bad_name.yml" )
246+ _ , err = loadAndParseOverrideLimitsFromFile ("testdata/busted_overrides_second_entry_bad_name.yml" )
240247 test .AssertError (t , err , "multiple override limits, second entry is bad" )
241248 test .Assert (t , ! os .IsNotExist (err ), "test file should exist" )
242249
243250 // Multiple entries, third entry has id of "lol", instead of an IPv4 address.
244- _ , err = loadAndParseOverrideLimits ("testdata/busted_overrides_third_entry_bad_id.yml" )
251+ _ , err = loadAndParseOverrideLimitsFromFile ("testdata/busted_overrides_third_entry_bad_id.yml" )
245252 test .AssertError (t , err , "multiple override limits, third entry has bad Id value" )
246253 test .Assert (t , ! os .IsNotExist (err ), "test file should exist" )
247254}
248255
256+ func TestLoadOverrides (t * testing.T ) {
257+ mockLog := blog .NewMock ()
258+
259+ tb , err := NewTransactionBuilderFromFiles ("../test/config-next/wfe2-ratelimit-defaults.yml" , "../test/config-next/wfe2-ratelimit-overrides.yml" , metrics .NoopRegisterer , mockLog )
260+ test .AssertNotError (t , err , "creating TransactionBuilder" )
261+ overridesData , err := loadOverridesFromFile ("../test/config-next/wfe2-ratelimit-overrides.yml" )
262+ test .AssertNotError (t , err , "loading overrides from file" )
263+ testOverrides , err := parseOverrideLimits (overridesData )
264+ test .AssertNotError (t , err , "parsing overrides" )
265+
266+ test .AssertDeepEquals (t , tb .limitRegistry .overrides , testOverrides )
267+
268+ // FIXME: Test that testLimitRegistry.overridesPerLimit[name] values were set correctly, including that limits without overrides are set to 0.
269+
270+ var iom io_prometheus_client.Metric
271+ err = tb .limitRegistry .overridesTimestamp .Write (& iom )
272+ test .AssertNotError (t , err , "encoding overridesTimestamp metric" )
273+ test .Assert (t , int64 (iom .Gauge .GetValue ()) >= time .Now ().Unix ()- 5 , "overridesTimestamp too old" )
274+
275+ // A failure loading overrides should log and return an error, and not
276+ // overwrite existing overrides.
277+ mockLog .Clear ()
278+ tb .limitRegistry .refreshOverrides = func (context.Context , prometheus.Gauge , blog.Logger ) (Limits , error ) {
279+ return nil , errors .New ("mock failure" )
280+ }
281+ err = tb .limitRegistry .loadOverrides (context .Background ())
282+ test .AssertEquals (t , mockLog .GetAll ()[0 ], "ERR: [AUDIT] loading overrides: mock failure" )
283+ test .AssertError (t , err , "fail to load overrides" )
284+ test .AssertDeepEquals (t , tb .limitRegistry .overrides , testOverrides )
285+
286+ // An empty set of overrides should log a warning, return nil, and not
287+ // overwrite existing overrides.
288+ mockLog .Clear ()
289+ tb .limitRegistry .refreshOverrides = func (context.Context , prometheus.Gauge , blog.Logger ) (Limits , error ) {
290+ return Limits {}, nil
291+ }
292+ err = tb .limitRegistry .loadOverrides (context .Background ())
293+ test .AssertEquals (t , mockLog .GetAll ()[0 ], "WARNING: loading overrides: no valid overrides" )
294+ test .AssertNotError (t , err , "load empty overrides" )
295+ test .AssertDeepEquals (t , tb .limitRegistry .overrides , testOverrides )
296+ }
297+
298+ // FIXME: TestNewRefresher
299+
300+ // FIXME: TestHydrateOverrideLimit
301+
249302func TestLoadAndParseDefaultLimits (t * testing.T ) {
250303 // Load a single valid default limit.
251304 l , err := loadAndParseDefaultLimits ("testdata/working_default.yml" )
0 commit comments