mirror of
https://github.com/Horizontal42/netsleuth.git
synced 2026-11-10 15:42:10 +03:00
rename package netcheck to netsleuth (name taken on pypi)
This commit is contained in:
parent
0336be4080
commit
483989c1bc
45 changed files with 163 additions and 163 deletions
|
|
@ -1,11 +1,11 @@
|
|||
[project]
|
||||
name = "netcheck"
|
||||
name = "netsleuth"
|
||||
version = "0.1.0"
|
||||
description = "Cross-platform CLI for deep network diagnostics: ISP/VPN/ASN identity, latency, path and bandwidth"
|
||||
readme = "README.md"
|
||||
license = "PolyForm-Noncommercial-1.0.0"
|
||||
requires-python = ">=3.10"
|
||||
authors = [{ name = "netcheck contributors" }]
|
||||
authors = [{ name = "netsleuth contributors" }]
|
||||
keywords = ["network", "diagnostics", "traceroute", "bgp", "vpn", "speedtest"]
|
||||
dependencies = [
|
||||
"typer>=0.12",
|
||||
|
|
@ -24,7 +24,7 @@ tcptrace = ["scapy>=2.5"]
|
|||
ndt7 = ["websockets>=12"]
|
||||
|
||||
[project.scripts]
|
||||
netcheck = "netcheck.cli:main"
|
||||
netsleuth = "netsleuth.cli:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
|
|
@ -38,9 +38,9 @@ requires = ["hatchling"]
|
|||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/netcheck"]
|
||||
packages = ["src/netsleuth"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
asyncio_mode = "auto"
|
||||
filterwarnings = ["error::DeprecationWarning:netcheck.*"]
|
||||
filterwarnings = ["error::DeprecationWarning:netsleuth.*"]
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ colorama==0.4.6 ; sys_platform == 'win32'
|
|||
# pytest
|
||||
# typer
|
||||
dnspython==2.8.0
|
||||
# via netcheck
|
||||
# via netsleuth
|
||||
exceptiongroup==1.3.1 ; python_full_version < '3.11'
|
||||
# via
|
||||
# anyio
|
||||
|
|
@ -33,12 +33,12 @@ httpcore==1.0.9
|
|||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via
|
||||
# netcheck
|
||||
# netsleuth
|
||||
# pytest-httpx
|
||||
hyperframe==6.1.0
|
||||
# via h2
|
||||
icmplib==3.0.4
|
||||
# via netcheck
|
||||
# via netsleuth
|
||||
idna==3.18
|
||||
# via
|
||||
# anyio
|
||||
|
|
@ -54,15 +54,15 @@ packaging==26.3
|
|||
pluggy==1.6.0
|
||||
# via pytest
|
||||
psutil==7.2.2
|
||||
# via netcheck
|
||||
# via netsleuth
|
||||
pydantic==2.13.4
|
||||
# via
|
||||
# netcheck
|
||||
# netsleuth
|
||||
# pydantic-settings
|
||||
pydantic-core==2.46.4
|
||||
# via pydantic
|
||||
pydantic-settings==2.15.0
|
||||
# via netcheck
|
||||
# via netsleuth
|
||||
pygments==2.20.0
|
||||
# via
|
||||
# pytest
|
||||
|
|
@ -76,17 +76,17 @@ pytest-httpx==0.36.2
|
|||
python-dotenv==1.2.2
|
||||
# via pydantic-settings
|
||||
pyyaml==6.0.3
|
||||
# via netcheck
|
||||
# via netsleuth
|
||||
rich==15.0.0
|
||||
# via
|
||||
# netcheck
|
||||
# netsleuth
|
||||
# typer
|
||||
shellingham==1.5.4
|
||||
# via typer
|
||||
tomli==2.4.1 ; python_full_version < '3.11'
|
||||
# via pytest
|
||||
typer==0.27.1
|
||||
# via netcheck
|
||||
# via netsleuth
|
||||
typing-extensions==4.16.0
|
||||
# via
|
||||
# anyio
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from netcheck.cli import main
|
||||
from netsleuth.cli import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -5,8 +5,8 @@ from datetime import datetime, timedelta, timezone
|
|||
|
||||
import httpx
|
||||
|
||||
from netcheck.config import Providers
|
||||
from netcheck.models import BgpEvent
|
||||
from netsleuth.config import Providers
|
||||
from netsleuth.models import BgpEvent
|
||||
|
||||
# These calls return the whole routing history of an ASN; on a large ISP that is
|
||||
# tens of megabytes unless the window and row count are pinned.
|
||||
|
|
@ -110,7 +110,7 @@ import time
|
|||
from pathlib import Path
|
||||
from typing import Awaitable, Callable
|
||||
|
||||
from netcheck.models import IxpPresence
|
||||
from netsleuth.models import IxpPresence
|
||||
|
||||
|
||||
def parse_asrank(payload: dict) -> tuple[int | None, int | None, int | None]:
|
||||
|
|
@ -174,7 +174,7 @@ async def cached_json(
|
|||
return payload
|
||||
|
||||
|
||||
from netcheck.models import BgpIntel
|
||||
from netsleuth.models import BgpIntel
|
||||
|
||||
|
||||
def build_bgp_intel(
|
||||
|
|
@ -13,25 +13,25 @@ import httpx
|
|||
import typer
|
||||
from rich.console import Console
|
||||
|
||||
from netcheck import __version__
|
||||
from netcheck.compare import diff_reports, load_report, render_diff
|
||||
from netcheck.config import Settings, load_settings
|
||||
from netcheck.exporter import build_report, egress_asn, render_markdown, report_filename, write_report
|
||||
from netcheck.interpret import (
|
||||
from netsleuth import __version__
|
||||
from netsleuth.compare import diff_reports, load_report, render_diff
|
||||
from netsleuth.config import Settings, load_settings
|
||||
from netsleuth.exporter import build_report, egress_asn, render_markdown, report_filename, write_report
|
||||
from netsleuth.interpret import (
|
||||
assess_vpn,
|
||||
gather_vpn_signals,
|
||||
latency_findings,
|
||||
path_findings,
|
||||
speed_findings,
|
||||
)
|
||||
from netcheck.ip_geo import dual_stack_mismatch, gather_identity
|
||||
from netcheck.models import Finding, IpGeo, LocalNet, ModuleResult, SpeedResult
|
||||
from netcheck.netinfo import collect_local_net, detect_capabilities, is_tunnel_iface
|
||||
from netcheck.orchestration import gather_modules, run_module, utc_now_iso
|
||||
from netcheck.probes.dns_leak import collect_dns_leak
|
||||
from netcheck.probes.latency import ping_fanout, tcp_connect_rtt
|
||||
from netcheck.probes.traceroute import traceroute
|
||||
from netcheck.speed import NDT7_CONSENT_NOTICE
|
||||
from netsleuth.ip_geo import dual_stack_mismatch, gather_identity
|
||||
from netsleuth.models import Finding, IpGeo, LocalNet, ModuleResult, SpeedResult
|
||||
from netsleuth.netinfo import collect_local_net, detect_capabilities, is_tunnel_iface
|
||||
from netsleuth.orchestration import gather_modules, run_module, utc_now_iso
|
||||
from netsleuth.probes.dns_leak import collect_dns_leak
|
||||
from netsleuth.probes.latency import ping_fanout, tcp_connect_rtt
|
||||
from netsleuth.probes.traceroute import traceroute
|
||||
from netsleuth.speed import NDT7_CONSENT_NOTICE
|
||||
|
||||
if sys.platform == "win32":
|
||||
# A legacy console codepage (e.g. cp1251) cannot encode the emoji badges and
|
||||
|
|
@ -150,7 +150,7 @@ async def _identity(client: httpx.AsyncClient, settings: Settings, options: Opti
|
|||
async def _bgp_section(client, settings: Settings, asn: str | None, raw: dict):
|
||||
if not asn:
|
||||
return ModuleResult(name="bgp", status="skipped", warnings=["no ASN was resolved for this target"])
|
||||
from netcheck.bgp import collect_bgp
|
||||
from netsleuth.bgp import collect_bgp
|
||||
|
||||
key = settings.peeringdb_api_key.get_secret_value() if settings.peeringdb_api_key else None
|
||||
intel, payloads = await collect_bgp(
|
||||
|
|
@ -161,7 +161,7 @@ async def _bgp_section(client, settings: Settings, asn: str | None, raw: dict):
|
|||
|
||||
|
||||
async def _reputation_section(client, settings: Settings, options: Options, geo: IpGeo, raw: dict):
|
||||
from netcheck.reputation import (
|
||||
from netsleuth.reputation import (
|
||||
build_reputation,
|
||||
fetch_abuseipdb,
|
||||
fetch_internetdb,
|
||||
|
|
@ -225,7 +225,7 @@ async def _traces(hosts, caps, settings: Settings, cycles: int, options: Options
|
|||
async def _speed_section(client, settings: Settings, options: Options, idle_rtt_ms: float | None):
|
||||
import shutil
|
||||
|
||||
from netcheck.speed import (
|
||||
from netsleuth.speed import (
|
||||
measure_with_bufferbloat,
|
||||
run_speed_cascade,
|
||||
tier_cloudflare,
|
||||
|
|
@ -285,7 +285,7 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, str, str
|
|||
timeout=timeouts.http_seconds,
|
||||
follow_redirects=True,
|
||||
http2=True,
|
||||
headers={"User-Agent": f"netcheck/{__version__}"},
|
||||
headers={"User-Agent": f"netsleuth/{__version__}"},
|
||||
) as client:
|
||||
# Phase 1 — local facts and identity. Blocking: everything below needs the ASN.
|
||||
modules["connection"] = await run_module(
|
||||
|
|
@ -463,12 +463,12 @@ def run(
|
|||
"if it cannot run, the cascade falls through to the normal tiers.[/yellow]"
|
||||
)
|
||||
if watch:
|
||||
from netcheck.watch import run_watch
|
||||
from netsleuth.watch import run_watch
|
||||
|
||||
asyncio.run(run_watch(settings, options))
|
||||
raise typer.Exit(0)
|
||||
|
||||
console.print(f"netcheck {__version__} · {options.mode} mode · {platform.system()}")
|
||||
console.print(f"netsleuth {__version__} · {options.mode} mode · {platform.system()}")
|
||||
report, _markdown, _markdown_ru, json_path, md_path, ru_md_path = asyncio.run(diagnose(settings, options))
|
||||
interpretation = report["interpretation"]
|
||||
console.print(
|
||||
|
|
@ -5,7 +5,7 @@ from dataclasses import dataclass, field
|
|||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from netcheck.exporter import badge
|
||||
from netsleuth.exporter import badge
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
@ -124,7 +124,7 @@ def _block(title: str, changes: list[Change]) -> list[str]:
|
|||
|
||||
|
||||
def render_diff(diff: ReportDiff, emoji: bool = True) -> str:
|
||||
lines = ["# netcheck compare", ""]
|
||||
lines = ["# netsleuth compare", ""]
|
||||
lines += _block("Identity", diff.identity)
|
||||
lines += _block("Latency", diff.latency)
|
||||
lines += _block("Speed", diff.speed)
|
||||
|
|
@ -134,7 +134,7 @@ class Watch(BaseModel):
|
|||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
env_prefix="NETCHECK_",
|
||||
env_prefix="NETSLEUTH_",
|
||||
env_nested_delimiter="__",
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
|
|
@ -6,8 +6,8 @@ import re
|
|||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from netcheck.interpret import overall_verdict
|
||||
from netcheck.models import Finding, ModuleResult, to_jsonable
|
||||
from netsleuth.interpret import overall_verdict
|
||||
from netsleuth.models import Finding, ModuleResult, to_jsonable
|
||||
|
||||
SCHEMA_VERSION = 1
|
||||
SECTION_ORDER = (
|
||||
|
|
@ -101,7 +101,7 @@ def write_report(
|
|||
return json_path, md_path, ru_md_path
|
||||
|
||||
|
||||
from netcheck.interpret import bufferbloat_consequence
|
||||
from netsleuth.interpret import bufferbloat_consequence
|
||||
|
||||
SPARK_CHARS = "▁▂▃▅▇"
|
||||
_BADGES = {"ok": "🟢", "info": "🟢", "warn": "🟡", "crit": "🔴"}
|
||||
|
|
@ -210,7 +210,7 @@ def _header(report: dict, emoji: bool, lang: str = "en") -> list[str]:
|
|||
summary = interp.get("summary_text", "") if lang == "en" else _ru_summary(report, status)
|
||||
status_word = status if lang == "en" else _SEVERITY_WORDS_RU.get(status, status)
|
||||
return [
|
||||
"# netcheck report",
|
||||
"# netsleuth report",
|
||||
"",
|
||||
f"- {_t(lang, 'Mode', 'Режим')}: `{meta.get('mode', 'auto')}`{target}",
|
||||
f"- {_t(lang, 'Started', 'Начало')}: {meta.get('started_at', '?')} · "
|
||||
|
|
@ -2,8 +2,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import Iterable
|
||||
|
||||
from netcheck.config import Band, BufferbloatBands, Thresholds, VpnBands
|
||||
from netcheck.models import (
|
||||
from netsleuth.config import Band, BufferbloatBands, Thresholds, VpnBands
|
||||
from netsleuth.models import (
|
||||
CfTrace,
|
||||
DnsLeak,
|
||||
Finding,
|
||||
|
|
@ -15,7 +15,7 @@ from netcheck.models import (
|
|||
TraceResult,
|
||||
VpnAssessment,
|
||||
)
|
||||
from netcheck.netinfo import is_tunnel_iface, mtu_anomaly
|
||||
from netsleuth.netinfo import is_tunnel_iface, mtu_anomaly
|
||||
|
||||
_SEVERITY_ORDER = {"ok": 0, "info": 1, "warn": 2, "crit": 3}
|
||||
|
||||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import ipaddress
|
||||
import re
|
||||
|
||||
from netcheck.models import CfTrace, IpGeo
|
||||
from netsleuth.models import CfTrace, IpGeo
|
||||
|
||||
_AS_PREFIX_RE = re.compile(r"^AS(\d+)\s*(?P<name>.*)$", re.IGNORECASE)
|
||||
|
||||
|
|
@ -214,7 +214,7 @@ import asyncio
|
|||
|
||||
import httpx
|
||||
|
||||
from netcheck.config import Providers
|
||||
from netsleuth.config import Providers
|
||||
|
||||
|
||||
async def _json(client: httpx.AsyncClient, url: str, **kwargs) -> dict:
|
||||
|
|
@ -12,7 +12,7 @@ import subprocess
|
|||
|
||||
import psutil
|
||||
|
||||
from netcheck.models import Capabilities, LocalNet
|
||||
from netsleuth.models import Capabilities, LocalNet
|
||||
|
||||
_TUNNEL_PATTERNS = (
|
||||
re.compile(r"^(tun|tap|utun|ppp|wg|nordlynx|proton|ipsec|gpd)\d*", re.IGNORECASE),
|
||||
|
|
@ -7,7 +7,7 @@ from typing import Any, Awaitable
|
|||
|
||||
import httpx
|
||||
|
||||
from netcheck.models import ModuleResult, ProbeError
|
||||
from netsleuth.models import ModuleResult, ProbeError
|
||||
|
||||
_BLOCKED_STATUS = {401, 403, 451}
|
||||
_RETRYABLE_STATUS_FLOOR = 500
|
||||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import ipaddress
|
||||
|
||||
from netcheck.models import AdapterLeakResult, DnsLeak
|
||||
from netsleuth.models import AdapterLeakResult, DnsLeak
|
||||
|
||||
_LEAK_NOTE = (
|
||||
"This test only sees resolvers configured at the OS level. A browser using DoH "
|
||||
|
|
@ -99,8 +99,8 @@ import asyncio
|
|||
import dns.asyncresolver
|
||||
import dns.exception
|
||||
|
||||
from netcheck.bgp import parse_cymru_origin
|
||||
from netcheck.models import LocalNet
|
||||
from netsleuth.bgp import parse_cymru_origin
|
||||
from netsleuth.models import LocalNet
|
||||
|
||||
MYADDR_NAME = "o-o.myaddr.l.google.com"
|
||||
AKAHELP_NAME = "whoami.ds.akahelp.net"
|
||||
|
|
@ -107,7 +107,7 @@ def _handle():
|
|||
return iphlpapi, handle
|
||||
|
||||
|
||||
def echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netcheck") -> IcmpReply:
|
||||
def echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netsleuth") -> IcmpReply:
|
||||
iphlpapi, handle = _handle()
|
||||
try:
|
||||
options = _IpOptionInformation(Ttl=ttl, Tos=0, Flags=0, OptionsSize=0, OptionsData=None)
|
||||
|
|
@ -4,9 +4,9 @@ import asyncio
|
|||
import socket
|
||||
import time
|
||||
|
||||
from netcheck.models import Capabilities, PingResult
|
||||
from netcheck.netinfo import choose_latency_backend
|
||||
from netcheck.stats import rtt_stats
|
||||
from netsleuth.models import Capabilities, PingResult
|
||||
from netsleuth.netinfo import choose_latency_backend
|
||||
from netsleuth.stats import rtt_stats
|
||||
|
||||
|
||||
def summarize_ping(
|
||||
|
|
@ -57,7 +57,7 @@ def _resolve(host: str) -> str | None:
|
|||
|
||||
async def _icmp_samples(host: str, count: int, interval: float, timeout: float, backend: str) -> list[float | None]:
|
||||
if backend == "icmp_win":
|
||||
from netcheck.probes.icmp_win import ping_samples_win
|
||||
from netsleuth.probes.icmp_win import ping_samples_win
|
||||
|
||||
return await asyncio.to_thread(ping_samples_win, host, count, interval, timeout)
|
||||
from icmplib import async_ping
|
||||
|
|
@ -8,9 +8,9 @@ import shutil
|
|||
import threading
|
||||
from typing import Awaitable, Callable, TypeVar
|
||||
|
||||
from netcheck.models import Capabilities, TraceHop, TraceResult
|
||||
from netcheck.probes.icmp_win import IcmpReply, classify_status
|
||||
from netcheck.traceparse import build_trace_result, finalize_hop
|
||||
from netsleuth.models import Capabilities, TraceHop, TraceResult
|
||||
from netsleuth.probes.icmp_win import IcmpReply, classify_status
|
||||
from netsleuth.traceparse import build_trace_result, finalize_hop
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ def _run_in_daemon_thread(func: Callable[..., _T], *args: object) -> "asyncio.Fu
|
|||
else:
|
||||
result.set_result(value)
|
||||
|
||||
threading.Thread(target=_target, name="netcheck-icmp-win", daemon=True).start()
|
||||
threading.Thread(target=_target, name="netsleuth-icmp-win", daemon=True).start()
|
||||
return asyncio.wrap_future(result)
|
||||
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ async def _tier_mtr(target: str, binary: str, cycles: int, max_hops: int, timeou
|
|||
|
||||
|
||||
async def _tier_icmp_win(target: str, max_hops: int, timeout: float) -> TraceResult:
|
||||
from netcheck.probes.icmp_win import trace_hops_win
|
||||
from netsleuth.probes.icmp_win import trace_hops_win
|
||||
|
||||
replies = await _run_in_daemon_thread(trace_hops_win, target, max_hops, int(timeout * 1000))
|
||||
hops = hops_from_win_replies(replies)
|
||||
|
|
@ -12,8 +12,8 @@ import dns.asyncresolver
|
|||
import dns.exception
|
||||
import httpx
|
||||
|
||||
from netcheck.config import Providers
|
||||
from netcheck.models import DnsblHit, InternetDbResult, Reputation
|
||||
from netsleuth.config import Providers
|
||||
from netsleuth.models import DnsblHit, InternetDbResult, Reputation
|
||||
|
||||
|
||||
def parse_netset(text: str) -> list[str]:
|
||||
|
|
@ -3,8 +3,8 @@ from __future__ import annotations
|
|||
import re
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
from netcheck.models import CfL4Stats
|
||||
from netcheck.stats import percentile
|
||||
from netsleuth.models import CfL4Stats
|
||||
from netsleuth.stats import percentile
|
||||
|
||||
_CFL4_RE = re.compile(r'cfL4\s*;\s*desc\s*=\s*"?\??(?P<query>[^",]*)"?')
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ import asyncio
|
|||
import time
|
||||
from typing import Awaitable, Callable
|
||||
|
||||
from netcheck.models import SpeedResult, TierAttempt
|
||||
from netsleuth.models import SpeedResult, TierAttempt
|
||||
|
||||
NDT7_CONSENT_NOTICE = (
|
||||
"M-Lab NDT7 publishes every measurement as public CC0 open data, including your "
|
||||
|
|
@ -106,7 +106,7 @@ import json
|
|||
|
||||
import httpx
|
||||
|
||||
from netcheck.config import Speedtest
|
||||
from netsleuth.config import Speedtest
|
||||
|
||||
|
||||
async def tier_ookla(binary: str, server: str | None, timeout: float) -> SpeedResult:
|
||||
|
|
@ -213,9 +213,9 @@ async def tier_ndt7(client: httpx.AsyncClient, cfg: Speedtest, timeout: float) -
|
|||
)
|
||||
|
||||
|
||||
from netcheck.config import BufferbloatBands
|
||||
from netcheck.interpret import grade_bufferbloat
|
||||
from netcheck.stats import rtt_stats
|
||||
from netsleuth.config import BufferbloatBands
|
||||
from netsleuth.interpret import grade_bufferbloat
|
||||
from netsleuth.stats import rtt_stats
|
||||
|
||||
|
||||
async def probe_while(
|
||||
|
|
@ -2,8 +2,8 @@ from __future__ import annotations
|
|||
|
||||
import re
|
||||
|
||||
from netcheck.models import TraceHop, TraceResult
|
||||
from netcheck.stats import rtt_stats
|
||||
from netsleuth.models import TraceHop, TraceResult
|
||||
from netsleuth.stats import rtt_stats
|
||||
|
||||
IPV4_RE = re.compile(r"\b(?:\d{1,3}\.){3}\d{1,3}\b")
|
||||
IPV6_RE = re.compile(r"\b(?:[0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b")
|
||||
|
|
@ -11,14 +11,14 @@ from rich.console import Console
|
|||
from rich.live import Live
|
||||
from rich.table import Table
|
||||
|
||||
from netcheck import __version__
|
||||
from netcheck.config import Settings
|
||||
from netcheck.exporter import atomic_write, compact_timestamp, dump_json, sanitize_name, sparkline
|
||||
from netcheck.ip_geo import gather_identity
|
||||
from netcheck.models import PingResult, SpeedResult, to_jsonable
|
||||
from netcheck.netinfo import detect_capabilities
|
||||
from netcheck.orchestration import run_module, utc_now_iso
|
||||
from netcheck.probes.latency import ping_fanout
|
||||
from netsleuth import __version__
|
||||
from netsleuth.config import Settings
|
||||
from netsleuth.exporter import atomic_write, compact_timestamp, dump_json, sanitize_name, sparkline
|
||||
from netsleuth.ip_geo import gather_identity
|
||||
from netsleuth.models import PingResult, SpeedResult, to_jsonable
|
||||
from netsleuth.netinfo import detect_capabilities
|
||||
from netsleuth.orchestration import run_module, utc_now_iso
|
||||
from netsleuth.probes.latency import ping_fanout
|
||||
|
||||
WATCH_SCHEMA_VERSION = 1
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ def write_session(session: WatchSession, logs_dir: Path) -> Path:
|
|||
|
||||
|
||||
def render_dashboard(session: WatchSession) -> Table:
|
||||
table = Table(title=f"netcheck --watch · {session.asn or 'unknown ASN'} · cycle {len(session.cycles)}")
|
||||
table = Table(title=f"netsleuth --watch · {session.asn or 'unknown ASN'} · cycle {len(session.cycles)}")
|
||||
for column in ("Host", "Avg ms", "Jitter", "Loss", "Trend"):
|
||||
table.add_column(column)
|
||||
latest = session.cycles[-1]["hosts"] if session.cycles else {}
|
||||
|
|
@ -137,7 +137,7 @@ def render_dashboard(session: WatchSession) -> Table:
|
|||
async def run_watch(settings: Settings, options) -> Path:
|
||||
# Imported here, not at module import time: cli imports watch lazily for --watch,
|
||||
# and a module-level import back into cli would close the cycle.
|
||||
from netcheck.cli import _speed_section
|
||||
from netsleuth.cli import _speed_section
|
||||
|
||||
caps = detect_capabilities()
|
||||
session = WatchSession(
|
||||
|
|
@ -149,12 +149,12 @@ async def run_watch(settings: Settings, options) -> Path:
|
|||
if options.extra_host:
|
||||
hosts.append(("target-host", options.extra_host))
|
||||
console = Console()
|
||||
console.print(f"netcheck {__version__} · watching every {session.interval_seconds}s · Ctrl-C to stop")
|
||||
console.print(f"netsleuth {__version__} · watching every {session.interval_seconds}s · Ctrl-C to stop")
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
timeout=settings.timeouts.http_seconds,
|
||||
follow_redirects=True,
|
||||
headers={"User-Agent": f"netcheck/{__version__}"},
|
||||
headers={"User-Agent": f"netsleuth/{__version__}"},
|
||||
) as client:
|
||||
try:
|
||||
geo, _cf, _flags, _raw = await gather_identity(client, settings.providers)
|
||||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import httpx
|
||||
import pytest
|
||||
|
||||
from netcheck.bgp import (
|
||||
from netsleuth.bgp import (
|
||||
classify_stability,
|
||||
parse_announced_prefixes,
|
||||
parse_as_overview,
|
||||
|
|
@ -11,8 +11,8 @@ from netcheck.bgp import (
|
|||
parse_bgp_updates,
|
||||
ripestat,
|
||||
)
|
||||
from netcheck.config import Providers
|
||||
from netcheck.models import BgpEvent
|
||||
from netsleuth.config import Providers
|
||||
from netsleuth.models import BgpEvent
|
||||
|
||||
|
||||
def test_as_overview_extracts_holder_and_block(api_fixture):
|
||||
|
|
@ -99,7 +99,7 @@ async def test_ripestat_does_not_bound_non_bulk_calls(httpx_mock):
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from netcheck.bgp import (
|
||||
from netsleuth.bgp import (
|
||||
cached_json,
|
||||
parse_asrank,
|
||||
parse_cymru_origin,
|
||||
|
|
@ -211,7 +211,7 @@ async def test_cached_json_survives_a_corrupt_cache_file(tmp_path: Path):
|
|||
assert await cached_json(tmp_path, "k", ttl_hours=24, fetch=fetch) == {"value": "fresh"}
|
||||
|
||||
|
||||
from netcheck.bgp import build_bgp_intel
|
||||
from netsleuth.bgp import build_bgp_intel
|
||||
|
||||
|
||||
def test_build_bgp_intel_merges_every_source(api_fixture):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.compare import (
|
||||
from netsleuth.compare import (
|
||||
Change,
|
||||
diff_reports,
|
||||
finding_changes,
|
||||
|
|
@ -101,7 +101,7 @@ def test_diff_reports_assembles_every_part(before, after):
|
|||
|
||||
def test_render_diff_shows_before_and_after_values(before, after):
|
||||
text = render_diff(diff_reports(before, after))
|
||||
assert text.startswith("# netcheck compare")
|
||||
assert text.startswith("# netsleuth compare")
|
||||
assert "203.0.113.44" in text
|
||||
assert "198.51.100.7" in text
|
||||
assert "-188.2" in text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import textwrap
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.config import load_settings
|
||||
from netsleuth.config import load_settings
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
|
@ -48,15 +48,15 @@ def test_yaml_overrides_defaults(yaml_file, tmp_path):
|
|||
|
||||
def test_dotenv_overrides_yaml(yaml_file, tmp_path):
|
||||
env_file = tmp_path / ".env"
|
||||
env_file.write_text("NETCHECK_PROBING__PING_COUNT=13\n", encoding="utf-8")
|
||||
env_file.write_text("NETSLEUTH_PROBING__PING_COUNT=13\n", encoding="utf-8")
|
||||
s = load_settings(config_path=yaml_file, env_file=env_file)
|
||||
assert s.probing.ping_count == 13
|
||||
|
||||
|
||||
def test_environment_overrides_dotenv(yaml_file, tmp_path, monkeypatch):
|
||||
env_file = tmp_path / ".env"
|
||||
env_file.write_text("NETCHECK_PROBING__PING_COUNT=13\n", encoding="utf-8")
|
||||
monkeypatch.setenv("NETCHECK_PROBING__PING_COUNT", "99")
|
||||
env_file.write_text("NETSLEUTH_PROBING__PING_COUNT=13\n", encoding="utf-8")
|
||||
monkeypatch.setenv("NETSLEUTH_PROBING__PING_COUNT", "99")
|
||||
s = load_settings(config_path=yaml_file, env_file=env_file)
|
||||
assert s.probing.ping_count == 99
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from netcheck.probes.dns_leak import (
|
||||
from netsleuth.probes.dns_leak import (
|
||||
build_adapter_result,
|
||||
build_dns_leak,
|
||||
detect_ecs_leak,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.reputation import decode_dnsbl, reverse_ip, summarize_dnsbl
|
||||
from netsleuth.reputation import decode_dnsbl, reverse_ip, summarize_dnsbl
|
||||
|
||||
|
||||
def test_reverse_ip_builds_the_dnsbl_query_label():
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from pathlib import Path
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.exporter import (
|
||||
from netsleuth.exporter import (
|
||||
SCHEMA_VERSION,
|
||||
SECTION_ORDER,
|
||||
atomic_write,
|
||||
|
|
@ -19,7 +19,7 @@ from netcheck.exporter import (
|
|||
sanitize_name,
|
||||
write_report,
|
||||
)
|
||||
from netcheck.models import (
|
||||
from netsleuth.models import (
|
||||
Finding,
|
||||
IpGeo,
|
||||
LocalNet,
|
||||
|
|
@ -196,7 +196,7 @@ def test_egress_asn_is_read_out_of_the_assembled_report():
|
|||
def test_write_report_names_the_file_after_the_target_in_target_mode(tmp_path: Path):
|
||||
report = build_report({**meta(), "mode": "target", "target": "AS15169"}, modules(), [], {})
|
||||
json_path, md_path, ru_md_path = write_report(
|
||||
report, "# netcheck report\n", "# netcheck report\n", tmp_path
|
||||
report, "# netsleuth report\n", "# netsleuth report\n", tmp_path
|
||||
)
|
||||
assert json_path.name == "report_AS15169_20260808T191200Z.json"
|
||||
assert md_path.name == "report_AS15169_20260808T191200Z.md"
|
||||
|
|
@ -221,18 +221,18 @@ def test_atomic_write_replaces_an_existing_file(tmp_path: Path):
|
|||
def test_write_report_emits_both_artifacts_with_matching_names(tmp_path: Path):
|
||||
report = build_report(meta(), modules(), [], {})
|
||||
json_path, md_path, ru_md_path = write_report(
|
||||
report, "# netcheck report\n", "# netcheck report\n", tmp_path
|
||||
report, "# netsleuth report\n", "# netsleuth report\n", tmp_path
|
||||
)
|
||||
assert json_path.name == "report_AS64500_20260808T191200Z.json"
|
||||
assert md_path.name == "report_AS64500_20260808T191200Z.md"
|
||||
assert ru_md_path.name == "report_AS64500_20260808T191200Z.ru.md"
|
||||
assert json.loads(json_path.read_text(encoding="utf-8"))["schema_version"] == SCHEMA_VERSION
|
||||
assert md_path.read_text(encoding="utf-8").startswith("# netcheck report")
|
||||
assert ru_md_path.read_text(encoding="utf-8").startswith("# netcheck report")
|
||||
assert md_path.read_text(encoding="utf-8").startswith("# netsleuth report")
|
||||
assert ru_md_path.read_text(encoding="utf-8").startswith("# netsleuth report")
|
||||
|
||||
|
||||
from netcheck.exporter import SPARK_CHARS, badge, first_loss_jump, render_markdown, sparkline
|
||||
from netcheck.models import (
|
||||
from netsleuth.exporter import SPARK_CHARS, badge, first_loss_jump, render_markdown, sparkline
|
||||
from netsleuth.models import (
|
||||
AdapterLeakResult,
|
||||
BgpIntel,
|
||||
CfTrace,
|
||||
|
|
@ -466,7 +466,7 @@ def test_markdown_has_every_section_from_the_spec_in_order():
|
|||
"## Problems & recommendations",
|
||||
"## Run diagnostics",
|
||||
]
|
||||
assert text.startswith("# netcheck report")
|
||||
assert text.startswith("# netsleuth report")
|
||||
|
||||
|
||||
def test_markdown_header_states_mode_timestamp_and_verdict():
|
||||
|
|
@ -542,7 +542,7 @@ def test_markdown_without_emoji_uses_text_badges():
|
|||
assert "🟡" not in text
|
||||
|
||||
|
||||
from netcheck.exporter import unavailable
|
||||
from netsleuth.exporter import unavailable
|
||||
|
||||
|
||||
def dead_modules() -> dict[str, ModuleResult]:
|
||||
|
|
@ -603,7 +603,7 @@ def test_unavailable_translates_the_skip_reason_into_russian():
|
|||
|
||||
|
||||
def test_diagnostics_translates_module_warnings_into_russian():
|
||||
from netcheck.exporter import _diagnostics
|
||||
from netsleuth.exporter import _diagnostics
|
||||
|
||||
report = build_report(
|
||||
meta(),
|
||||
|
|
@ -666,7 +666,7 @@ def test_russian_markdown_is_non_empty_and_contains_cyrillic():
|
|||
text = render_markdown(full_report(), lang="ru")
|
||||
assert text.strip()
|
||||
assert _has_cyrillic(text)
|
||||
assert text.startswith("# netcheck report")
|
||||
assert text.startswith("# netsleuth report")
|
||||
|
||||
|
||||
def _structural_shape(text: str) -> tuple[int, int, int]:
|
||||
|
|
@ -723,7 +723,7 @@ def test_render_markdown_default_call_is_byte_identical_to_before_the_lang_featu
|
|||
"## Problems & recommendations",
|
||||
"## Run diagnostics",
|
||||
]
|
||||
assert text.startswith("# netcheck report")
|
||||
assert text.startswith("# netsleuth report")
|
||||
assert "[Русский]" not in text
|
||||
assert "[English]" not in text
|
||||
assert "cloudflare-dns" in text
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import struct
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.probes.icmp_win import (
|
||||
from netsleuth.probes.icmp_win import (
|
||||
IP_DEST_HOST_UNREACHABLE,
|
||||
IP_REQ_TIMED_OUT,
|
||||
IP_SUCCESS,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import time
|
||||
from unittest.mock import patch
|
||||
|
||||
from netcheck.probes.icmp_win import IP_REQ_TIMED_OUT, IcmpReply, trace_hops_win
|
||||
from netsleuth.probes.icmp_win import IP_REQ_TIMED_OUT, IcmpReply, trace_hops_win
|
||||
|
||||
|
||||
def _fake_gethostbyname(host: str) -> str:
|
||||
|
|
@ -19,14 +19,14 @@ def test_trace_hops_win_total_elapsed_is_bounded_by_the_total_budget_not_hops_ti
|
|||
# to the 100ms total budget.
|
||||
call_timeouts: list[int] = []
|
||||
|
||||
def fake_echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netcheck") -> IcmpReply:
|
||||
def fake_echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netsleuth") -> IcmpReply:
|
||||
call_timeouts.append(timeout_ms)
|
||||
time.sleep(timeout_ms / 1000.0)
|
||||
return IcmpReply(address=None, status=IP_REQ_TIMED_OUT, rtt_ms=None, ttl=0)
|
||||
|
||||
with (
|
||||
patch("netcheck.probes.icmp_win.socket.gethostbyname", side_effect=_fake_gethostbyname),
|
||||
patch("netcheck.probes.icmp_win.echo_once", side_effect=fake_echo_once),
|
||||
patch("netsleuth.probes.icmp_win.socket.gethostbyname", side_effect=_fake_gethostbyname),
|
||||
patch("netsleuth.probes.icmp_win.echo_once", side_effect=fake_echo_once),
|
||||
):
|
||||
started = time.monotonic()
|
||||
trace_hops_win("example.invalid", max_hops=30, timeout_ms=100)
|
||||
|
|
@ -43,13 +43,13 @@ def test_trace_hops_win_total_elapsed_is_bounded_by_the_total_budget_not_hops_ti
|
|||
def test_trace_hops_win_per_hop_timeout_is_capped_even_for_a_huge_total_budget():
|
||||
call_timeouts: list[int] = []
|
||||
|
||||
def fake_echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netcheck") -> IcmpReply:
|
||||
def fake_echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netsleuth") -> IcmpReply:
|
||||
call_timeouts.append(timeout_ms)
|
||||
return IcmpReply(address=None, status=IP_REQ_TIMED_OUT, rtt_ms=None, ttl=0)
|
||||
|
||||
with (
|
||||
patch("netcheck.probes.icmp_win.socket.gethostbyname", side_effect=_fake_gethostbyname),
|
||||
patch("netcheck.probes.icmp_win.echo_once", side_effect=fake_echo_once),
|
||||
patch("netsleuth.probes.icmp_win.socket.gethostbyname", side_effect=_fake_gethostbyname),
|
||||
patch("netsleuth.probes.icmp_win.echo_once", side_effect=fake_echo_once),
|
||||
):
|
||||
# A single-hop trace with a huge total budget (e.g. subprocess_seconds=60s
|
||||
# divided across a small max_hops) must still not hand the whole budget
|
||||
|
|
@ -60,16 +60,16 @@ def test_trace_hops_win_per_hop_timeout_is_capped_even_for_a_huge_total_budget()
|
|||
|
||||
|
||||
def test_trace_hops_win_happy_path_hop_count_and_ok_break_are_unchanged():
|
||||
from netcheck.probes.icmp_win import IP_SUCCESS
|
||||
from netsleuth.probes.icmp_win import IP_SUCCESS
|
||||
|
||||
def fake_echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netcheck") -> IcmpReply:
|
||||
def fake_echo_once(dest: str, ttl: int, timeout_ms: int, payload: bytes = b"netsleuth") -> IcmpReply:
|
||||
if ttl < 3:
|
||||
return IcmpReply(address=f"10.0.0.{ttl}", status=IP_REQ_TIMED_OUT, rtt_ms=None, ttl=0)
|
||||
return IcmpReply(address="203.0.113.1", status=IP_SUCCESS, rtt_ms=5.0, ttl=64)
|
||||
|
||||
with (
|
||||
patch("netcheck.probes.icmp_win.socket.gethostbyname", side_effect=_fake_gethostbyname),
|
||||
patch("netcheck.probes.icmp_win.echo_once", side_effect=fake_echo_once),
|
||||
patch("netsleuth.probes.icmp_win.socket.gethostbyname", side_effect=_fake_gethostbyname),
|
||||
patch("netsleuth.probes.icmp_win.echo_once", side_effect=fake_echo_once),
|
||||
):
|
||||
hops = trace_hops_win("example.invalid", max_hops=30, timeout_ms=60_000)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ from __future__ import annotations
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.config import Band, Thresholds
|
||||
from netcheck.models import PingResult, TraceHop, TraceResult
|
||||
from netcheck.interpret import latency_findings, path_findings, severity_for, worst
|
||||
from netsleuth.config import Band, Thresholds
|
||||
from netsleuth.models import PingResult, TraceHop, TraceResult
|
||||
from netsleuth.interpret import latency_findings, path_findings, severity_for, worst
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
|
@ -156,9 +156,9 @@ def test_path_findings_report_an_incomplete_trace():
|
|||
assert [f.id for f in path_findings(trace)] == ["path.incomplete"]
|
||||
|
||||
|
||||
from netcheck.config import VpnBands
|
||||
from netcheck.models import AdapterLeakResult, CfTrace, DnsLeak, IpGeo, LocalNet, Signal
|
||||
from netcheck.interpret import SIGNAL_WEIGHTS, assess_vpn, gather_vpn_signals, score_vpn
|
||||
from netsleuth.config import VpnBands
|
||||
from netsleuth.models import AdapterLeakResult, CfTrace, DnsLeak, IpGeo, LocalNet, Signal
|
||||
from netsleuth.interpret import SIGNAL_WEIGHTS, assess_vpn, gather_vpn_signals, score_vpn
|
||||
|
||||
|
||||
def sig(name: str, observed: bool = True) -> Signal:
|
||||
|
|
@ -303,9 +303,9 @@ def test_assess_vpn_returns_a_complete_assessment():
|
|||
assert assessment.confidence >= 0.75
|
||||
|
||||
|
||||
from netcheck.config import BufferbloatBands
|
||||
from netcheck.models import Finding, SpeedResult
|
||||
from netcheck.interpret import bufferbloat_consequence, grade_bufferbloat, overall_verdict, speed_findings
|
||||
from netsleuth.config import BufferbloatBands
|
||||
from netsleuth.models import Finding, SpeedResult
|
||||
from netsleuth.interpret import bufferbloat_consequence, grade_bufferbloat, overall_verdict, speed_findings
|
||||
|
||||
|
||||
def test_bufferbloat_grades_follow_the_configured_bands():
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ from __future__ import annotations
|
|||
import httpx
|
||||
import pytest
|
||||
|
||||
from netcheck.config import Providers
|
||||
from netcheck.ip_geo import (
|
||||
from netsleuth.config import Providers
|
||||
from netsleuth.ip_geo import (
|
||||
classify_ip_type,
|
||||
gather_identity,
|
||||
normalize_freeipapi,
|
||||
|
|
@ -130,8 +130,8 @@ def test_ip_type_classification(mobile, proxy, hosting, known, expected):
|
|||
assert classify_ip_type(mobile, proxy, hosting, known) == expected
|
||||
|
||||
|
||||
from netcheck.models import IpGeo
|
||||
from netcheck.ip_geo import dual_stack_mismatch, merge_geo
|
||||
from netsleuth.models import IpGeo
|
||||
from netsleuth.ip_geo import dual_stack_mismatch, merge_geo
|
||||
|
||||
|
||||
def test_merge_takes_the_first_non_empty_value_in_priority_order():
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import json
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.models import (
|
||||
from netsleuth.models import (
|
||||
AdapterLeakResult,
|
||||
BgpEvent,
|
||||
BgpIntel,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from netcheck.models import Capabilities
|
||||
from netcheck.netinfo import choose_latency_backend, choose_trace_backend, degradation_note
|
||||
from netsleuth.models import Capabilities
|
||||
from netsleuth.netinfo import choose_latency_backend, choose_trace_backend, degradation_note
|
||||
|
||||
|
||||
def caps(**kw) -> Capabilities:
|
||||
|
|
@ -69,7 +69,7 @@ def test_degradation_note_on_windows_mentions_the_api_rather_than_sysctl():
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.netinfo import iface_for_ip, is_tunnel_iface, mtu_anomaly
|
||||
from netsleuth.netinfo import iface_for_ip, is_tunnel_iface, mtu_anomaly
|
||||
|
||||
|
||||
def test_iface_for_ip_matches_the_owning_adapter():
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import asyncio
|
|||
import httpx
|
||||
import pytest
|
||||
|
||||
from netcheck.models import ModuleResult, ProbeError
|
||||
from netcheck.orchestration import classify_exception, gather_modules, run_module
|
||||
from netsleuth.models import ModuleResult, ProbeError
|
||||
from netsleuth.orchestration import classify_exception, gather_modules, run_module
|
||||
|
||||
|
||||
def test_classify_timeout_errors():
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.probes.latency import summarize_ping
|
||||
from netsleuth.probes.latency import summarize_ping
|
||||
|
||||
|
||||
def test_summarize_builds_a_complete_ping_result():
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from netcheck.reputation import (
|
||||
from netsleuth.reputation import (
|
||||
NetsetIndex,
|
||||
build_reputation,
|
||||
captcha_risk,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.speed import bufferbloat_delta, mbps, parse_server_timing_cfl4, throughput_from_samples
|
||||
from netsleuth.speed import bufferbloat_delta, mbps, parse_server_timing_cfl4, throughput_from_samples
|
||||
|
||||
|
||||
def test_mbps_converts_bytes_and_seconds():
|
||||
|
|
@ -86,8 +86,8 @@ def test_bufferbloat_delta_needs_both_a_baseline_and_samples():
|
|||
assert bufferbloat_delta(12.0, []) is None
|
||||
|
||||
|
||||
from netcheck.models import SpeedResult, TierAttempt
|
||||
from netcheck.speed import NDT7_CONSENT_NOTICE, run_speed_cascade
|
||||
from netsleuth.models import SpeedResult, TierAttempt
|
||||
from netsleuth.speed import NDT7_CONSENT_NOTICE, run_speed_cascade
|
||||
|
||||
|
||||
async def test_cascade_stops_at_the_first_tier_that_returns_a_download_figure():
|
||||
|
|
@ -171,8 +171,8 @@ def test_the_ndt7_consent_notice_states_what_gets_published():
|
|||
assert "public" in NDT7_CONSENT_NOTICE.lower()
|
||||
|
||||
|
||||
from netcheck.config import BufferbloatBands
|
||||
from netcheck.speed import measure_with_bufferbloat, probe_while
|
||||
from netsleuth.config import BufferbloatBands
|
||||
from netsleuth.speed import measure_with_bufferbloat, probe_while
|
||||
|
||||
|
||||
async def test_probe_while_collects_samples_for_the_whole_duration_of_the_work():
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import math
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.stats import percentile, rtt_stats
|
||||
from netsleuth.stats import percentile, rtt_stats
|
||||
|
||||
|
||||
def test_all_samples_present():
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.traceparse import parse_linux
|
||||
from netsleuth.traceparse import parse_linux
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
|
@ -73,7 +73,7 @@ def test_linux_parser_tolerates_empty_and_garbage_input():
|
|||
assert parse_linux("bash: traceroute: command not found\n") == []
|
||||
|
||||
|
||||
from netcheck.traceparse import WINDOWS_SUB_MS, parse_windows
|
||||
from netsleuth.traceparse import WINDOWS_SUB_MS, parse_windows
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
|
@ -143,7 +143,7 @@ def test_windows_parser_tolerates_empty_input():
|
|||
assert parse_windows("") == []
|
||||
|
||||
|
||||
from netcheck.traceparse import parse_darwin
|
||||
from netsleuth.traceparse import parse_darwin
|
||||
|
||||
|
||||
def test_darwin_basic_hops_match_the_gnu_shape(trace_fixture):
|
||||
|
|
@ -185,7 +185,7 @@ def test_darwin_parser_tolerates_empty_input():
|
|||
assert parse_darwin("") == []
|
||||
|
||||
|
||||
from netcheck.traceparse import build_trace_result, parse_traceroute
|
||||
from netsleuth.traceparse import build_trace_result, parse_traceroute
|
||||
|
||||
|
||||
def test_dispatcher_routes_by_os_name(trace_fixture):
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import threading
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.models import Capabilities, TraceHop, TraceResult
|
||||
from netcheck.probes.icmp_win import IP_REQ_TIMED_OUT, IP_SUCCESS, IP_TTL_EXPIRED_TRANSIT, IcmpReply
|
||||
from netcheck.probes.traceroute import _run_in_daemon_thread, hops_from_win_replies, run_cascade, tier_order
|
||||
from netsleuth.models import Capabilities, TraceHop, TraceResult
|
||||
from netsleuth.probes.icmp_win import IP_REQ_TIMED_OUT, IP_SUCCESS, IP_TTL_EXPIRED_TRANSIT, IcmpReply
|
||||
from netsleuth.probes.traceroute import _run_in_daemon_thread, hops_from_win_replies, run_cascade, tier_order
|
||||
|
||||
|
||||
def caps(**kw) -> Capabilities:
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ from pathlib import Path
|
|||
|
||||
import pytest
|
||||
|
||||
from netcheck.models import PingResult, SpeedResult
|
||||
from netcheck.watch import (
|
||||
from netsleuth.models import PingResult, SpeedResult
|
||||
from netsleuth.watch import (
|
||||
WATCH_SCHEMA_VERSION,
|
||||
WatchSession,
|
||||
is_speedtest_cycle,
|
||||
|
|
|
|||
2
uv.lock
generated
2
uv.lock
generated
|
|
@ -208,7 +208,7 @@ wheels = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "netcheck"
|
||||
name = "netsleuth"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue