diff --git a/score_params.go b/score_params.go index e70d3c84fff0ea0d0c760af0273fb88fcb8ce8b9..2355c502b62fe93ddb224022ace5fd51e8c6a5d7 100644 --- a/score_params.go +++ b/score_params.go @@ -199,47 +199,47 @@ func (p *PeerScoreParams) validate() error { func (p *TopicScoreParams) validate() error { // make sure we have a sane topic weight - if p.TopicWeight < 0 { - return fmt.Errorf("invalid topic weight; must be >= 0") + if p.TopicWeight < 0 || isInvalidNumber(p.TopicWeight) { + return fmt.Errorf("invalid topic weight; must be >= 0 and a valid number") } // check P1 if p.TimeInMeshQuantum == 0 { return fmt.Errorf("invalid TimeInMeshQuantum; must be non zero") } - if p.TimeInMeshWeight < 0 { - return fmt.Errorf("invalid TimeInMeshWeight; must be positive (or 0 to disable)") + if p.TimeInMeshWeight < 0 || isInvalidNumber(p.TimeInMeshWeight) { + return fmt.Errorf("invalid TimeInMeshWeight; must be positive (or 0 to disable) and a valid number") } if p.TimeInMeshWeight != 0 && p.TimeInMeshQuantum <= 0 { return fmt.Errorf("invalid TimeInMeshQuantum; must be positive") } - if p.TimeInMeshWeight != 0 && p.TimeInMeshCap <= 0 { - return fmt.Errorf("invalid TimeInMeshCap; must be positive") + if p.TimeInMeshWeight != 0 && (p.TimeInMeshCap <= 0 || isInvalidNumber(p.TimeInMeshCap)) { + return fmt.Errorf("invalid TimeInMeshCap; must be positive and a valid number") } // check P2 - if p.FirstMessageDeliveriesWeight < 0 { - return fmt.Errorf("invallid FirstMessageDeliveriesWeight; must be positive (or 0 to disable)") + if p.FirstMessageDeliveriesWeight < 0 || isInvalidNumber(p.FirstMessageDeliveriesWeight) { + return fmt.Errorf("invallid FirstMessageDeliveriesWeight; must be positive (or 0 to disable) and a valid number") } - if p.FirstMessageDeliveriesWeight != 0 && (p.FirstMessageDeliveriesDecay <= 0 || p.FirstMessageDeliveriesDecay >= 1) { + if p.FirstMessageDeliveriesWeight != 0 && (p.FirstMessageDeliveriesDecay <= 0 || p.FirstMessageDeliveriesDecay >= 1 || isInvalidNumber(p.FirstMessageDeliveriesDecay)) { return fmt.Errorf("invalid FirstMessageDeliveriesDecay; must be between 0 and 1") } - if p.FirstMessageDeliveriesWeight != 0 && p.FirstMessageDeliveriesCap <= 0 { - return fmt.Errorf("invalid FirstMessageDeliveriesCap; must be positive") + if p.FirstMessageDeliveriesWeight != 0 && (p.FirstMessageDeliveriesCap <= 0 || isInvalidNumber(p.FirstMessageDeliveriesCap)) { + return fmt.Errorf("invalid FirstMessageDeliveriesCap; must be positive and a valid number") } // check P3 - if p.MeshMessageDeliveriesWeight > 0 { - return fmt.Errorf("invalid MeshMessageDeliveriesWeight; must be negative (or 0 to disable)") + if p.MeshMessageDeliveriesWeight > 0 || isInvalidNumber(p.MeshFailurePenaltyWeight) { + return fmt.Errorf("invalid MeshMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } - if p.MeshMessageDeliveriesWeight != 0 && (p.MeshMessageDeliveriesDecay <= 0 || p.MeshMessageDeliveriesDecay >= 1) { + if p.MeshMessageDeliveriesWeight != 0 && (p.MeshMessageDeliveriesDecay <= 0 || p.MeshMessageDeliveriesDecay >= 1 || isInvalidNumber(p.MeshMessageDeliveriesDecay)) { return fmt.Errorf("invalid MeshMessageDeliveriesDecay; must be between 0 and 1") } - if p.MeshMessageDeliveriesWeight != 0 && p.MeshMessageDeliveriesCap <= 0 { - return fmt.Errorf("invalid MeshMessageDeliveriesCap; must be positive") + if p.MeshMessageDeliveriesWeight != 0 && (p.MeshMessageDeliveriesCap <= 0 || isInvalidNumber(p.MeshMessageDeliveriesCap)) { + return fmt.Errorf("invalid MeshMessageDeliveriesCap; must be positive and a valid number") } - if p.MeshMessageDeliveriesWeight != 0 && p.MeshMessageDeliveriesThreshold <= 0 { - return fmt.Errorf("invalid MeshMessageDeliveriesThreshold; must be positive") + if p.MeshMessageDeliveriesWeight != 0 && (p.MeshMessageDeliveriesThreshold <= 0 || isInvalidNumber(p.MeshMessageDeliveriesThreshold)) { + return fmt.Errorf("invalid MeshMessageDeliveriesThreshold; must be positive and a valid number") } if p.MeshMessageDeliveriesWindow < 0 { return fmt.Errorf("invalid MeshMessageDeliveriesWindow; must be non-negative") @@ -249,18 +249,18 @@ func (p *TopicScoreParams) validate() error { } // check P3b - if p.MeshFailurePenaltyWeight > 0 { - return fmt.Errorf("invalid MeshFailurePenaltyWeight; must be negative (or 0 to disable)") + if p.MeshFailurePenaltyWeight > 0 || isInvalidNumber(p.MeshFailurePenaltyWeight) { + return fmt.Errorf("invalid MeshFailurePenaltyWeight; must be negative (or 0 to disable) and a valid number") } - if p.MeshFailurePenaltyWeight != 0 && (p.MeshFailurePenaltyDecay <= 0 || p.MeshFailurePenaltyDecay >= 1) { + if p.MeshFailurePenaltyWeight != 0 && (isInvalidNumber(p.MeshFailurePenaltyDecay) || p.MeshFailurePenaltyDecay <= 0 || p.MeshFailurePenaltyDecay >= 1) { return fmt.Errorf("invalid MeshFailurePenaltyDecay; must be between 0 and 1") } // check P4 - if p.InvalidMessageDeliveriesWeight > 0 { - return fmt.Errorf("invalid InvalidMessageDeliveriesWeight; must be negative (or 0 to disable)") + if p.InvalidMessageDeliveriesWeight > 0 || isInvalidNumber(p.InvalidMessageDeliveriesWeight) { + return fmt.Errorf("invalid InvalidMessageDeliveriesWeight; must be negative (or 0 to disable) and a valid number") } - if p.InvalidMessageDeliveriesDecay <= 0 || p.InvalidMessageDeliveriesDecay >= 1 { + if p.InvalidMessageDeliveriesDecay <= 0 || p.InvalidMessageDeliveriesDecay >= 1 || isInvalidNumber(p.InvalidMessageDeliveriesDecay) { return fmt.Errorf("invalid InvalidMessageDeliveriesDecay; must be between 0 and 1") } @@ -285,3 +285,9 @@ func ScoreParameterDecayWithBase(decay time.Duration, base time.Duration, decayT ticks := float64(decay / base) return math.Pow(decayToZero, 1/ticks) } + +// checks whether the provided floating-point number is `Not a Number` +// or an infinite number. +func isInvalidNumber(num float64) bool { + return math.IsNaN(num) || math.IsInf(num, 0) +} diff --git a/score_params_test.go b/score_params_test.go index 45018d713a54bf991291cde6161dfb71f1f2b57b..18188fa6c8e9806a76d49861c8f05e8e347ee42d 100644 --- a/score_params_test.go +++ b/score_params_test.go @@ -1,6 +1,7 @@ package pubsub import ( + "math" "testing" "time" @@ -254,6 +255,40 @@ func TestPeerScoreParamsValidation(t *testing.T) { t.Fatal("expected validation failure") } + // Checks the topic parameters for invalid values such as infinite and + // NaN numbers. + if (&PeerScoreParams{ + TopicScoreCap: 1, + AppSpecificScore: appScore, + DecayInterval: time.Second, + DecayToZero: 0.01, + IPColocationFactorWeight: -1, + IPColocationFactorThreshold: 1, + Topics: map[string]*TopicScoreParams{ + "test": &TopicScoreParams{ + TopicWeight: math.Inf(0), + TimeInMeshWeight: math.NaN(), + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 10, + FirstMessageDeliveriesWeight: math.Inf(1), + FirstMessageDeliveriesDecay: 0.5, + FirstMessageDeliveriesCap: 10, + MeshMessageDeliveriesWeight: math.Inf(-1), + MeshMessageDeliveriesDecay: math.NaN(), + MeshMessageDeliveriesCap: math.Inf(0), + MeshMessageDeliveriesThreshold: 5, + MeshMessageDeliveriesWindow: time.Millisecond, + MeshMessageDeliveriesActivation: time.Second, + MeshFailurePenaltyWeight: -1, + MeshFailurePenaltyDecay: math.NaN(), + InvalidMessageDeliveriesWeight: math.Inf(0), + InvalidMessageDeliveriesDecay: math.NaN(), + }, + }, + }).validate() == nil { + t.Fatal("expected validation failure") + } + } func TestScoreParameterDecay(t *testing.T) {