Files
wehub-resource-sync e0e362d700
SDK Tests / changes (push) Successful in 2m29s
Real E2E Tests / changes (push) Successful in 2m29s
Deploy Docs Pages / build (push) Has been cancelled
Deploy Docs Pages / deploy (push) Has been cancelled
Real E2E Tests / JavaScript E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Python E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Java E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / C# E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Go E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Real E2E CI (push) Has been cancelled
SDK Tests / SDK CI (push) Has been cancelled
SDK Tests / CLI Tests (push) Has been cancelled
SDK Tests / Python SDK Quality (code-interpreter) (push) Has been cancelled
SDK Tests / Python SDK Quality (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (sandbox) (push) Has been cancelled
SDK Tests / CLI Quality (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Go SDK Quality And Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:39:33 +08:00

129 lines
3.9 KiB
Go

// Copyright 2026 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package supervisor
import (
"testing"
"time"
)
// fixedRNG returns a constant value to make jitter deterministic.
func fixedRNG(v float64) func() float64 { return func() float64 { return v } }
func TestNextBackoff_NoJitterDoublesAndClamps(t *testing.T) {
min := 1 * time.Second
max := 8 * time.Second
noJitter := fixedRNG(0.5) // would be zero delta anyway with jitter=0
cases := []struct {
prev time.Duration
want time.Duration
}{
{0, min}, // initial
{-1 * time.Second, min}, // negative
{500 * time.Millisecond, min}, // below min after doubling -> clamp up
{1 * time.Second, 2 * time.Second},
{2 * time.Second, 4 * time.Second},
{4 * time.Second, 8 * time.Second},
{8 * time.Second, max}, // would be 16s -> clamp to max
{100 * time.Second, max},
}
for _, c := range cases {
got := nextBackoff(c.prev, min, max, 0, noJitter)
if got != c.want {
t.Errorf("nextBackoff(prev=%s) = %s, want %s", c.prev, got, c.want)
}
}
}
func TestNextBackoff_JitterWithinBounds(t *testing.T) {
min := 1 * time.Second
max := 10 * time.Second
jitter := 0.5
// rng=0 -> delta = -1 * 0.5 * d = -50%
// rng=0.5 -> delta = 0
// rng=1- -> delta ≈ +50%
// Approximate by checking the two extremes plus the midpoint.
for _, v := range []float64{0.0, 0.5, 0.9999} {
got := nextBackoff(2*time.Second, min, max, jitter, fixedRNG(v))
// Base after doubling = 4s. jitter range ±2s. So [2s, 6s].
if got < 2*time.Second || got > 6*time.Second {
t.Errorf("rng=%v: got %s, want in [2s, 6s]", v, got)
}
}
}
func TestNextBackoff_JitterClampsToMax(t *testing.T) {
min := 1 * time.Second
max := 5 * time.Second
// Base = max after doubling. Positive jitter must not push above max.
got := nextBackoff(max, min, max, 0.5, fixedRNG(0.9999))
if got > max {
t.Errorf("got %s > max %s", got, max)
}
}
func TestNextBackoff_JitterClampsToMin(t *testing.T) {
min := 2 * time.Second
max := 10 * time.Second
// Base = min. Negative jitter must not push below min.
got := nextBackoff(0, min, max, 0.5, fixedRNG(0.0))
if got < min {
t.Errorf("got %s < min %s", got, min)
}
}
// Spec.BackoffJitter is *float64 specifically so callers can pass &zero to
// disable jitter; verify the underlying nextBackoff respects jitter=0.
func TestNextBackoff_JitterZeroDisablesJitter(t *testing.T) {
min := 1 * time.Second
max := 16 * time.Second
// With jitter=0, output must be the exact doubled value regardless of rng.
for _, rng := range []float64{0.0, 0.5, 0.9999} {
got := nextBackoff(2*time.Second, min, max, 0, fixedRNG(rng))
if got != 4*time.Second {
t.Errorf("rng=%v: got %s, want exactly 4s", rng, got)
}
}
}
func TestApplyDefaults_BackoffJitter(t *testing.T) {
cases := []struct {
name string
in *float64
want float64
}{
{"nil applies default", nil, defaultBackoffJitter},
{"zero stays zero", floatPtr(0), 0},
{"explicit value preserved", floatPtr(0.25), 0.25},
{"negative clamped to zero", floatPtr(-0.5), 0},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
s := Spec{Cmd: "/bin/true", BackoffJitter: c.in}
s.applyDefaults()
if s.BackoffJitter == nil {
t.Fatal("BackoffJitter still nil after applyDefaults")
}
if *s.BackoffJitter != c.want {
t.Errorf("BackoffJitter = %v, want %v", *s.BackoffJitter, c.want)
}
})
}
}
func floatPtr(v float64) *float64 { return &v }