Skip to content

Commit

Permalink
ratelimits: Add unit test coverage for TransactionBuilder methods (#7752
Browse files Browse the repository at this point in the history
)
  • Loading branch information
beautifulentropy authored Oct 9, 2024
1 parent 15c8752 commit c5dae06
Show file tree
Hide file tree
Showing 2 changed files with 188 additions and 0 deletions.
174 changes: 174 additions & 0 deletions ratelimits/bucket_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package ratelimits

import (
"fmt"
"net"
"sort"
"testing"

"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/test"
)

Expand All @@ -14,3 +18,173 @@ func TestNewTransactionBuilder_WithBadLimitsPath(t *testing.T) {
_, err = NewTransactionBuilder("testdata/defaults.yml", "testdata/does-not-exist.yml")
test.AssertError(t, err, "should error")
}

func sortTransactions(txns []Transaction) []Transaction {
sort.Slice(txns, func(i, j int) bool {
return txns[i].bucketKey < txns[j].bucketKey
})
return txns
}

func TestNewRegistrationsPerIPAddressTransactions(t *testing.T) {
t.Parallel()

tb, err := NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "")
test.AssertNotError(t, err, "creating TransactionBuilder")

// A check-and-spend transaction for the global limit.
txn, err := tb.registrationsPerIPAddressTransaction(net.ParseIP("1.2.3.4"))
test.AssertNotError(t, err, "creating transaction")
test.AssertEquals(t, txn.bucketKey, "1:1.2.3.4")
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
}

func TestNewRegistrationsPerIPv6AddressTransactions(t *testing.T) {
t.Parallel()

tb, err := NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "")
test.AssertNotError(t, err, "creating TransactionBuilder")

// A check-and-spend transaction for the global limit.
txn, err := tb.registrationsPerIPv6RangeTransaction(net.ParseIP("2001:db8::1"))
test.AssertNotError(t, err, "creating transaction")
test.AssertEquals(t, txn.bucketKey, "2:2001:db8::/48")
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
}

func TestNewOrdersPerAccountTransactions(t *testing.T) {
t.Parallel()

tb, err := NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "")
test.AssertNotError(t, err, "creating TransactionBuilder")

// A check-and-spend transaction for the global limit.
txn, err := tb.ordersPerAccountTransaction(123456789)
test.AssertNotError(t, err, "creating transaction")
test.AssertEquals(t, txn.bucketKey, "3:123456789")
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
}

func TestFailedAuthorizationsPerDomainPerAccountTransactions(t *testing.T) {
t.Parallel()

tb, err := NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "testdata/working_override_13371338.yml")
test.AssertNotError(t, err, "creating TransactionBuilder")

// A check-only transaction for the default per-account limit.
txns, err := tb.FailedAuthorizationsPerDomainPerAccountCheckOnlyTransactions(123456789, []string{"so.many.labels.here.example.com"})
test.AssertNotError(t, err, "creating transactions")
test.AssertEquals(t, len(txns), 1)
test.AssertEquals(t, txns[0].bucketKey, "4:123456789:so.many.labels.here.example.com")
test.Assert(t, txns[0].checkOnly(), "should be check-only")
test.Assert(t, !txns[0].limit.isOverride(), "should not be an override")

// A spend-only transaction for the default per-account limit.
txn, err := tb.FailedAuthorizationsPerDomainPerAccountSpendOnlyTransaction(123456789, "so.many.labels.here.example.com")
test.AssertNotError(t, err, "creating transaction")
test.AssertEquals(t, txn.bucketKey, "4:123456789:so.many.labels.here.example.com")
test.Assert(t, txn.spendOnly(), "should be spend-only")
test.Assert(t, !txn.limit.isOverride(), "should not be an override")

// A check-only transaction for the per-account limit override.
txns, err = tb.FailedAuthorizationsPerDomainPerAccountCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com"})
test.AssertNotError(t, err, "creating transactions")
test.AssertEquals(t, len(txns), 1)
test.AssertEquals(t, txns[0].bucketKey, "4:13371338:so.many.labels.here.example.com")
test.Assert(t, txns[0].checkOnly(), "should be check-only")
test.Assert(t, txns[0].limit.isOverride(), "should be an override")

// A spend-only transaction for the per-account limit override.
txn, err = tb.FailedAuthorizationsPerDomainPerAccountSpendOnlyTransaction(13371338, "so.many.labels.here.example.com")
test.AssertNotError(t, err, "creating transaction")
test.AssertEquals(t, txn.bucketKey, "4:13371338:so.many.labels.here.example.com")
test.Assert(t, txn.spendOnly(), "should be spend-only")
test.Assert(t, txn.limit.isOverride(), "should be an override")
}

func TestCertificatesPerDomainTransactions(t *testing.T) {
t.Parallel()

tb, err := NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "")
test.AssertNotError(t, err, "creating TransactionBuilder")

// One check-only transaction for the global limit.
txns, err := tb.certificatesPerDomainCheckOnlyTransactions(123456789, []string{"so.many.labels.here.example.com"})
test.AssertNotError(t, err, "creating transactions")
test.AssertEquals(t, len(txns), 1)
test.AssertEquals(t, txns[0].bucketKey, "5:example.com")
test.Assert(t, txns[0].checkOnly(), "should be check-only")

// One spend-only transaction for the global limit.
txns, err = tb.CertificatesPerDomainSpendOnlyTransactions(123456789, []string{"so.many.labels.here.example.com"})
test.AssertNotError(t, err, "creating transactions")
test.AssertEquals(t, len(txns), 1)
test.AssertEquals(t, txns[0].bucketKey, "5:example.com")
test.Assert(t, txns[0].spendOnly(), "should be spend-only")
}

func TestCertificatesPerDomainPerAccountTransactions(t *testing.T) {
t.Parallel()

tb, err := NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "testdata/working_override_13371338.yml")
test.AssertNotError(t, err, "creating TransactionBuilder")

// We only expect a single check-only transaction for the per-account limit
// override. We can safely ignore the global limit when an override is
// present.
txns, err := tb.certificatesPerDomainCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com"})
test.AssertNotError(t, err, "creating transactions")
test.AssertEquals(t, len(txns), 1)
test.AssertEquals(t, txns[0].bucketKey, "6:13371338:example.com")
test.Assert(t, txns[0].checkOnly(), "should be check-only")
test.Assert(t, txns[0].limit.isOverride(), "should be an override")

// Same as above, but with multiple example.com domains.
txns, err = tb.certificatesPerDomainCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com", "z.example.com"})
test.AssertNotError(t, err, "creating transactions")
test.AssertEquals(t, len(txns), 1)
test.AssertEquals(t, txns[0].bucketKey, "6:13371338:example.com")
test.Assert(t, txns[0].checkOnly(), "should be check-only")
test.Assert(t, txns[0].limit.isOverride(), "should be an override")

// Same as above, but with different domains.
txns, err = tb.certificatesPerDomainCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com", "z.example.net"})
test.AssertNotError(t, err, "creating transactions")
txns = sortTransactions(txns)
test.AssertEquals(t, len(txns), 2)
test.AssertEquals(t, txns[0].bucketKey, "6:13371338:example.com")
test.Assert(t, txns[0].checkOnly(), "should be check-only")
test.Assert(t, txns[0].limit.isOverride(), "should be an override")
test.AssertEquals(t, txns[1].bucketKey, "6:13371338:example.net")
test.Assert(t, txns[1].checkOnly(), "should be check-only")
test.Assert(t, txns[1].limit.isOverride(), "should be an override")

// Two spend-only transactions, one for the global limit and one for the
// per-account limit override.
txns, err = tb.CertificatesPerDomainSpendOnlyTransactions(13371338, []string{"so.many.labels.here.example.com"})
test.AssertNotError(t, err, "creating TransactionBuilder")
test.AssertEquals(t, len(txns), 2)
txns = sortTransactions(txns)
test.AssertEquals(t, txns[0].bucketKey, "5:example.com")
test.Assert(t, txns[0].spendOnly(), "should be spend-only")
test.Assert(t, !txns[0].limit.isOverride(), "should not be an override")

test.AssertEquals(t, txns[1].bucketKey, "6:13371338:example.com")
test.Assert(t, txns[1].spendOnly(), "should be spend-only")
test.Assert(t, txns[1].limit.isOverride(), "should be an override")
}

func TestCertificatesPerFQDNSetTransactions(t *testing.T) {
t.Parallel()

tb, err := NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "")
test.AssertNotError(t, err, "creating TransactionBuilder")

// A single check-only transaction for the global limit.
txn, err := tb.certificatesPerFQDNSetCheckOnlyTransaction([]string{"example.com", "example.net", "example.org"})
test.AssertNotError(t, err, "creating transaction")
namesHash := fmt.Sprintf("%x", core.HashNames([]string{"example.com", "example.net", "example.org"}))
test.AssertEquals(t, txn.bucketKey, "7:"+namesHash)
test.Assert(t, txn.checkOnly(), "should be check-only")
test.Assert(t, !txn.limit.isOverride(), "should not be an override")
}
14 changes: 14 additions & 0 deletions ratelimits/testdata/working_override_13371338.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
- CertificatesPerDomainPerAccount:
burst: 1337
count: 1337
period: 2160h
ids:
- id: 13371338
comment: Used to test the TransactionBuilder
- FailedAuthorizationsPerDomainPerAccount:
burst: 1337
count: 1337
period: 5m
ids:
- id: 13371338
comment: Used to test the TransactionBuilder

0 comments on commit c5dae06

Please sign in to comment.