Files
omarchy/plugins/io.github.x3me.nexthop/test/test_score.py
T
asepharyana 1cdb82a76f Sync config from arch
- hypr/apps.lua
- hypr/autostart.lua
- hypr/envs.lua
- hypr/hyprland.lua
- hypr/hyprsunset.conf
- hypr/input.lua
- hypr/looknfeel.lua
- hypr/omasettings.lua
- hypr/xdph.conf
- omarchy/branding/about.txt
- omarchy/branding/screensaver.txt
- omarchy/extensions/omarchy-menu.jsonc
- omarchy/hooks/battery-low.d/play-warning-sound.sample
- omarchy/hooks/font-set.d/show-font-notification.sample
- omarchy/hooks/post-boot.d/weather.sample
- omarchy/hooks/post-update.d/install-voxtype.hook
- omarchy/hooks/post-update.d/setup-agent.hook
- omarchy/hooks/post-update.d/setup-fingerprint.hook
- omarchy/hooks/post-update.d/show-update-notification.sample
- omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample
- omarchy/hooks/theme-set.d/show-theme-notification.sample
- omarchy/shell.json
- omarchy/shell.toml
- omarchy/theme.name
- omarchy/themes/azure-glow/README.md
- omarchy/themes/azure-glow/alacritty.toml
- omarchy/themes/azure-glow/btop.theme
- omarchy/themes/azure-glow/hyprland.conf
- omarchy/themes/azure-glow/hyprlock.conf
- omarchy/themes/azure-glow/icons.theme
- … 269 more
2026-09-23 15:19:12 +07:00

532 lines
24 KiB
Python

"""Tests for score.py — the anchor tables, the folds, and the wrong-direction sweep.
Run: python3 -m unittest discover -s test
"""
import sys
import tempfile
import time
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from nexthopd import score # noqa: E402
class Scoring(unittest.TestCase):
def test_lag_charges_for_loss(self):
clean = {"count": 100, "loss": 0.0, "p75": 10.0, "jitter": 1.0}
lossy = {"count": 100, "loss": 0.02, "p75": 10.0, "jitter": 1.0}
self.assertGreater(score.lag_ms(lossy), score.lag_ms(clean) + 15)
def test_score_bands(self):
self.assertEqual(score.band(94), "excellent")
self.assertEqual(score.band(85), "good")
self.assertEqual(score.band(74), "okay")
self.assertEqual(score.band(55), "fair")
self.assertEqual(score.band(10), "poor")
self.assertEqual(score.band(None), "unknown")
def test_index_skips_unknown_components(self):
# Weakest-link: 90 owns the number, 100 nudges it up slightly.
self.assertEqual(score.index(90.0, 100.0, None), 91)
self.assertIsNone(score.index(None, None, None))
# A single measurable component is that component.
self.assertEqual(score.index(None, 73.0, None), 73)
def test_index_does_not_let_good_components_mask_a_broken_one(self):
# A line whose calls do not work, with a fast download and no
# outages. The mean called this 78 ("okay"); the bottleneck is 40.
idx = score.index(40.0, 100.0, 95.0)
self.assertLess(idx, 50)
self.assertEqual(score.band(idx), "poor")
def test_index_still_rewards_an_otherwise_excellent_connection(self):
# All three healthy: the number stays where the components are.
self.assertGreaterEqual(score.index(96.0, 100.0, 94.0), 94)
def test_index_ties_do_not_lose_a_component(self):
self.assertEqual(score.index(70.0, 70.0, 70.0), 70)
def test_loss_costs_the_same_as_before_on_an_ordinary_link(self):
# The flat 1000 ms/unit-loss was right for normal round trips, so
# nothing changes for them — only the shape above the RTO floor.
for p75 in (5.0, 15.0, 40.0, 66.0):
self.assertEqual(score.loss_cost_ms(p75), 1000.0)
def test_loss_costs_more_on_a_high_latency_link(self):
# A retransmit on a 600 ms link is not the same 10 ms per percent
# that it is on fibre.
self.assertGreater(score.loss_cost_ms(600.0),
score.loss_cost_ms(15.0) * 5)
fibre = score.lag_ms({"count": 100, "p75": 15.0, "jitter": 3.0,
"loss": 0.01})
sat = score.lag_ms({"count": 100, "p75": 600.0, "jitter": 30.0,
"loss": 0.01})
self.assertAlmostEqual(fibre - 19.5, 10.0, places=1) # 10 ms, as before
self.assertAlmostEqual(sat - 645.0, 90.0, places=1) # 90 ms, scaled
def test_loss_cost_never_drops_below_the_rto_floor(self):
self.assertEqual(score.loss_cost_ms(0.0),
score.LOSS_STALL_FACTOR * score.LOSS_RTO_FLOOR_MS)
def test_reliability_charges_outages_harder_than_self_healed_blips(self):
# The inversion this replaced: three brief disruptions used to cost
# 18 points while a ten-minute outage cost 0.7, so the milder event
# was punished twenty-six times harder.
day = 24 * 3600
outage = score.reliability(600 / day, 0)
blips = score.reliability(0.0, 3, disruption_fraction=45 / day)
self.assertLess(outage, blips,
"ten minutes fully down must cost more than three "
"short self-healed blips")
def test_reliability_scales_with_downtime(self):
day = 24 * 3600
self.assertGreater(score.reliability(600 / day, 0),
score.reliability(3600 / day, 0))
self.assertGreater(score.reliability(3600 / day, 0),
score.reliability(6 * 3600 / day, 0))
def test_a_bad_evening_of_blips_cannot_zero_reliability(self):
# Seventeen disruptions used to land on exactly 0.0.
day = 24 * 3600
rel = score.reliability(0.0, 17, disruption_fraction=17 * 30 / day)
self.assertGreater(rel, 90.0) # not a catastrophe
self.assertLess(rel, 100.0) # but not free either
def test_repeated_blips_still_cost_more_than_one(self):
day = 24 * 3600
one = score.reliability(0.0, 1, disruption_fraction=300 / day)
many = score.reliability(0.0, 10, disruption_fraction=300 / day)
self.assertLess(many, one)
def test_total_downtime_floors_at_zero(self):
self.assertEqual(score.reliability(1.0, 0), 0.0)
def test_uncovered_window_is_not_punished(self):
self.assertEqual(score.reliability(0.0, 5, covered=False), 100.0)
def test_wan_subtraction_monotone(self):
w = score.wan_from(
{"count": 60, "loss": 0.0, "p50": 11.5, "p75": 15.5, "p95": 22.5,
"max": 25.2, "jitter": 4.9, "last": 8.0},
{"count": 60, "loss": 0.0, "p50": 8.6, "p75": 9.8, "p95": 19.8,
"max": 21.2, "jitter": 4.2, "last": 7.8})
self.assertLessEqual(w["p50"], w["p75"])
self.assertLessEqual(w["p75"], w["p95"])
self.assertLessEqual(w["p95"], w["max"])
def test_wan_loss_never_negative(self):
w = score.wan_from({"count": 10, "loss": 0.0, "p50": 5.0},
{"count": 10, "loss": 0.1, "p50": 2.0})
self.assertEqual(w["loss"], 0.0)
def test_speed_prefers_download(self):
# Full download, empty upload should still score well above 50.
self.assertGreater(score.speed(450, 0.1, 450, 50), 70)
def test_speed_absolute_needs_no_config(self):
# The default basis scores without a plan and saturates sensibly.
self.assertIsNotNone(score.speed(230, 100))
self.assertGreater(score.speed(230, 100), 90)
self.assertLess(score.speed(10, 2), 40)
# Past the perception ceiling extra speed barely moves the score.
self.assertLess(score.speed(900, 200) - score.speed(500, 100), 3)
def test_degradation_penalty_only_on_big_drops(self):
# Ordinary shared-line variance is free; a real drop is not.
self.assertEqual(score.degradation_penalty(200, 300), 0.0)
self.assertGreater(score.degradation_penalty(60, 300), 15)
# No baseline, no penalty — cold start stays honest.
self.assertEqual(score.degradation_penalty(60, None), 0.0)
def test_plan_overrides_absolute(self):
# A configured plan switches the basis entirely.
with_plan = score.speed(412, 48, 450, 50)
without = score.speed(412, 48)
self.assertNotEqual(with_plan, without)
class SpeedScoring(unittest.TestCase):
"""Daemon.speed_score against a real store, no probes started."""
def setUp(self):
import os as _os
from nexthopd.daemon import Daemon
self.dir = tempfile.TemporaryDirectory()
_os.environ["XDG_STATE_HOME"] = self.dir.name
self.daemon = Daemon()
self._os = _os
def tearDown(self):
self.daemon.store.close()
del self._os.environ["XDG_STATE_HOME"]
self.dir.cleanup()
def put(self, ago_s, down, up, network):
self.daemon.store.put_test(int(time.time() - ago_s), "content",
"cloudflare", down_mbps=down, up_mbps=up,
ok=True, network=network)
def test_other_networks_checks_do_not_score_here(self):
self.put(600, 300, 100, "OfficeA")
spd, ctx = self.daemon.speed_score(time.time(), "OfficeB")
self.assertIsNone(spd)
self.assertTrue(ctx.get("pending"))
def test_median_shrugs_off_one_bad_check(self):
self.put(7200, 220, 90, "OfficeA")
self.put(3600, 240, 95, "OfficeA")
self.put(600, 18, 5, "OfficeA") # the mid-roam outlier
spd, ctx = self.daemon.speed_score(time.time(), "OfficeA")
self.assertEqual(ctx["last_down"], 220) # median, not the outlier
self.assertGreater(spd, 85)
def test_no_cross_network_penalty(self):
# A fast history elsewhere must not depress a slower network.
for i in range(6):
self.put(3600 * (i + 2), 300, 100, "FastOffice")
self.put(600, 30, 10, "SlowCafe")
spd, ctx = self.daemon.speed_score(time.time(), "SlowCafe")
self.assertIsNone(ctx["baseline_down"])
# Pure absolute curve for 30/10: mid-50s to 60 — no minus-35 cliff.
self.assertGreater(spd, 50)
class UnknownWanLeg(unittest.TestCase):
def test_missing_local_yields_unknown_not_the_whole_round_trip(self):
total = {"count": 500, "p50": 3.5, "p75": 4.0, "p95": 18.0,
"max": 26.0, "loss": 0.0, "jitter": 4.8, "last": 3.5}
gone = {"count": 0, "p50": None, "p75": None, "p95": None,
"max": None, "loss": 1.0, "jitter": None, "last": None}
w = score.wan_from(total, gone)
# Substituting zero used to make the derived leg equal the total, so
# a silent gateway produced a confident healthy internet figure that
# was really the whole round trip wearing the wan leg's label.
for key in ("p50", "p75", "p95", "max"):
self.assertIsNone(w[key], key)
def test_known_local_still_subtracts(self):
total = {"count": 500, "p50": 10.0, "p75": 12.0, "p95": 20.0,
"max": 30.0, "loss": 0.0, "jitter": 1.0, "last": 10.0}
local = {"count": 500, "p50": 2.0, "p75": 2.5, "p95": 5.0,
"max": 8.0, "loss": 0.0, "jitter": 0.4, "last": 2.0}
w = score.wan_from(total, local)
self.assertEqual(w["p50"], 8.0)
self.assertGreaterEqual(w["p95"], w["p50"])
class LagBand(unittest.TestCase):
def test_one_scale_so_the_range_cannot_read_backwards(self):
# The reported case: "best 4 · typical 644 ms · worst 26" — two raw
# round trips either side of a loss-charged composite.
lossy = {"count": 500, "p50": 3.5, "p75": 4.0, "p95": 18.0,
"max": 26.0, "loss": 1.0, "jitter": 4.8}
b = score.lag_band(lossy)
self.assertLessEqual(b["best"], b["typical"])
self.assertLessEqual(b["typical"], b["worst"])
# Loss moves all three together, which is what a range implies.
self.assertGreater(b["best"], 1000)
def test_monotonic_across_loss_levels_and_degenerate_windows(self):
base = {"count": 500, "p50": 5.0, "p75": 5.0, "p95": 5.0,
"max": 5.0, "jitter": 0.0}
for loss in (0.0, 0.01, 0.35, 1.0):
b = score.lag_band(dict(base, loss=loss))
vals = [b["best"], b["typical"], b["worst"]]
self.assertEqual(vals, sorted(vals), loss)
def test_no_samples_reports_nothing(self):
b = score.lag_band({"count": 0})
self.assertEqual(b, {"best": None, "typical": None, "worst": None})
class OutagePresentation(unittest.TestCase):
"""What the panel may say when nothing is replying."""
DEAD = {"count": 60, "p50": None, "p75": None, "p95": None,
"max": None, "loss": 1.0, "jitter": None}
def test_scoring_keeps_its_anchor(self):
# Responsiveness must still land on zero, which is what 1500 is for.
self.assertEqual(score.lag_ms(self.DEAD), 1500.0)
self.assertEqual(score.responsiveness(score.lag_ms(self.DEAD)), 0.0)
def test_display_band_shows_nothing_rather_than_the_anchor(self):
# 1500 is an anchor, not a round trip. The panel printed it three
# times as "best 1500 · typical 1500 ms · worst 1500", which says
# the link is replying slowly when it is not replying.
self.assertEqual(score.lag_band(self.DEAD),
{"best": None, "typical": None, "worst": None})
def test_partial_loss_still_reports_a_band(self):
lossy = {"count": 500, "p50": 5.0, "p75": 6.0, "p95": 20.0,
"max": 30.0, "loss": 0.4, "jitter": 1.0}
b = score.lag_band(lossy)
self.assertIsNotNone(b["typical"])
self.assertLessEqual(b["best"], b["typical"])
self.assertLessEqual(b["typical"], b["worst"])
class DrainAfterLoad(unittest.TestCase):
"""Depth is what everyone reports; duration is what you feel after the
download has finished."""
def test_measures_from_the_last_loaded_sample(self):
sm = [(1, 10, False), (2, 10, False), (3, 60, True), (4, 80, True),
(5, 70, True), (5.4, 40, False), (6.2, 12, False),
(7, 10, False)]
d = score.drain_after_load(sm, 10.0)
# Load ended at t=5; latency was back inside tolerance at t=6.2.
self.assertEqual(d["ms"], 1200.0)
self.assertTrue(d["settled"])
def test_tolerance_not_exactness(self):
# A queue does not empty to the exact millisecond it started from.
sm = [(1, 10, True), (2, 12.4, False)]
self.assertTrue(score.drain_after_load(sm, 10.0)["settled"])
sm = [(1, 10, True), (2, 20.0, False)]
self.assertFalse(score.drain_after_load(sm, 10.0)["settled"])
def test_still_under_load_says_nothing(self):
sm = [(1, 10, False), (2, 80, True)]
self.assertIsNone(score.drain_after_load(sm, 10.0)["ms"])
def test_no_burst_says_nothing(self):
sm = [(1, 10, False), (2, 11, False)]
self.assertIsNone(score.drain_after_load(sm, 10.0)["ms"])
def test_unrecovered_reports_a_floor_not_a_recovery(self):
sm = [(1, 10, True), (2, 90, False), (3, 88, False), (4, 86, False)]
d = score.drain_after_load(sm, 10.0)
self.assertEqual(d["ms"], 3000.0)
self.assertFalse(d["settled"]) # never came back
def test_beyond_the_cap_is_not_a_drain(self):
sm = [(0, 10, True), (score.DRAIN_MAX_S + 5, 10, False)]
self.assertIsNone(score.drain_after_load(sm, 10.0)["ms"])
def test_lost_probes_are_skipped_not_treated_as_recovery(self):
sm = [(1, 90, True), (2, None, False), (3, None, False),
(4, 11, False)]
d = score.drain_after_load(sm, 10.0)
self.assertEqual(d["ms"], 3000.0)
self.assertTrue(d["settled"])
def test_no_baseline_no_claim(self):
sm = [(1, 90, True), (2, 10, False)]
self.assertIsNone(score.drain_after_load(sm, None)["ms"])
self.assertIsNone(score.drain_after_load(sm, 0)["ms"])
class Pressure(unittest.TestCase):
"""The fast channel the index cannot be."""
def test_bands(self):
self.assertEqual(score.pressure(socket_queue_ms=5.1)["state"], "clear")
self.assertEqual(score.pressure(socket_queue_ms=18.4)["state"], "busy")
self.assertEqual(score.pressure(socket_queue_ms=64.0)["state"],
"congested")
def test_real_traffic_beats_an_inference_from_probes(self):
p = score.pressure(socket_queue_ms=3.0, loaded_ms=99.0, idle_ms=10.0)
self.assertEqual(p["source"], "sockets")
self.assertEqual(p["queue_ms"], 3.0)
def test_probes_are_the_fallback(self):
p = score.pressure(loaded_ms=48.0, idle_ms=12.0)
self.assertEqual(p["source"], "probes")
self.assertEqual(p["queue_ms"], 36.0)
def test_a_backwards_difference_is_withheld(self):
# Queueing cannot be negative; that means the split is unreliable,
# not that load made the link quicker. Same rule as the inflation
# plausibility floor.
self.assertIsNone(score.pressure(loaded_ms=10.0, idle_ms=12.0)["state"])
def test_nothing_to_say_is_a_valid_answer(self):
self.assertIsNone(score.pressure()["state"])
self.assertIsNone(score.pressure(loaded_ms=50.0)["state"])
class WrongDirectionSweep(unittest.TestCase):
"""A result wrong in DIRECTION is not a result.
Four instances turned up one at a time this session — the loaded/idle
ratio at 0.87, the 1500 ms scoring anchor printed as a latency, the
internet leg substituting zero for an unknown local leg, and a peak test
graded A+ for measuring lower latency under load than at rest. This
class pins the class rather than the instances, so a fifth cannot be
introduced quietly.
"""
TOTAL = {"count": 500, "p50": 8.1, "p75": 10.4, "p95": 14.4,
"max": 26.0, "loss": 0.0, "jitter": 2.3, "last": 8.0}
def test_a_slower_router_than_internet_withholds_the_isp_leg(self):
# Gateways commonly deprioritise ICMP addressed to themselves, so
# their own replies are slow while everything they forward is fast.
# That is a fact about the control plane, not the ISP's share.
slow_gateway = {"count": 500, "p50": 20.0, "p75": 25.0, "p95": 40.0,
"max": 60.0, "loss": 0.0, "jitter": 3.0, "last": 20.0}
w = score.wan_from(self.TOTAL, slow_gateway)
for key in ("p50", "p75", "p95", "max", "last"):
self.assertIsNone(w[key], key)
def test_a_genuinely_near_zero_isp_leg_is_still_reported(self):
# An anchor a hop past the gateway really can cost almost nothing;
# withholding that would be its own kind of dishonesty.
near = dict(self.TOTAL, p50=8.4, p75=10.6, p95=14.6, max=26.2)
w = score.wan_from(self.TOTAL, near)
self.assertEqual(w["p50"], 0.0)
def test_normal_subtraction_untouched(self):
local = {"count": 500, "p50": 2.1, "p75": 2.5, "p95": 5.0,
"max": 8.0, "loss": 0.0, "jitter": 0.4, "last": 2.0}
w = score.wan_from(self.TOTAL, local)
self.assertEqual(w["p50"], 6.0)
self.assertEqual(w["last"], 6.0)
def test_loss_subtraction_stays_clamped_and_that_is_correct(self):
# Unlike latency, this one is legitimate: loss on the local link
# shows up in both probes, so if the internet probe lost nothing the
# wan leg genuinely lost nothing, however much the router probe lost.
lossy_local = dict(self.TOTAL, loss=0.3)
w = score.wan_from(dict(self.TOTAL, loss=0.0), lossy_local)
self.assertEqual(w["loss"], 0.0)
def test_the_signed_difference_stays_signed(self):
# icmp_delta_ms is MEANT to go both ways: our own measurements show
# ICMP optimistic at the median and pessimistic in the tail, so a
# negative delta is a finding, not an error. Guarding it would
# destroy the comparison it exists for.
self.assertLess(score.lag_ms(dict(self.TOTAL, p75=4.0)),
score.lag_ms(dict(self.TOTAL, p75=40.0)))
class SpeedTrust(unittest.TestCase):
"""Weakest-link means the lowest component is the headline, so the
thinnest input must not hold a veto over it."""
def test_one_sample_is_not_enough(self):
self.assertFalse(score.speed_scored(63.4, 1))
self.assertTrue(score.speed_scored(63.4, 2))
def test_a_contradicting_peak_withdraws_the_figure(self):
# 251 Mbps measured by hand on the same line disproves 63.
self.assertFalse(score.speed_scored(63.4, 3, 251.4))
# Within the same order of magnitude it stands: a saturating test
# reading somewhat higher than an everyday sample is normal.
self.assertTrue(score.speed_scored(200.0, 3, 251.4))
def test_nothing_measured_is_never_scored(self):
self.assertFalse(score.speed_scored(None, 9))
def test_the_index_leaves_an_untrusted_figure_out(self):
# The reported case: a healthy line read POOR because one check
# pinned the headline.
pinned = score.index(97.3, 97.0, 42.4)
honest = score.index(97.3, 97.0, None)
self.assertLess(pinned, 50)
self.assertGreater(honest, 90)
class HeadlineDuringAnOutage(unittest.TestCase):
"""The index must not contradict the verdict printed beside it.
Observed 2026-09-08 on a real 61 s Wi-Fi drop: EXPERIENCE 100 directly
beneath ROUTER UNREACHABLE, because Lag's 30 s window still held
pre-outage replies and 61 s against 24 h rounds Reliability to 100.
"""
def test_a_confirmed_outage_withholds_the_headline(self):
for state in ("local-down", "wan-down"):
self.assertFalse(score.scored_now(state), state)
def test_ordinary_states_keep_it(self):
for state in ("online", "degraded", "captive"):
self.assertTrue(score.scored_now(state), state)
def test_a_quiet_spell_is_not_an_outage(self):
# gateway-quiet and icmp-quiet leave the state calm on purpose:
# traffic still crosses the leg, so the index still means something.
self.assertTrue(score.scored_now("online"))
def test_the_components_that_produced_it_still_stand(self):
# Only the headline is withheld. Reliability really is 100 over the
# window, and its pillar says so in amber with the live downtime.
self.assertEqual(score.index(100.0, 100.0, None), 100)
self.assertFalse(score.scored_now("local-down"))
def test_withholding_is_a_band_of_unknown_not_of_poor(self):
# A withheld index must not colour as a bad one. band(None) is the
# same "unknown" every other absent figure uses.
self.assertEqual(score.band(None), "unknown")
class WanPerPoint(unittest.TestCase):
"""One pair of readings to one ISP-leg figure.
Factored out of `wan_from` so the per-point series in recent.json and the
per-window statistics cannot drift: the rule that matters here is the one
that REFUSES to answer, and a second copy of it is a copy that can forget.
"""
def test_it_subtracts_the_router_share(self):
self.assertEqual(score.wan_point_ms(11.13, 3.92), 7.21)
def test_a_gateway_slower_than_the_internet_says_nothing(self):
# Plenty of routers deprioritise ICMP addressed to themselves, so the
# local leg reads slower than the total that crosses it. The
# subtraction has nothing to say about the line; a clamped zero would
# report a perfect ISP leg from an invalid measurement.
self.assertIsNone(score.wan_point_ms(5.0, 9.0))
def test_inside_the_tolerance_it_still_answers(self):
# A hair over is measurement noise, not an inversion.
self.assertEqual(score.wan_point_ms(5.0, 5.5), 0.0)
self.assertIsNone(
score.wan_point_ms(5.0, 5.0 + score.WAN_INVERSION_TOLERANCE_MS + 0.01))
def test_either_reading_missing_is_unknown_not_zero(self):
self.assertIsNone(score.wan_point_ms(5.0, None))
self.assertIsNone(score.wan_point_ms(None, 2.0))
self.assertIsNone(score.wan_point_ms(None, None))
def test_the_per_point_rule_refuses_exactly_when_wan_from_does(self):
"""The two must never disagree about WHAT THEY REFUSE.
Raised by the HopSense session 2026-09-12: their Go port is pinned to
`wan_from` by golden vectors, and a per-point refusal is a surface
those vectors do not cover. They cannot diverge today because
`wan_from` calls this helper — this pins that they still cannot after
someone inlines it back for speed.
"""
cases = [(10.0, 2.0), (10.0, 10.0), (10.0, 10.5), (10.0, 11.5),
(10.0, 30.0), (0.5, 0.4), (None, 2.0), (10.0, None),
(None, None), (0.0, 0.0)]
for total, local in cases:
point = score.wan_point_ms(total, local)
window = score.wan_from({"p50": total, "count": 9}, {"p50": local})
self.assertEqual(
point is None, window["p50"] is None,
"disagreed on total=%s local=%s: point=%s window=%s"
% (total, local, point, window["p50"]))
def test_wan_from_still_floors_each_statistic_at_the_last(self):
# The helper is unfloored by design; `wan_from` carries the floor
# forward FLOORED, which is what keeps a derived leg reading like a
# distribution. Extracting the arithmetic broke this once.
w = score.wan_from(
{"p50": 10.0, "p75": 12.0, "p95": 13.0, "max": 13.5, "count": 9},
{"p50": 1.0, "p75": 1.0, "p95": 8.0, "max": 12.0})
self.assertLessEqual(w["p50"], w["p75"])
self.assertLessEqual(w["p75"], w["p95"])
self.assertLessEqual(w["p95"], w["max"])
if __name__ == "__main__":
unittest.main()