diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 617f3119..26352904 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ 'name': 'build' 'env': - 'GO_VERSION': '1.24.5' + 'GO_VERSION': '1.24.6' 'NODE_VERSION': '20' 'on': diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2c0b13e8..7853f146 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,7 +1,7 @@ 'name': 'lint' 'env': - 'GO_VERSION': '1.24.5' + 'GO_VERSION': '1.24.6' 'on': 'push': diff --git a/.gitignore b/.gitignore index 0b7a6414..49e63663 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,8 @@ AdGuardHome.exe AdGuardHome.yaml* coverage.txt node_modules/ +test-reports/ +tmp/ !/build/gitkeep diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e20e7be..d5c96ab1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ See also the [v0.107.65 GitHub milestone][ms-v0.107.65]. NOTE: Add new changes BELOW THIS COMMENT. --> +### Security + +- Go version has been updated to prevent the possibility of exploiting the Go vulnerabilities fixed in [1.24.6][go-1.24.6]. + ### Added - A separate checkbox in the Web UI to enable or disable the global DNS response cache without losing the configured cache size. @@ -53,6 +57,8 @@ In this release, the schema version has changed from 29 to 30. [#7923]: https://github.com/AdguardTeam/AdGuardHome/issues/7923 +[go-1.24.6]: https://groups.google.com/g/golang-announce/c/x5MKroML2yM + diff --git a/Makefile b/Makefile index f838467b..336a7f29 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ DIST_DIR = dist GOAMD64 = v1 GOPROXY = https://proxy.golang.org|direct GOTELEMETRY = off -GOTOOLCHAIN = go1.24.5 +GOTOOLCHAIN = go1.24.6 GPG_KEY = devteam@adguard.com GPG_KEY_PASSPHRASE = not-a-real-password NPM = npm diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 116ade6f..838c94ed 100644 --- a/bamboo-specs/release.yaml +++ b/bamboo-specs/release.yaml @@ -8,7 +8,7 @@ 'variables': 'channel': 'edge' 'dockerFrontend': 'adguard/home-js-builder:3.1' - 'dockerGo': 'adguard/go-builder:1.24.5--2' + 'dockerGo': 'adguard/go-builder:1.24.6--1' 'stages': - 'Build frontend': @@ -279,7 +279,7 @@ 'variables': 'channel': 'beta' 'dockerFrontend': 'adguard/home-js-builder:3.1' - 'dockerGo': 'adguard/go-builder:1.24.5--2' + 'dockerGo': 'adguard/go-builder:1.24.6--1' # release-vX.Y.Z branches are the branches from which the actual final # release is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -295,4 +295,4 @@ 'variables': 'channel': 'release' 'dockerFrontend': 'adguard/home-js-builder:3.1' - 'dockerGo': 'adguard/go-builder:1.24.5--2' + 'dockerGo': 'adguard/go-builder:1.24.6--1' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index 3c94be2f..9bb4cf83 100644 --- a/bamboo-specs/test.yaml +++ b/bamboo-specs/test.yaml @@ -6,7 +6,7 @@ 'name': 'AdGuard Home - Build and run tests' 'variables': 'dockerFrontend': 'adguard/home-js-builder:3.1' - 'dockerGo': 'adguard/go-builder:1.24.5--2' + 'dockerGo': 'adguard/go-builder:1.24.6--1' 'channel': 'development' 'stages': @@ -67,6 +67,13 @@ 'volumes': '${system.GO_CACHE_DIR}': '${bamboo.cacheGo}' '${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}' + 'final-tasks': + - 'test-parser': + # The default pattern, '**/test-reports/*.xml', works, so don't set + # the test-results property. + 'type': 'junit' + 'ignore-time': true + - 'clean' 'key': 'GOTEST' 'other': 'clean-working-dir': true @@ -81,16 +88,26 @@ set -e -f -u -x - make\ - GOMAXPROCS=1\ - VERBOSE=1\ + make \ + GOMAXPROCS=1 \ + VERBOSE=1 \ go-deps go-tools go-lint - make\ - VERBOSE=1\ - go-test - 'final-tasks': - - 'clean' + make \ + TEST_REPORTS_DIR="./test-reports/" \ + VERBOSE=1 \ + go-test \ + ; + + exit_code="$(cat ./test-reports/test-exit-code.txt)" + readonly exit_code + + make VERBOSE=1 \ + go-fuzz \ + go-bench \ + ; + + exit "$exit_code" 'requirements': - 'adg-docker': 'true' @@ -234,5 +251,5 @@ # may need to build a few of these. 'variables': 'dockerFrontend': 'adguard/home-js-builder:3.1' - 'dockerGo': 'adguard/go-builder:1.24.5--2' + 'dockerGo': 'adguard/go-builder:1.24.6--1' 'channel': 'candidate' diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json index db963b2e..4484f9ad 100644 --- a/client/src/__locales/be.json +++ b/client/src/__locales/be.json @@ -89,7 +89,7 @@ "form_enter_hostname": "Увядзіце імя хаста", "error_details": "Дэталізацыя памылкі", "response_details": "Дэталі адказу", - "request_details": "Інфармацыя пра запыт", + "request_details": "Падрабязнасці запыту", "client_details": "Дэталі кліента", "details": "Дэталі", "back": "Назад", @@ -108,7 +108,7 @@ "off": "Выкл", "copyright": "Усе правы захаваныя", "homepage": "Хатняя старонка", - "report_an_issue": "Паведаміць пра праблему", + "report_an_issue": "Паведаміць аб праблеме", "privacy_policy": "Палітыка прыватнасці", "enable_protection": "Уключыць абарону", "enabled_protection": "Абарона ўкл.", @@ -736,13 +736,13 @@ "thursday": "Чацвер", "friday": "Пятніца", "saturday": "Субота", - "sunday_short": "Нд.", - "monday_short": "Пн.", - "tuesday_short": "Аў.", - "wednesday_short": "Ср.", - "thursday_short": "Чц.", - "friday_short": "Пт.", - "saturday_short": "Сб.", + "sunday_short": "Ндз", + "monday_short": "Пан", + "tuesday_short": "Аўт", + "wednesday_short": "Срд", + "thursday_short": "Чцв", + "friday_short": "Птн", + "saturday_short": "Суб", "upstream_dns_cache_configuration": "Канфігурацыя кэша upstream сервер DNSаў", "enable_upstream_dns_cache": "Ўключыць кэшаванне для карыстацкай канфігурацыі upstream-сервераў гэтага кліента", "dns_cache_size": "Памер кэша DNS, у байтах" diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index 4851d0ba..9a6106c5 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -655,7 +655,10 @@ "safe_search": "Bezpečné vyhledávání", "blocklist": "Zakázaný", "milliseconds_abbreviation": "ms", + "cache_enabled": "Povolit mezipaměť", + "cache_enabled_desc": "Ukládejte odezvy DNS lokálně.", "cache_size": "Velikost mezipaměti", + "cache_size_validation": "Velikost mezipaměti musí být větší než nula, pokud je tato funkce povolena.", "cache_size_desc": "Velikost mezipaměti DNS (v bajtech). Chcete-li ukládání do mezipaměti zakázat, nastavte 0.", "cache_ttl_min_override": "Přepsat minimální hodnotu TTL", "cache_ttl_max_override": "Přepsat maximální hodnotu TTL", diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index 9acaaece..f74f92f3 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -655,7 +655,10 @@ "safe_search": "Sikker søgning", "blocklist": "Sortliste", "milliseconds_abbreviation": "ms", + "cache_enabled": "Aktivér cache", + "cache_enabled_desc": "Opbevar DNS-svar lokalt.", "cache_size": "Cache-størrelse", + "cache_size_validation": "Cache-størrelsen skal være større end nul, når den er aktiveret.", "cache_size_desc": "DNS cache-størrelse (i bytes). Sæt til 0 for at deaktivere cache.", "cache_ttl_min_override": "Tilsidesæt minimum TTL", "cache_ttl_max_override": "Tilsidesæt maksimal TTL", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index 4c855793..e52d9a3b 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -655,7 +655,10 @@ "safe_search": "Sichere Suche", "blocklist": "Sperrliste", "milliseconds_abbreviation": "ms", + "cache_enabled": "Cache aktivieren", + "cache_enabled_desc": "DNS-Antworten lokal speichern.", "cache_size": "Größe des Cache", + "cache_size_validation": "Die Cachegröße muss größer als Null sein, wenn diese Option aktiviert ist.", "cache_size_desc": "Größe des DNS-Cache (in Bytes). Um das Caching zu deaktivieren, setzen Sie den Wert auf 0.", "cache_ttl_min_override": "TTL-Minimalwert überschreiben", "cache_ttl_max_override": "TTL-Höchstwert überschreiben", diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index 4b1fec83..11468a15 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -428,9 +428,9 @@ "encryption_hostnames": "Nombres de hosts", "encryption_reset": "¿Estás seguro de que deseas restablecer la configuración de cifrado?", "encryption_warning": "Advertencia", - "encryption_plain_dns_enable": "Activar DNS simple (sin cifrado)", - "encryption_plain_dns_desc": "El DNS simple (sin cifrado) está activado de forma predeterminada. Puedes desactivarlo para obligar a todos los dispositivos a utilizar DNS cifrado. Para ello, debes habilitar al menos un protocolo DNS cifrado", - "encryption_plain_dns_error": "Para desactivar el DNS simple, activa al menos un protocolo DNS cifrado", + "encryption_plain_dns_enable": "Habilitar DNS simple", + "encryption_plain_dns_desc": "El DNS simple está habilitado de manera predeterminada. Puedes deshabilitarlo para obligar a todos los dispositivos a utilizar DNS cifrado. Para ello, debe habilitar al menos un protocolo DNS cifrado", + "encryption_plain_dns_error": "Para deshabilitar el DNS simple, habilita al menos un protocolo DNS cifrado", "topline_expiring_certificate": "Tu certificado SSL está a punto de expirar. Actualiza la <0>configuración de cifrado.", "topline_expired_certificate": "Tu certificado SSL ha expirado. Actualiza la <0>configuración de cifrado.", "form_error_port_range": "Ingresa el número del puerto en el rango de 80 a 65535", @@ -655,8 +655,11 @@ "safe_search": "Búsqueda segura", "blocklist": "Lista de bloqueo", "milliseconds_abbreviation": "ms", + "cache_enabled": "Activar caché", + "cache_enabled_desc": "Almacene las respuestas de DNS localmente.", "cache_size": "Tamaño de la caché", - "cache_size_desc": "Tamaño de la caché DNS (en bytes). Para desactivar el almacenamiento en caché, configúralo en 0.", + "cache_size_validation": "El tamaño de la cache debe ser mayor que cero cuando está habilitado.", + "cache_size_desc": "Tamaño de la caché DNS (en bytes). Para deshabilitar el almacenamiento en caché, establécelo en 0.", "cache_ttl_min_override": "Anular TTL mínimo", "cache_ttl_max_override": "Anular TTL máximo", "enter_cache_size": "Ingresa el tamaño de la caché (bytes)", diff --git a/client/src/__locales/fr.json b/client/src/__locales/fr.json index 92f7afba..01475bad 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -655,7 +655,10 @@ "safe_search": "Recherche Sécurisée", "blocklist": "Liste de blocage", "milliseconds_abbreviation": "ms", + "cache_enabled": "Activer le cache", + "cache_enabled_desc": "Stockez les réponses DNS localement.", "cache_size": "Taille du cache", + "cache_size_validation": "La taille du cache doit être supérieure à zéro lorsqu'elle est activée.", "cache_size_desc": "Taille du cache DNS (en octets). Pour désactiver la mise en cache, mettez la valeur sur 0.", "cache_ttl_min_override": "Remplacer le TTL minimum", "cache_ttl_max_override": "Remplacer le TTL maximum", diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index 1f591b70..7d9fb128 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -655,7 +655,10 @@ "safe_search": "Ricerca Sicura", "blocklist": "Lista nera", "milliseconds_abbreviation": "ms", + "cache_enabled": "Abilita la cache", + "cache_enabled_desc": "Memorizza localmente le risposte DNS.", "cache_size": "Dimensioni cache", + "cache_size_validation": "La dimensione della cache deve essere maggiore di zero quando abilitata.", "cache_size_desc": "Dimensione della memoria temporanea DNS (in byte). Per disabilitare la memoria temporanea, impostare a 0.", "cache_ttl_min_override": "Sovrascrivi TTL minimo", "cache_ttl_max_override": "Sovrascrivi TTL massimo", diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index 2c679a8d..56174cfa 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -655,7 +655,10 @@ "safe_search": "セーフサーチ", "blocklist": "ブロックリスト", "milliseconds_abbreviation": "ms", + "cache_enabled": "キャッシュを有効にする", + "cache_enabled_desc": "DNSレスポンスをローカルに保存します。", "cache_size": "キャッシュサイズ", + "cache_size_validation": "キャッシュが有効の場合、キャッシュサイズはゼロより大きい値でなければなりません", "cache_size_desc": "DNSキャッシュサイズ(バイト単位)※キャッシュを無効化するには、「0」(ゼロ)にしてください。", "cache_ttl_min_override": "最小TTLの上書き(秒単位)", "cache_ttl_max_override": "最大TTLの上書き(秒単位)", diff --git a/client/src/__locales/ko.json b/client/src/__locales/ko.json index d4f1cb10..159eda48 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -655,7 +655,10 @@ "safe_search": "세이프서치", "blocklist": "차단 목록", "milliseconds_abbreviation": "ms", + "cache_enabled": "캐시 활성화", + "cache_enabled_desc": "DNS 응답을 로컬에 저장합니다.", "cache_size": "캐시 크기", + "cache_size_validation": "활성화된 경우 캐시 크기는 0보다 커야 합니다.", "cache_size_desc": "DNS 캐시 크기(바이트). 캐싱을 사용하지 않으려면 0으로 설정합니다.", "cache_ttl_min_override": "최소 TTL (초) 무시", "cache_ttl_max_override": "최대 TTL (초) 무시", diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 558e9dd4..a49baf0d 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -655,7 +655,10 @@ "safe_search": "Veilig zoeken", "blocklist": "Blokkeerlijst", "milliseconds_abbreviation": "ms", + "cache_enabled": "Cache inschakelen", + "cache_enabled_desc": "DNS-antwoorden lokaal opslaan.", "cache_size": "Cache grootte", + "cache_size_validation": "De cachegrootte moet groter zijn dan nul wanneer deze is ingeschakeld.", "cache_size_desc": "DNS-cachegrootte (in bytes). Om caching uit te schakelen, stel deze in op 0.", "cache_ttl_min_override": "Minimale TTL overschrijven", "cache_ttl_max_override": "Maximale TTL overschrijven", diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index 78203501..43e1f482 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -655,7 +655,10 @@ "safe_search": "Pesquisa segura", "blocklist": "Lista de bloqueio", "milliseconds_abbreviation": "ms", + "cache_enabled": "Ativar cache", + "cache_enabled_desc": "Armazenar as respostas DNS localmente.", "cache_size": "Tamanho do cache", + "cache_size_validation": "O tamanho do cache deve ser maior que zero quando ativado.", "cache_size_desc": "Tamanho do cache do DNS (em bytes). Para desativar o cache, defina como 0.", "cache_ttl_min_override": "Sobrepor o TTL mínimo", "cache_ttl_max_override": "Sobrepor o TTL máximo", diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index a4e9bcc4..9aa47f44 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -655,7 +655,10 @@ "safe_search": "Pesquisa segura", "blocklist": "Lista de bloqueio", "milliseconds_abbreviation": "ms", + "cache_enabled": "Ativar cache", + "cache_enabled_desc": "Armazene as respostas DNS localmente.", "cache_size": "Tamanho do cache", + "cache_size_validation": "O tamanho do cache deve ser maior que zero quando ativado.", "cache_size_desc": "Tamanho do cache DNS (em bytes). Para desativar o cache, defina como 0.", "cache_ttl_min_override": "Sobrepor o TTL mínimo", "cache_ttl_max_override": "Sobrepor o TTL máximo", diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 81568339..85715714 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -655,7 +655,10 @@ "safe_search": "Безопасный поиск", "blocklist": "Чёрный список", "milliseconds_abbreviation": "мс", + "cache_enabled": "Включить кеш", + "cache_enabled_desc": "Сохранять локально ответы DNS.", "cache_size": "Размер кеша", + "cache_size_validation": "Если кеш включен, его размер должен быть больше нуля.", "cache_size_desc": "Размер кеша DNS (в байтах). Чтобы отключить кеширование, установите значение 0.", "cache_ttl_min_override": "Переопределить минимальный TTL", "cache_ttl_max_override": "Переопределить максимальный TTL", diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index 1ba33318..0484565e 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -655,7 +655,10 @@ "safe_search": "Bezpečné vyhľadávanie", "blocklist": "Zoznam blokovaní", "milliseconds_abbreviation": "ms", + "cache_enabled": "Povoliť vyrovnávaciu pamäť", + "cache_enabled_desc": "Ukladať DNS odpovede lokálne.", "cache_size": "Veľkosť cache", + "cache_size_validation": "Veľkosť vyrovnávacej pamäte musí byť po povolení väčšia ako nula.", "cache_size_desc": "Veľkosť vyrovnávacej pamäte DNS (v bajtoch). Ak chcete vypnúť ukladanie do vyrovnávacej pamäte, nastavte hodnotu 0.", "cache_ttl_min_override": "Prepísať minimálne TTL", "cache_ttl_max_override": "Prepísať maximálne TTL", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index ea2e92e0..97ae1c9c 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -655,7 +655,10 @@ "safe_search": "Güvenli Arama", "blocklist": "Engel listesi", "milliseconds_abbreviation": "ms", + "cache_enabled": "Önbelleği etkinleştir", + "cache_enabled_desc": "DNS yanıtlarını yerel olarak depolayın.", "cache_size": "Önbellek boyutu", + "cache_size_validation": "Etkinleştirildiğinde önbellek boyutu sıfırdan büyük olmalıdır.", "cache_size_desc": "DNS önbellek boyutu (bayt cinsinden). Önbelleği devre dışı bırakmak için 0 olarak ayarlayın.", "cache_ttl_min_override": "En az kullanım süresini geçersiz kıl", "cache_ttl_max_override": "En fazla kullanım süresini geçersiz kıl", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index 68ddf586..c2d50561 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -655,7 +655,10 @@ "safe_search": "安全搜索", "blocklist": "黑名单", "milliseconds_abbreviation": "毫秒", + "cache_enabled": "启用缓存", + "cache_enabled_desc": "在本地存储 DNS 响应。", "cache_size": "缓存大小", + "cache_size_validation": "启用时,缓存大小必须大于 0。", "cache_size_desc": "DNS 缓存大小(单位:字节)。若要禁用缓存,请设置为 0。", "cache_ttl_min_override": "覆盖最小 TTL 值", "cache_ttl_max_override": "覆盖最大 TTL 值", diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 3b3e0fed..11a9cf6b 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -655,7 +655,10 @@ "safe_search": "安全搜尋", "blocklist": "封鎖清單", "milliseconds_abbreviation": "ms", + "cache_enabled": "啟用快取", + "cache_enabled_desc": "在本機儲存 DNS 回應。", "cache_size": "快取大小", + "cache_size_validation": "啟用時,快取大小必須大於 0。", "cache_size_desc": "DNS 快取大小(位元組)。若要停用快取,請設為 0。", "cache_ttl_min_override": "覆寫最小的存活時間(TTL)", "cache_ttl_max_override": "覆寫最大的存活時間(TTL)", diff --git a/client_v2/package-lock.json b/client_v2/package-lock.json index 586a954f..1748543b 100644 --- a/client_v2/package-lock.json +++ b/client_v2/package-lock.json @@ -16192,6 +16192,21 @@ } } }, + "node_modules/vite-node/node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/vitest": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", @@ -16395,6 +16410,21 @@ } } }, + "node_modules/vitest/node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", diff --git a/client_v2/src/common/ui/Footer/Footer.tsx b/client_v2/src/common/ui/Footer/Footer.tsx index 87ba62c8..37046ea5 100644 --- a/client_v2/src/common/ui/Footer/Footer.tsx +++ b/client_v2/src/common/ui/Footer/Footer.tsx @@ -157,7 +157,10 @@ export const Footer = () => { className={cn(theme.dropdown.item, { [theme.dropdown.item_active]: currentLanguage === lang, })} - onClick={() => changeLanguage(lang as LocalesType)}> + onClick={() => { + changeLanguage(lang as LocalesType); + setLangDropdownOpen(false); + }}> {LANGUAGES[lang]} ))} diff --git a/client_v2/src/common/ui/Footer/styles.module.pcss b/client_v2/src/common/ui/Footer/styles.module.pcss index 634d2398..28514b92 100644 --- a/client_v2/src/common/ui/Footer/styles.module.pcss +++ b/client_v2/src/common/ui/Footer/styles.module.pcss @@ -24,6 +24,7 @@ .links { display: flex; flex-wrap: wrap; + justify-content: center; gap: 16px; @media (min-width: 1024px) { diff --git a/client_v2/src/components/App/index.tsx b/client_v2/src/components/App/index.tsx index ccf42c0b..06c8e535 100644 --- a/client_v2/src/components/App/index.tsx +++ b/client_v2/src/components/App/index.tsx @@ -11,6 +11,7 @@ import { Settings } from 'panel/components/Settings'; import { LocalesType } from 'panel/common/intl'; import { Encryption } from 'panel/components/Encryption'; +import { LOCAL_STORAGE_KEYS, LocalStorageHelper } from 'panel/helpers/localStorageHelper'; import Toasts from '../Toasts'; import i18n from '../../i18n'; import { THEMES } from '../../helpers/constants'; @@ -67,6 +68,7 @@ const App = () => { if (language) { i18n.changeLanguage(language); setHtmlLangAttr(language); + LocalStorageHelper.setItem(LOCAL_STORAGE_KEYS.LANGUAGE, language); } } diff --git a/client_v2/src/components/Settings/SettingsGroup/RadioGroup.tsx b/client_v2/src/components/Settings/SettingsGroup/RadioGroup.tsx new file mode 100644 index 00000000..2c8f6520 --- /dev/null +++ b/client_v2/src/components/Settings/SettingsGroup/RadioGroup.tsx @@ -0,0 +1,50 @@ +import React, { ReactNode } from 'react'; +import cn from 'clsx'; + +import { Radio } from 'panel/common/controls/Radio'; +import theme from 'panel/lib/theme'; + +import s from './styles.module.pcss'; + +type Option = { text: string; value: T }; + +type Props = { + title: string; + description?: string; + disabled?: boolean; + value: T; + options: Option[]; + onChange: (value: T) => void; + className?: string; + children?: ReactNode; + name?: string; +}; + +export const RadioGroup = ({ + title, + description, + disabled, + value, + options, + onChange, + className, + children, + name, +}: Props) => { + return ( +
+
+
+
{title}
+ {description &&
{description}
} +
+
+
+ +
+ disabled={disabled} value={value} options={options} handleChange={onChange} name={name} /> + {children} +
+
+ ); +}; diff --git a/client_v2/src/components/Settings/SettingsGroup/SwitchGroup.tsx b/client_v2/src/components/Settings/SettingsGroup/SwitchGroup.tsx new file mode 100644 index 00000000..56a3350f --- /dev/null +++ b/client_v2/src/components/Settings/SettingsGroup/SwitchGroup.tsx @@ -0,0 +1,46 @@ +import React, { ReactNode, useRef } from 'react'; +import cn from 'clsx'; + +import { Switch } from 'panel/common/controls/Switch'; +import theme from 'panel/lib/theme'; + +import s from './styles.module.pcss'; + +type Props = { + title: string; + description?: string; + id: string; + className?: string; + checked: boolean; + onChange: (e: React.ChangeEvent) => void; + disabled?: boolean; + children?: ReactNode; +}; + +export const SwitchGroup = ({ title, description, id, className, checked, onChange, disabled, children }: Props) => { + const inputRef = useRef(null); + + const handleRowClick = () => { + if (disabled || !inputRef.current) { + return; + } + + inputRef.current?.click(); + }; + + return ( +
+
+
+
{title}
+ {description &&
{description}
} +
+
e.stopPropagation()}> + +
+
+ + {children &&
{children}
} +
+ ); +}; diff --git a/client_v2/src/components/Settings/SettingsGroup/index.ts b/client_v2/src/components/Settings/SettingsGroup/index.ts new file mode 100644 index 00000000..b1ed7a80 --- /dev/null +++ b/client_v2/src/components/Settings/SettingsGroup/index.ts @@ -0,0 +1,2 @@ +export { RadioGroup } from './RadioGroup'; +export { SwitchGroup } from './SwitchGroup'; diff --git a/client_v2/src/components/Settings/SettingsGroup/styles.module.pcss b/client_v2/src/components/Settings/SettingsGroup/styles.module.pcss new file mode 100644 index 00000000..9739abd8 --- /dev/null +++ b/client_v2/src/components/Settings/SettingsGroup/styles.module.pcss @@ -0,0 +1,40 @@ +.switch { + width: 100%; + padding: 8px 16px; + transition: background-color var(--t2); + border-radius: 8px; + + &:hover, + &:focus { + background-color: var(--fills-backgrounds-page-background-additional); + } +} + +.row { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 24px; + cursor: pointer; + + @media (min-width: 1024px) { + gap: 40px; + } +} + +.text { + padding: 8px 0; +} + +.title { + color: var(--default-main-text); +} + +.desc { + color: var(--default-description-text); +} + +.input, +.content { + padding: 8px 0; +} diff --git a/client_v2/src/lib/theme/Dropdown.module.pcss b/client_v2/src/lib/theme/Dropdown.module.pcss index e02af8ad..e52a5d14 100644 --- a/client_v2/src/lib/theme/Dropdown.module.pcss +++ b/client_v2/src/lib/theme/Dropdown.module.pcss @@ -11,7 +11,7 @@ cursor: default; &_lang { - max-height: 300px; + max-height: 420px; max-width: 100%; overflow: auto; diff --git a/go.mod b/go.mod index a0c6ff7f..24103c3a 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,11 @@ module github.com/AdguardTeam/AdGuardHome -go 1.24.5 +go 1.24.6 require ( github.com/AdguardTeam/dnsproxy v0.76.1 - github.com/AdguardTeam/golibs v0.32.15 + // TODO(s.chzhen): Use osutil/executil and fakeos/fakeexec. + github.com/AdguardTeam/golibs v0.34.0 github.com/AdguardTeam/urlfilter v0.20.0 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.4.0 @@ -32,21 +33,21 @@ require ( github.com/stretchr/testify v1.10.0 github.com/ti-mo/netfilter v0.5.3 go.etcd.io/bbolt v1.4.1 - golang.org/x/crypto v0.39.0 - golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b - golang.org/x/net v0.41.0 - golang.org/x/sys v0.33.0 + golang.org/x/crypto v0.41.0 + golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 + golang.org/x/net v0.43.0 + golang.org/x/sys v0.35.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 howett.net/plist v1.0.1 ) require ( - cloud.google.com/go v0.121.3 // indirect + cloud.google.com/go v0.121.5 // indirect cloud.google.com/go/ai v0.12.1 // indirect - cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go/auth v0.16.4 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.7.0 // indirect + cloud.google.com/go/compute/metadata v0.8.0 // indirect cloud.google.com/go/longrunning v0.6.7 // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/ameshkov/dnsstamps v1.0.3 // indirect @@ -61,7 +62,7 @@ require ( github.com/google/generative-ai-go v0.20.1 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gookit/color v1.5.4 // indirect github.com/gordonklaus/ineffassign v0.1.0 // indirect github.com/josharian/native v1.1.0 // indirect @@ -75,7 +76,7 @@ require ( github.com/quic-go/qpack v0.5.1 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect - github.com/securego/gosec/v2 v2.22.5 // indirect + github.com/securego/gosec/v2 v2.22.8 // indirect github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect github.com/uudashr/gocognit v1.2.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect @@ -86,22 +87,22 @@ require ( go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.uber.org/mock v0.5.2 // indirect - golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b // indirect - golang.org/x/mod v0.25.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20250813145105-42675adae3e6 // indirect + golang.org/x/mod v0.27.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/telemetry v0.0.0-20250708141652-5a6bbb13955f // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/telemetry v0.0.0-20250813145757-41cd51e6ab6a // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.36.0 // indirect golang.org/x/vuln v1.1.4 // indirect gonum.org/v1/gonum v0.16.0 // indirect - google.golang.org/api v0.240.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/grpc v1.73.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect + google.golang.org/api v0.247.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a // indirect + google.golang.org/grpc v1.74.2 // indirect + google.golang.org/protobuf v1.36.7 // indirect honnef.co/go/tools v0.6.1 // indirect mvdan.cc/editorconfig v0.3.0 // indirect mvdan.cc/gofumpt v0.8.0 // indirect diff --git a/go.sum b/go.sum index 942b62ec..580ba09e 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,19 @@ -cloud.google.com/go v0.121.3 h1:84RD+hQXNdY5Sw/MWVAx5O9Aui/rd5VQ9HEcdN19afo= -cloud.google.com/go v0.121.3/go.mod h1:6vWF3nJWRrEUv26mMB3FEIU/o1MQNVPG1iHdisa2SJc= +cloud.google.com/go v0.121.5 h1:KU9tFP5NeZiVDSWcsgjJ2P/HosAlD4fCGBimBlGiNXA= +cloud.google.com/go v0.121.5/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI= cloud.google.com/go/ai v0.12.1 h1:m1n/VjUuHS+pEO/2R4/VbuuEIkgk0w67fDQvFaMngM0= cloud.google.com/go/ai v0.12.1/go.mod h1:5vIPNe1ZQsVZqCliXIPL4QnhObQQY4d9hAGHdVc4iw4= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth v0.16.4 h1:fXOAIQmkApVvcIn7Pc2+5J8QTMVbUGLscnSVNl11su8= +cloud.google.com/go/auth v0.16.4/go.mod h1:j10ncYwjX/g3cdX7GpEzsdM+d+ZNsXAbb6qXA7p1Y5M= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= -cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= -cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= +cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= github.com/AdguardTeam/dnsproxy v0.76.1 h1:ms5vgdbYYXrKGPEpMFqUeql2j3aSfK1tGbCKju9rUgM= github.com/AdguardTeam/dnsproxy v0.76.1/go.mod h1:9Mw3wQMTYwM/HR9FdtatQAd+m0S8mbwq2J+UZiy/gXc= -github.com/AdguardTeam/golibs v0.32.15 h1:arDRDWiZCH3g5Onr8AqMnOHhaOppNoBpgC3DNhmeDeA= -github.com/AdguardTeam/golibs v0.32.15/go.mod h1:G9CzUOzx87J+2u+eClJrrwWD7lMbROvuUnT8uvDUzIA= +github.com/AdguardTeam/golibs v0.34.0 h1:JQK024DkTYxE7vsPVsYsoyDHW/53Nun7OYb9qscniK8= +github.com/AdguardTeam/golibs v0.34.0/go.mod h1:K4C2EbfSEM1zY5YXoti9SfbTAHN/kIX97LpDtCwORrM= github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs= github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= @@ -85,8 +85,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= @@ -128,8 +128,8 @@ github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= -github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= -github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= +github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= +github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= @@ -149,8 +149,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/securego/gosec/v2 v2.22.5 h1:ySws9uwOeE42DsG54v2moaJfh7r08Ev7SAYJuoMDfRA= -github.com/securego/gosec/v2 v2.22.5/go.mod h1:AWfgrFsVewk5LKobsPWlygCHt8K91boVPyL6GUZG5NY= +github.com/securego/gosec/v2 v2.22.8 h1:3NMpmfXO8wAVFZPNsd3EscOTa32Jyo6FLLlW53bexMI= +github.com/securego/gosec/v2 v2.22.8/go.mod h1:ZAw8K2ikuH9qDlfdV87JmNghnVfKB1XC7+TVzk6Utto= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -203,17 +203,17 @@ go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= -golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo= -golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= +golang.org/x/exp/typeparams v0.0.0-20250813145105-42675adae3e6 h1:zAfbUfwhYzU4abt1UJxExk7WVbeTsYEnOPySl6RVucI= +golang.org/x/exp/typeparams v0.0.0-20250813145105-42675adae3e6/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -221,14 +221,14 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -240,25 +240,29 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/telemetry v0.0.0-20250708141652-5a6bbb13955f h1:GnwFSf1cKD9qa+VRJWGjDBK0OHWJgTMaj49bSkN3agw= -golang.org/x/telemetry v0.0.0-20250708141652-5a6bbb13955f/go.mod h1:mUcjA5g0luJpMYCLjhH91f4t4RAUNp+zq9ZmUoqPD7M= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20250813145757-41cd51e6ab6a h1:60aHXv7uIB0ngdMlalCWv6pSC/giLMowErJBA/5xbPQ= +golang.org/x/telemetry v0.0.0-20250813145757-41cd51e6ab6a/go.mod h1:JIJwPkb04vX0KeIBbQ7epGtgIjA8ihHbsAtW4A/lIQ4= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -267,18 +271,18 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU= -google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= -google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= -google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/api v0.247.0 h1:tSd/e0QrUlLsrwMKmkbQhYVa109qIintOls2Wh6bngc= +google.golang.org/api v0.247.0/go.mod h1:r1qZOPmxXffXg6xS5uhx16Fa/UFY8QU/K4bfKrnvovM= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a h1:DMCgtIAIQGZqJXMVzJF4MV8BlWoJh2ZuFiRdAleyr58= +google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a/go.mod h1:y2yVLIE/CSMCPXaHnSKXxu1spLPnglFLegmgdY23uuE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a h1:tPE/Kp+x9dMSwUm/uM0JKK0IfdiJkwAbSMSeZBXXJXc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/aghnet/hostscontainer_internal_test.go b/internal/aghnet/hostscontainer_internal_test.go index 321c3dec..6e718eb4 100644 --- a/internal/aghnet/hostscontainer_internal_test.go +++ b/internal/aghnet/hostscontainer_internal_test.go @@ -7,7 +7,8 @@ import ( "testing/fstest" "github.com/AdguardTeam/golibs/errors" - "github.com/AdguardTeam/golibs/testutil/fakefs" + "github.com/AdguardTeam/golibs/testutil" + "github.com/AdguardTeam/golibs/testutil/fakeio/fakefs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -64,7 +65,7 @@ func TestHostsContainer_PathsToPatterns(t *testing.T) { const errStat errors.Error = "bad file" badFS := &fakefs.StatFS{ - OnOpen: func(_ string) (f fs.File, err error) { panic("not implemented") }, + OnOpen: func(s string) (f fs.File, err error) { panic(testutil.UnexpectedCall(s)) }, OnStat: func(name string) (fi fs.FileInfo, err error) { return nil, errStat }, diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index b86e95ca..47562f2e 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -68,7 +68,9 @@ func TestNewHostsContainer(t *testing.T) { } hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{ - OnStart: func(_ context.Context) (_ error) { panic("not implemented") }, + OnStart: func(ctx context.Context) (_ error) { + panic(testutil.UnexpectedCall(ctx)) + }, OnEvents: onEvents, OnAdd: onAdd, OnShutdown: func(_ context.Context) (err error) { return nil }, @@ -95,10 +97,12 @@ func TestNewHostsContainer(t *testing.T) { t.Run("nil_fs", func(t *testing.T) { require.Panics(t, func() { _, _ = aghnet.NewHostsContainer(nil, &aghtest.FSWatcher{ - OnStart: func(_ context.Context) (_ error) { panic("not implemented") }, + OnStart: func(ctx context.Context) (_ error) { + panic(testutil.UnexpectedCall(ctx)) + }, // Those shouldn't panic. OnEvents: func() (e <-chan struct{}) { return nil }, - OnAdd: func(name string) (err error) { return nil }, + OnAdd: func(_ string) (err error) { return nil }, OnShutdown: func(_ context.Context) (err error) { return nil }, }, p) }) @@ -114,9 +118,9 @@ func TestNewHostsContainer(t *testing.T) { const errOnAdd errors.Error = "error" errWatcher := &aghtest.FSWatcher{ - OnStart: func(_ context.Context) (_ error) { panic("not implemented") }, - OnEvents: func() (e <-chan struct{}) { panic("not implemented") }, - OnAdd: func(name string) (err error) { return errOnAdd }, + OnStart: func(ctx context.Context) (_ error) { panic(testutil.UnexpectedCall(ctx)) }, + OnEvents: func() (_ <-chan struct{}) { panic(testutil.UnexpectedCall()) }, + OnAdd: func(_ string) (err error) { return errOnAdd }, OnShutdown: func(_ context.Context) (err error) { return nil }, } @@ -159,7 +163,7 @@ func TestHostsContainer_refresh(t *testing.T) { t.Cleanup(func() { close(eventsCh) }) w := &aghtest.FSWatcher{ - OnStart: func(_ context.Context) (_ error) { panic("not implemented") }, + OnStart: func(ctx context.Context) (_ error) { panic(testutil.UnexpectedCall(ctx)) }, OnEvents: func() (e <-chan event) { return eventsCh }, OnAdd: func(name string) (err error) { assert.Equal(t, "dir", name) diff --git a/internal/aghnet/net_darwin_internal_test.go b/internal/aghnet/net_darwin_internal_test.go index 7593a969..2b7375df 100644 --- a/internal/aghnet/net_darwin_internal_test.go +++ b/internal/aghnet/net_darwin_internal_test.go @@ -9,7 +9,7 @@ import ( "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/testutil" - "github.com/AdguardTeam/golibs/testutil/fakefs" + "github.com/AdguardTeam/golibs/testutil/fakeio/fakefs" "github.com/stretchr/testify/assert" ) @@ -121,7 +121,7 @@ func TestIfaceSetStaticIP(t *testing.T) { }, } panicFsys := &fakefs.FS{ - OnOpen: func(name string) (fs.File, error) { panic("not implemented") }, + OnOpen: func(name string) (_ fs.File, _ error) { panic(testutil.UnexpectedCall(name)) }, } testCases := []struct { diff --git a/internal/aghnet/net_internal_test.go b/internal/aghnet/net_internal_test.go index 6b5dc392..becf67be 100644 --- a/internal/aghnet/net_internal_test.go +++ b/internal/aghnet/net_internal_test.go @@ -19,11 +19,11 @@ import ( // substRootDirFS replaces the aghos.RootDirFS function used throughout the // package with fsys for tests ran under t. -func substRootDirFS(t testing.TB, fsys fs.FS) { - t.Helper() +func substRootDirFS(tb testing.TB, fsys fs.FS) { + tb.Helper() prev := rootDirFS - t.Cleanup(func() { rootDirFS = prev }) + tb.Cleanup(func() { rootDirFS = prev }) rootDirFS = fsys } @@ -32,11 +32,11 @@ type RunCmdFunc func(cmd string, args ...string) (code int, out []byte, err erro // substShell replaces the the aghos.RunCommand function used throughout the // package with rc for tests ran under t. -func substShell(t testing.TB, rc RunCmdFunc) { - t.Helper() +func substShell(tb testing.TB, rc RunCmdFunc) { + tb.Helper() prev := aghosRunCommand - t.Cleanup(func() { aghosRunCommand = prev }) + tb.Cleanup(func() { aghosRunCommand = prev }) aghosRunCommand = rc } @@ -72,11 +72,11 @@ type ifaceAddrsFunc func() (ifaces []net.Addr, err error) // substNetInterfaceAddrs replaces the the net.InterfaceAddrs function used // throughout the package with f for tests ran under t. -func substNetInterfaceAddrs(t *testing.T, f ifaceAddrsFunc) { - t.Helper() +func substNetInterfaceAddrs(tb testing.TB, f ifaceAddrsFunc) { + tb.Helper() prev := netInterfaceAddrs - t.Cleanup(func() { netInterfaceAddrs = prev }) + tb.Cleanup(func() { netInterfaceAddrs = prev }) netInterfaceAddrs = f } diff --git a/internal/aghrenameio/renameio_test.go b/internal/aghrenameio/renameio_test.go index 2fdc2cdb..f33e3433 100644 --- a/internal/aghrenameio/renameio_test.go +++ b/internal/aghrenameio/renameio_test.go @@ -43,14 +43,14 @@ func TestPendingFile(t *testing.T) { // newInitialFile is a test helper that returns the path to the file containing // [initialData]. -func newInitialFile(t *testing.T) (targetPath string) { - t.Helper() +func newInitialFile(tb testing.TB) (targetPath string) { + tb.Helper() - dir := t.TempDir() + dir := tb.TempDir() targetPath = filepath.Join(dir, "target") err := os.WriteFile(targetPath, initialData, 0o644) - require.NoError(t, err) + require.NoError(tb, err) return targetPath } diff --git a/internal/aghtest/aghtest.go b/internal/aghtest/aghtest.go index fcf62be4..333971df 100644 --- a/internal/aghtest/aghtest.go +++ b/internal/aghtest/aghtest.go @@ -34,16 +34,16 @@ func HostToIPs(host string) (ipv4, ipv6 netip.Addr) { // StartHTTPServer is a helper that starts the HTTP server, which is configured // to return data on every request, and returns the client and server URL. -func StartHTTPServer(t testing.TB, data []byte) (c *http.Client, u *url.URL) { - t.Helper() +func StartHTTPServer(tb testing.TB, data []byte) (c *http.Client, u *url.URL) { + tb.Helper() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write(data) })) - t.Cleanup(srv.Close) + tb.Cleanup(srv.Close) u, err := url.Parse(srv.URL) - require.NoError(t, err) + require.NoError(tb, err) return srv.Client(), u } @@ -55,8 +55,8 @@ const testTimeout = 1 * time.Second // StartLocalhostUpstream is a test helper that starts a DNS server on // localhost. -func StartLocalhostUpstream(t *testing.T, h dns.Handler) (addr *url.URL) { - t.Helper() +func StartLocalhostUpstream(tb *testing.T, h dns.Handler) (addr *url.URL) { + tb.Helper() startCh := make(chan netip.AddrPort) defer close(startCh) @@ -83,12 +83,12 @@ func StartLocalhostUpstream(t *testing.T, h dns.Handler) (addr *url.URL) { Host: addrPort.String(), } - testutil.CleanupAndRequireSuccess(t, func() (err error) { return <-errCh }) - testutil.CleanupAndRequireSuccess(t, srv.Shutdown) + testutil.CleanupAndRequireSuccess(tb, func() (err error) { return <-errCh }) + testutil.CleanupAndRequireSuccess(tb, srv.Shutdown) case err := <-errCh: - require.NoError(t, err) + require.NoError(tb, err) case <-time.After(testTimeout): - require.FailNow(t, "timeout exceeded") + require.FailNow(tb, "timeout exceeded") } return addr diff --git a/internal/aghtest/interface.go b/internal/aghtest/interface.go index 17385a15..734c3a61 100644 --- a/internal/aghtest/interface.go +++ b/internal/aghtest/interface.go @@ -2,7 +2,6 @@ package aghtest import ( "context" - "net" "net/netip" "time" @@ -15,14 +14,6 @@ import ( "github.com/miekg/dns" ) -// Interface Mocks -// -// Keep entities in this file in alphabetic order. - -// Module adguard-home - -// Package aghos - // FSWatcher is a fake [aghos.FSWatcher] implementation for tests. type FSWatcher struct { OnStart func(ctx context.Context) (err error) @@ -54,8 +45,6 @@ func (w *FSWatcher) Add(name string) (err error) { return w.OnAdd(name) } -// Package nextagh - // ServiceWithConfig is a fake [nextagh.ServiceWithConfig] implementation for // tests. type ServiceWithConfig[ConfigType any] struct { @@ -85,8 +74,6 @@ func (s *ServiceWithConfig[ConfigType]) Config() (c ConfigType) { return s.OnConfig() } -// Package client - // AddressProcessor is a fake [client.AddressProcessor] implementation for // tests. type AddressProcessor struct { @@ -122,20 +109,6 @@ func (p *AddressUpdater) UpdateAddress( p.OnUpdateAddress(ctx, ip, host, info) } -// Package filtering - -// Resolver is a fake [filtering.Resolver] implementation for tests. -type Resolver struct { - OnLookupIP func(ctx context.Context, network, host string) (ips []net.IP, err error) -} - -// LookupIP implements the [filtering.Resolver] interface for *Resolver. -func (r *Resolver) LookupIP(ctx context.Context, network, host string) (ips []net.IP, err error) { - return r.OnLookupIP(ctx, network, host) -} - -// Package rdns - // Exchanger is a fake [rdns.Exchanger] implementation for tests. type Exchanger struct { OnExchange func(ip netip.Addr) (host string, ttl time.Duration, err error) @@ -149,10 +122,6 @@ func (e *Exchanger) Exchange(ip netip.Addr) (host string, ttl time.Duration, err return e.OnExchange(ip) } -// Module dnsproxy - -// Package upstream - // UpstreamMock is a fake [upstream.Upstream] implementation for tests. // // TODO(a.garipov): Replace with all uses of Upstream with UpstreamMock and diff --git a/internal/aghtest/interface_test.go b/internal/aghtest/interface_test.go index 93866c2b..fbddcf05 100644 --- a/internal/aghtest/interface_test.go +++ b/internal/aghtest/interface_test.go @@ -3,20 +3,12 @@ package aghtest_test import ( "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/client" - "github.com/AdguardTeam/AdGuardHome/internal/filtering" ) -// Put interface checks that cause import cycles here. - -// type check -var _ filtering.Resolver = (*aghtest.Resolver)(nil) - // type check // -// TODO(s.chzhen): It's here to avoid the import cycle. Remove it. -var _ client.AddressProcessor = (*aghtest.AddressProcessor)(nil) - -// type check -// -// TODO(s.chzhen): It's here to avoid the import cycle. Remove it. -var _ client.AddressUpdater = (*aghtest.AddressUpdater)(nil) +// TODO(s.chzhen): Resolve the import cycles and move it to aghtest. +var ( + _ client.AddressProcessor = (*aghtest.AddressProcessor)(nil) + _ client.AddressUpdater = (*aghtest.AddressUpdater)(nil) +) diff --git a/internal/aghtest/upstream.go b/internal/aghtest/upstream.go index be6bbdbe..598fe802 100644 --- a/internal/aghtest/upstream.go +++ b/internal/aghtest/upstream.go @@ -220,7 +220,7 @@ func NewErrorUpstream() (u *UpstreamMock) { return &UpstreamMock{ OnAddress: func() (addr string) { return "error.upstream.example" }, OnExchange: func(_ *dns.Msg) (resp *dns.Msg, err error) { - return nil, errors.Error("test upstream error") + return nil, ErrUpstream }, OnClose: func() (err error) { return nil }, } diff --git a/internal/arpdb/arpdb_internal_test.go b/internal/arpdb/arpdb_internal_test.go index 50cd6661..39dc666e 100644 --- a/internal/arpdb/arpdb_internal_test.go +++ b/internal/arpdb/arpdb_internal_test.go @@ -24,12 +24,12 @@ var testdata fs.FS = os.DirFS("./testdata") type RunCmdFunc func(cmd string, args ...string) (code int, out []byte, err error) // substShell replaces the the aghos.RunCommand function used throughout the -// package with rc for tests ran under t. -func substShell(t testing.TB, rc RunCmdFunc) { - t.Helper() +// package with rc for tests ran under tb. +func substShell(tb testing.TB, rc RunCmdFunc) { + tb.Helper() prev := aghosRunCommand - t.Cleanup(func() { aghosRunCommand = prev }) + tb.Cleanup(func() { aghosRunCommand = prev }) aghosRunCommand = rc } diff --git a/internal/client/storage_test.go b/internal/client/storage_test.go index f7d95715..658163b8 100644 --- a/internal/client/storage_test.go +++ b/internal/client/storage_test.go @@ -1208,12 +1208,8 @@ func TestStorage_CustomUpstreamConfig(t *testing.T) { } dhcp := &testDHCP{ - OnLeases: func() (ls []*dhcpsvc.Lease) { - panic("not implemented") - }, - OnHostBy: func(ip netip.Addr) (host string) { - panic("not implemented") - }, + OnLeases: func() (_ []*dhcpsvc.Lease) { panic(testutil.UnexpectedCall()) }, + OnHostBy: func(ip netip.Addr) (_ string) { panic(testutil.UnexpectedCall(ip)) }, OnMACBy: func(ip netip.Addr) (mac net.HardwareAddr) { return ipToMAC[ip] }, diff --git a/internal/configmigrate/migrations_internal_test.go b/internal/configmigrate/migrations_internal_test.go index cf681834..d232a375 100644 --- a/internal/configmigrate/migrations_internal_test.go +++ b/internal/configmigrate/migrations_internal_test.go @@ -242,8 +242,8 @@ func TestUpgradeSchema8to9(t *testing.T) { } // assertEqualExcept removes entries from configs and compares them. -func assertEqualExcept(t *testing.T, oldConf, newConf yobj, oldKeys, newKeys []string) { - t.Helper() +func assertEqualExcept(tb testing.TB, oldConf, newConf yobj, oldKeys, newKeys []string) { + tb.Helper() for _, k := range oldKeys { delete(oldConf, k) @@ -252,7 +252,7 @@ func assertEqualExcept(t *testing.T, oldConf, newConf yobj, oldKeys, newKeys []s delete(newConf, k) } - assert.Equal(t, oldConf, newConf) + assert.Equal(tb, oldConf, newConf) } func testDiskConf(schemaVersion int) (diskConf yobj) { diff --git a/internal/configmigrate/migrator_test.go b/internal/configmigrate/migrator_test.go index c684a00e..0694a392 100644 --- a/internal/configmigrate/migrator_test.go +++ b/internal/configmigrate/migrator_test.go @@ -54,6 +54,8 @@ func getField[T any](t require.TestingT, obj any, indexes ...any) (val T) { } func TestMigrateConfig_Migrate(t *testing.T) { + t.Parallel() + const ( inputFileName = "input.yml" outputFileName = "output.yml" @@ -201,6 +203,8 @@ func TestMigrateConfig_Migrate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + t.Parallel() + body, err := fs.ReadFile(testdata, path.Join(t.Name(), inputFileName)) require.NoError(t, err) diff --git a/internal/dhcpd/http_unix_internal_test.go b/internal/dhcpd/http_unix_internal_test.go index 23d11322..7f4c4390 100644 --- a/internal/dhcpd/http_unix_internal_test.go +++ b/internal/dhcpd/http_unix_internal_test.go @@ -34,18 +34,18 @@ func defaultResponse() *dhcpStatusResponse { // handleLease is the helper function that calls handler with provided static // lease as body and returns modified response recorder. -func handleLease(t *testing.T, lease *leaseStatic, handler http.HandlerFunc) (w *httptest.ResponseRecorder) { - t.Helper() +func handleLease(tb testing.TB, lease *leaseStatic, handler http.HandlerFunc) (w *httptest.ResponseRecorder) { + tb.Helper() w = httptest.NewRecorder() b := &bytes.Buffer{} err := json.NewEncoder(b).Encode(lease) - require.NoError(t, err) + require.NoError(tb, err) var r *http.Request r, err = http.NewRequest(http.MethodPost, "", b) - require.NoError(t, err) + require.NoError(tb, err) handler(w, r) diff --git a/internal/dhcpd/v4_unix_internal_test.go b/internal/dhcpd/v4_unix_internal_test.go index 4e0df75b..ae80b5bd 100644 --- a/internal/dhcpd/v4_unix_internal_test.go +++ b/internal/dhcpd/v4_unix_internal_test.go @@ -44,12 +44,12 @@ func defaultV4ServerConf() (conf *V4ServerConf) { // defaultSrv prepares the default DHCPServer to use in tests. The underlying // type of s is *v4Server. -func defaultSrv(t *testing.T) (s DHCPServer) { - t.Helper() +func defaultSrv(tb testing.TB) (s DHCPServer) { + tb.Helper() var err error s, err = v4Create(defaultV4ServerConf()) - require.NoError(t, err) + require.NoError(tb, err) return s } diff --git a/internal/dnsforward/dns64_internal_test.go b/internal/dnsforward/dns64_internal_test.go index 2d2c5471..b730ac3f 100644 --- a/internal/dnsforward/dns64_internal_test.go +++ b/internal/dnsforward/dns64_internal_test.go @@ -27,16 +27,16 @@ const maxDNS64SynTTL uint32 = 600 // newRR is a helper that creates a new dns.RR with the given name, qtype, ttl // and value. It fails the test if the qtype is not supported or the type of // value doesn't match the qtype. -func newRR(t *testing.T, name string, qtype uint16, ttl uint32, val any) (rr dns.RR) { - t.Helper() +func newRR(tb testing.TB, name string, qtype uint16, ttl uint32, val any) (rr dns.RR) { + tb.Helper() switch qtype { case dns.TypeA: - rr = &dns.A{A: testutil.RequireTypeAssert[net.IP](t, val)} + rr = &dns.A{A: testutil.RequireTypeAssert[net.IP](tb, val)} case dns.TypeAAAA: - rr = &dns.AAAA{AAAA: testutil.RequireTypeAssert[net.IP](t, val)} + rr = &dns.AAAA{AAAA: testutil.RequireTypeAssert[net.IP](tb, val)} case dns.TypeCNAME: - rr = &dns.CNAME{Target: testutil.RequireTypeAssert[string](t, val)} + rr = &dns.CNAME{Target: testutil.RequireTypeAssert[string](tb, val)} case dns.TypeSOA: rr = &dns.SOA{ Ns: "ns." + name, @@ -48,9 +48,9 @@ func newRR(t *testing.T, name string, qtype uint16, ttl uint32, val any) (rr dns Minttl: 1, } case dns.TypePTR: - rr = &dns.PTR{Ptr: testutil.RequireTypeAssert[string](t, val)} + rr = &dns.PTR{Ptr: testutil.RequireTypeAssert[string](tb, val)} default: - t.Fatalf("unsupported qtype: %d", qtype) + tb.Fatalf("unsupported qtype: %d", qtype) } *rr.Header() = dns.RR_Header{ @@ -325,7 +325,7 @@ func TestServer_dns64WithDisabledRDNS(t *testing.T) { // Shouldn't go to upstream at all. panicHdlr := dns.HandlerFunc(func(w dns.ResponseWriter, m *dns.Msg) { - panic("not implemented") + panic(testutil.UnexpectedCall(w, m)) }) upsAddr := aghtest.StartLocalhostUpstream(t, panicHdlr).String() localUpsAddr := aghtest.StartLocalhostUpstream(t, panicHdlr).String() diff --git a/internal/dnsforward/dnsforward_internal_test.go b/internal/dnsforward/dnsforward_internal_test.go index e05fa7a0..df63a140 100644 --- a/internal/dnsforward/dnsforward_internal_test.go +++ b/internal/dnsforward/dnsforward_internal_test.go @@ -104,13 +104,16 @@ func (c *clientsContainer) ClearUpstreamCache() { c.OnClearUpstreamCache() } -func startDeferStop(t *testing.T, s *Server) { - t.Helper() +// startDeferStop starts the server and stops it when the test ends. +// +// TODO(e.burkov): Replace with [servicetest.RequireRun]. +func startDeferStop(tb testing.TB, s *Server) { + tb.Helper() - err := s.Start(testutil.ContextWithTimeout(t, testTimeout)) - require.NoError(t, err) - testutil.CleanupAndRequireSuccess(t, func() (err error) { - return s.Stop(testutil.ContextWithTimeout(t, testTimeout)) + err := s.Start(testutil.ContextWithTimeout(tb, testTimeout)) + require.NoError(tb, err) + testutil.CleanupAndRequireSuccess(tb, func() (err error) { + return s.Stop(testutil.ContextWithTimeout(tb, testTimeout)) }) } @@ -130,11 +133,11 @@ func emptyFilteringBlockedServices() (bsvc *filtering.BlockedServices) { // *Server for use in tests, given the provided parameters. It also populates // the filtering configuration with default parameters. func createTestServer( - t *testing.T, + tb testing.TB, filterConf *filtering.Config, forwardConf ServerConfig, ) (s *Server) { - t.Helper() + tb.Helper() filterConf.Logger = cmp.Or(filterConf.Logger, testLogger) @@ -155,14 +158,14 @@ func createTestServer( } f, err := filtering.New(filterConf, filters) - require.NoError(t, err) + require.NoError(tb, err) f.SetEnabled(true) dhcp := &testDHCP{ OnEnabled: func() (ok bool) { return false }, OnHostByIP: func(ip netip.Addr) (host string) { return "" }, - OnIPByHost: func(host string) (ip netip.Addr) { panic("not implemented") }, + OnIPByHost: func(host string) (_ netip.Addr) { panic(testutil.UnexpectedCall(host)) }, } s, err = NewServer(DNSCreateParams{ DHCPServer: dhcp, @@ -170,23 +173,23 @@ func createTestServer( PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), Logger: testLogger, }) - require.NoError(t, err) + require.NoError(tb, err) - err = s.Prepare(testutil.ContextWithTimeout(t, testTimeout), &forwardConf) - require.NoError(t, err) + err = s.Prepare(testutil.ContextWithTimeout(tb, testTimeout), &forwardConf) + require.NoError(tb, err) return s } -func createServerTLSConfig(t *testing.T) (*tls.Config, []byte, []byte) { - t.Helper() +func createServerTLSConfig(tb testing.TB) (*tls.Config, []byte, []byte) { + tb.Helper() privateKey, err := rsa.GenerateKey(rand.Reader, 2048) - require.NoErrorf(t, err, "cannot generate RSA key: %s", err) + require.NoErrorf(tb, err, "cannot generate RSA key: %s", err) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - require.NoErrorf(t, err, "failed to generate serial number: %s", err) + require.NoErrorf(tb, err, "failed to generate serial number: %s", err) notBefore := time.Now() notAfter := notBefore.Add(5 * 365 * timeutil.Day) @@ -207,13 +210,13 @@ func createServerTLSConfig(t *testing.T) (*tls.Config, []byte, []byte) { template.DNSNames = append(template.DNSNames, tlsServerName) derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey) - require.NoErrorf(t, err, "failed to create certificate: %s", err) + require.NoErrorf(tb, err, "failed to create certificate: %s", err) certPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) keyPem := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}) cert, err := tls.X509KeyPair(certPem, keyPem) - require.NoErrorf(t, err, "failed to create certificate: %s", err) + require.NoErrorf(tb, err, "failed to create certificate: %s", err) return &tls.Config{ Certificates: []tls.Certificate{cert}, @@ -222,18 +225,18 @@ func createServerTLSConfig(t *testing.T) (*tls.Config, []byte, []byte) { }, certPem, keyPem } -func createTestTLS(t *testing.T, tlsConf *TLSConfig) (s *Server, certPem []byte) { - t.Helper() +func createTestTLS(tb testing.TB, tlsConf *TLSConfig) (s *Server, certPem []byte) { + tb.Helper() var keyPem []byte - _, certPem, keyPem = createServerTLSConfig(t) + _, certPem, keyPem = createServerTLSConfig(tb) cert, err := tls.X509KeyPair(certPem, keyPem) - require.NoError(t, err) + require.NoError(tb, err) tlsConf.Cert = &cert - s = createTestServer(t, &filtering.Config{ + s = createTestServer(tb, &filtering.Config{ BlockingMode: filtering.BlockingModeDefault, }, ServerConfig{ UDPListenAddrs: []*net.UDPAddr{{}}, @@ -247,8 +250,8 @@ func createTestTLS(t *testing.T, tlsConf *TLSConfig) (s *Server, certPem []byte) ServePlainDNS: true, }) - err = s.Prepare(testutil.ContextWithTimeout(t, testTimeout), &s.conf) - require.NoErrorf(t, err, "failed to prepare server: %s", err) + err = s.Prepare(testutil.ContextWithTimeout(tb, testTimeout), &s.conf) + require.NoErrorf(tb, err, "failed to prepare server: %s", err) return s, certPem } @@ -304,25 +307,27 @@ func newResp(rcode int, req *dns.Msg, ans []dns.RR) (resp *dns.Msg) { return resp } -func assertGoogleAResponse(t *testing.T, reply *dns.Msg) { - assertResponse(t, reply, netip.AddrFrom4([4]byte{8, 8, 8, 8})) +func assertGoogleAResponse(tb testing.TB, reply *dns.Msg) { + tb.Helper() + + assertResponse(tb, reply, netip.AddrFrom4([4]byte{8, 8, 8, 8})) } -func assertResponse(t *testing.T, reply *dns.Msg, ip netip.Addr) { - t.Helper() +func assertResponse(tb testing.TB, reply *dns.Msg, ip netip.Addr) { + tb.Helper() - require.Lenf(t, reply.Answer, 1, "dns server returned reply with wrong number of answers - %d", len(reply.Answer)) + require.Lenf(tb, reply.Answer, 1, "dns server returned reply with wrong number of answers - %d", len(reply.Answer)) a, ok := reply.Answer[0].(*dns.A) - require.Truef(t, ok, "dns server returned wrong answer type instead of A: %v", reply.Answer[0]) - assert.Equal(t, net.IP(ip.AsSlice()), a.A) + require.Truef(tb, ok, "dns server returned wrong answer type instead of A: %v", reply.Answer[0]) + assert.Equal(tb, net.IP(ip.AsSlice()), a.A) } // sendTestMessagesAsync sends messages in parallel to check for race issues. // //lint:ignore U1000 it's called from the function which is skipped for now. -func sendTestMessagesAsync(t *testing.T, conn *dns.Conn) { - t.Helper() +func sendTestMessagesAsync(tb testing.TB, conn *dns.Conn) { + tb.Helper() wg := &sync.WaitGroup{} @@ -334,29 +339,29 @@ func sendTestMessagesAsync(t *testing.T, conn *dns.Conn) { defer wg.Done() err := conn.WriteMsg(msg) - require.NoErrorf(t, err, "cannot write message: %s", err) + require.NoErrorf(tb, err, "cannot write message: %s", err) res, err := conn.ReadMsg() - require.NoErrorf(t, err, "cannot read response to message: %s", err) + require.NoErrorf(tb, err, "cannot read response to message: %s", err) - assertGoogleAResponse(t, res) + assertGoogleAResponse(tb, res) }() } wg.Wait() } -func sendTestMessages(t *testing.T, conn *dns.Conn) { - t.Helper() +func sendTestMessages(tb testing.TB, conn *dns.Conn) { + tb.Helper() for i := range testMessagesCount { req := createGoogleATestMessage() err := conn.WriteMsg(req) - assert.NoErrorf(t, err, "cannot write message #%d: %s", i, err) + assert.NoErrorf(tb, err, "cannot write message #%d: %s", i, err) res, err := conn.ReadMsg() - assert.NoErrorf(t, err, "cannot read response to message #%d: %s", i, err) - assertGoogleAResponse(t, res) + assert.NoErrorf(tb, err, "cannot read response to message #%d: %s", i, err) + assertGoogleAResponse(tb, res) } } @@ -1080,8 +1085,8 @@ func TestBlockedCustomIP(t *testing.T) { dhcp := &testDHCP{ OnEnabled: func() (ok bool) { return false }, - OnHostByIP: func(_ netip.Addr) (host string) { panic("not implemented") }, - OnIPByHost: func(_ string) (ip netip.Addr) { panic("not implemented") }, + OnHostByIP: func(ip netip.Addr) (_ string) { panic(testutil.UnexpectedCall(ip)) }, + OnIPByHost: func(host string) (_ netip.Addr) { panic(testutil.UnexpectedCall(host)) }, } s, err := NewServer(DNSCreateParams{ DHCPServer: dhcp, @@ -1256,8 +1261,8 @@ func TestRewrite(t *testing.T) { dhcp := &testDHCP{ OnEnabled: func() (ok bool) { return false }, - OnHostByIP: func(ip netip.Addr) (host string) { panic("not implemented") }, - OnIPByHost: func(host string) (ip netip.Addr) { panic("not implemented") }, + OnHostByIP: func(ip netip.Addr) (_ string) { panic(testutil.UnexpectedCall(ip)) }, + OnIPByHost: func(host string) (_ netip.Addr) { panic(testutil.UnexpectedCall(host)) }, } s, err := NewServer(DNSCreateParams{ DHCPServer: dhcp, @@ -1392,7 +1397,7 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) { DNSFilter: flt, DHCPServer: &testDHCP{ OnEnabled: func() (ok bool) { return true }, - OnIPByHost: func(host string) (ip netip.Addr) { panic("not implemented") }, + OnIPByHost: func(host string) (_ netip.Addr) { panic(testutil.UnexpectedCall(host)) }, OnHostByIP: func(ip netip.Addr) (host string) { return "myhost" }, @@ -1449,13 +1454,13 @@ func TestPTRResponseFromHosts(t *testing.T) { dhcp := &testDHCP{ OnEnabled: func() (ok bool) { return false }, - OnIPByHost: func(host string) (ip netip.Addr) { panic("not implemented") }, + OnIPByHost: func(host string) (_ netip.Addr) { panic(testutil.UnexpectedCall(host)) }, OnHostByIP: func(ip netip.Addr) (host string) { return "" }, } var eventsCalledCounter uint32 hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{ - OnStart: func(_ context.Context) (_ error) { panic("not implemented") }, + OnStart: func(ctx context.Context) (_ error) { panic(testutil.UnexpectedCall(ctx)) }, OnEvents: func() (e <-chan struct{}) { assert.Equal(t, uint32(1), atomic.AddUint32(&eventsCalledCounter, 1)) @@ -1466,7 +1471,7 @@ func TestPTRResponseFromHosts(t *testing.T) { return nil }, - OnShutdown: func(_ context.Context) (err error) { panic("not implemented") }, + OnShutdown: func(ctx context.Context) (err error) { panic(testutil.UnexpectedCall(ctx)) }, }, hostsFilename) require.NoError(t, err) t.Cleanup(func() { diff --git a/internal/dnsforward/filter_internal_test.go b/internal/dnsforward/filter_internal_test.go index cd6da731..99598dd2 100644 --- a/internal/dnsforward/filter_internal_test.go +++ b/internal/dnsforward/filter_internal_test.go @@ -58,8 +58,8 @@ func TestHandleDNSRequest_handleDNSRequest(t *testing.T) { s, err := NewServer(DNSCreateParams{ DHCPServer: &testDHCP{ OnEnabled: func() (ok bool) { return false }, - OnHostByIP: func(ip netip.Addr) (host string) { panic("not implemented") }, - OnIPByHost: func(host string) (ip netip.Addr) { panic("not implemented") }, + OnHostByIP: func(ip netip.Addr) (_ string) { panic(testutil.UnexpectedCall(ip)) }, + OnIPByHost: func(host string) (_ netip.Addr) { panic(testutil.UnexpectedCall(host)) }, }, DNSFilter: f, PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), diff --git a/internal/dnsforward/http_internal_test.go b/internal/dnsforward/http_internal_test.go index 1353bfdc..2da75e87 100644 --- a/internal/dnsforward/http_internal_test.go +++ b/internal/dnsforward/http_internal_test.go @@ -44,16 +44,18 @@ func (emptySysResolvers) Addrs() (addrs []netip.AddrPort) { return nil } -func loadTestData(t *testing.T, casesFileName string, cases any) { - t.Helper() +// loadTestData loads the test data from the file with the given name into +// cases. +func loadTestData(tb testing.TB, casesFileName string, cases any) { + tb.Helper() var f *os.File f, err := os.Open(filepath.Join("testdata", casesFileName)) - require.NoError(t, err) - testutil.CleanupAndRequireSuccess(t, f.Close) + require.NoError(tb, err) + testutil.CleanupAndRequireSuccess(tb, f.Close) err = json.NewDecoder(f).Decode(cases) - require.NoError(t, err) + require.NoError(tb, err) } const ( @@ -312,14 +314,17 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { } } -func newLocalUpstreamListener(t *testing.T, port uint16, handler dns.Handler) (real netip.AddrPort) { - t.Helper() +// newLocalUpstreamListener creates a local upstream listener and returns its +// address. The listener is started in a separate goroutine and stopped when +// the tb's test is finished. +func newLocalUpstreamListener(tb testing.TB, port uint16, h dns.Handler) (real netip.AddrPort) { + tb.Helper() startCh := make(chan struct{}) upsSrv := &dns.Server{ Addr: netip.AddrPortFrom(netutil.IPv4Localhost(), port).String(), Net: "tcp", - Handler: handler, + Handler: h, NotifyStartedFunc: func() { close(startCh) }, } go func() { @@ -328,9 +333,9 @@ func newLocalUpstreamListener(t *testing.T, port uint16, handler dns.Handler) (r }() <-startCh - testutil.CleanupAndRequireSuccess(t, upsSrv.Shutdown) + testutil.CleanupAndRequireSuccess(tb, upsSrv.Shutdown) - return testutil.RequireTypeAssert[*net.TCPAddr](t, upsSrv.Listener.Addr()).AddrPort() + return testutil.RequireTypeAssert[*net.TCPAddr](tb, upsSrv.Listener.Addr()).AddrPort() } func TestServer_HandleTestUpstreamDNS(t *testing.T) { @@ -364,7 +369,7 @@ func TestServer_HandleTestUpstreamDNS(t *testing.T) { }, }, &aghtest.FSWatcher{ - OnStart: func(_ context.Context) (_ error) { panic("not implemented") }, + OnStart: func(ctx context.Context) (_ error) { panic(testutil.UnexpectedCall(ctx)) }, OnEvents: func() (e <-chan struct{}) { return nil }, OnAdd: func(_ string) (err error) { return nil }, OnShutdown: func(_ context.Context) (err error) { return nil }, @@ -469,10 +474,8 @@ func TestServer_HandleTestUpstreamDNS(t *testing.T) { require.NoError(t, err) require.Contains(t, resp, sleepyUps) - require.IsType(t, "", resp[sleepyUps]) - sleepyRes, _ := resp[sleepyUps].(string) + sleepyRes := testutil.RequireTypeAssert[string](t, resp[sleepyUps]) - // TODO(e.burkov): Improve the format of an error in dnsproxy. assert.True(t, strings.HasSuffix(sleepyRes, "i/o timeout")) }) } diff --git a/internal/dnsforward/process_internal_test.go b/internal/dnsforward/process_internal_test.go index b5c54469..d9b78180 100644 --- a/internal/dnsforward/process_internal_test.go +++ b/internal/dnsforward/process_internal_test.go @@ -94,7 +94,7 @@ func TestServer_ProcessInitial(t *testing.T) { var gotAddr netip.Addr s.addrProc = &aghtest.AddressProcessor{ OnProcess: func(ctx context.Context, ip netip.Addr) { gotAddr = ip }, - OnClose: func() (err error) { panic("not implemented") }, + OnClose: func() (_ error) { panic(testutil.UnexpectedCall()) }, } dctx := &dnsContext{ @@ -373,14 +373,14 @@ func TestServer_ProcessDDRQuery(t *testing.T) { } // createTestDNSFilter returns the minimum valid DNSFilter. -func createTestDNSFilter(t *testing.T) (f *filtering.DNSFilter) { - t.Helper() +func createTestDNSFilter(tb testing.TB) (f *filtering.DNSFilter) { + tb.Helper() f, err := filtering.New(&filtering.Config{ Logger: testLogger, BlockingMode: filtering.BlockingModeDefault, }, []filtering.Filter{}) - require.NoError(t, err) + require.NoError(tb, err) return f } @@ -519,7 +519,7 @@ func TestServer_ProcessDHCPHosts(t *testing.T) { OnIPByHost: func(host string) (ip netip.Addr) { return knownClients[host] }, - OnHostByIP: func(ip netip.Addr) (host string) { panic("not implemented") }, + OnHostByIP: func(ip netip.Addr) (_ string) { panic(testutil.UnexpectedCall(ip)) }, } testCases := []struct { diff --git a/internal/filtering/filter_internal_test.go b/internal/filtering/filter_internal_test.go index c2d0de71..144ec061 100644 --- a/internal/filtering/filter_internal_test.go +++ b/internal/filtering/filter_internal_test.go @@ -22,17 +22,16 @@ const testTimeout = 5 * time.Second // serveHTTPLocally starts a new HTTP server, that handles its index with h. It // also gracefully closes the listener when the test under t finishes. -func serveHTTPLocally(t *testing.T, h http.Handler) (urlStr string) { - t.Helper() +func serveHTTPLocally(tb testing.TB, h http.Handler) (urlStr string) { + tb.Helper() l, err := net.Listen("tcp", ":0") - require.NoError(t, err) + require.NoError(tb, err) go func() { _ = http.Serve(l, h) }() - testutil.CleanupAndRequireSuccess(t, l.Close) + testutil.CleanupAndRequireSuccess(tb, l.Close) - addr := l.Addr() - require.IsType(t, (*net.TCPAddr)(nil), addr) + addr := testutil.RequireTypeAssert[*net.TCPAddr](tb, l.Addr()) return (&url.URL{ Scheme: urlutil.SchemeHTTP, @@ -42,10 +41,10 @@ func serveHTTPLocally(t *testing.T, h http.Handler) (urlStr string) { // serveFiltersLocally is a helper that concurrently listens on a free port to // respond with fltContent. -func serveFiltersLocally(t *testing.T, fltContent []byte) (urlStr string) { - t.Helper() +func serveFiltersLocally(tb testing.TB, fltContent []byte) (urlStr string) { + tb.Helper() - return serveHTTPLocally(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + return serveHTTPLocally(tb, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { pt := testutil.PanicT{} n, werr := w.Write(fltContent) @@ -57,43 +56,43 @@ func serveFiltersLocally(t *testing.T, fltContent []byte) (urlStr string) { // updateAndAssert loads filter content from its URL and then asserts rules // count. func updateAndAssert( - t *testing.T, + tb testing.TB, ctx context.Context, dnsFilter *DNSFilter, f *FilterYAML, wantUpd require.BoolAssertionFunc, wantRulesCount int, ) { - t.Helper() + tb.Helper() ok, err := dnsFilter.update(f) - require.NoError(t, err) - wantUpd(t, ok) + require.NoError(tb, err) + wantUpd(tb, ok) - assert.Equal(t, wantRulesCount, f.RulesCount) + assert.Equal(tb, wantRulesCount, f.RulesCount) dir, err := os.ReadDir(filepath.Join(dnsFilter.conf.DataDir, filterDir)) - require.NoError(t, err) - require.FileExists(t, f.Path(dnsFilter.conf.DataDir)) + require.NoError(tb, err) + require.FileExists(tb, f.Path(dnsFilter.conf.DataDir)) - assert.Len(t, dir, 1) + assert.Len(tb, dir, 1) err = dnsFilter.load(ctx, f) - require.NoError(t, err) + require.NoError(tb, err) } // newDNSFilter returns a new properly initialized DNS filter instance. -func newDNSFilter(t *testing.T) (d *DNSFilter) { - t.Helper() +func newDNSFilter(tb testing.TB) (d *DNSFilter) { + tb.Helper() dnsFilter, err := New(&Config{ Logger: slogutil.NewDiscardLogger(), - DataDir: t.TempDir(), + DataDir: tb.TempDir(), HTTPClient: &http.Client{ Timeout: testTimeout, }, }, nil) - require.NoError(t, err) + require.NoError(tb, err) return dnsFilter } diff --git a/internal/filtering/filtering_internal_test.go b/internal/filtering/filtering_internal_test.go index 5097755c..d5b14aff 100644 --- a/internal/filtering/filtering_internal_test.go +++ b/internal/filtering/filtering_internal_test.go @@ -63,37 +63,37 @@ func newChecker(host string) Checker { }) } -func (d *DNSFilter) checkMatch(t *testing.T, hostname string, setts *Settings) { - t.Helper() +func (d *DNSFilter) checkMatch(tb testing.TB, hostname string, setts *Settings) { + tb.Helper() res, err := d.CheckHost(hostname, dns.TypeA, setts) - require.NoErrorf(t, err, "host %q", hostname) + require.NoErrorf(tb, err, "host %q", hostname) - assert.Truef(t, res.IsFiltered, "host %q", hostname) + assert.Truef(tb, res.IsFiltered, "host %q", hostname) } -func (d *DNSFilter) checkMatchIP(t *testing.T, hostname, ip string, qtype uint16, setts *Settings) { - t.Helper() +func (d *DNSFilter) checkMatchIP(tb testing.TB, hostname, ip string, qtype uint16, setts *Settings) { + tb.Helper() res, err := d.CheckHost(hostname, qtype, setts) - require.NoErrorf(t, err, "host %q", hostname, err) - require.NotEmpty(t, res.Rules, "host %q", hostname) + require.NoErrorf(tb, err, "host %q", hostname, err) + require.NotEmpty(tb, res.Rules, "host %q", hostname) - assert.Truef(t, res.IsFiltered, "host %q", hostname) + assert.Truef(tb, res.IsFiltered, "host %q", hostname) r := res.Rules[0] - require.NotNilf(t, r.IP, "Expected ip %s to match, actual: %v", ip, r.IP) + require.NotNilf(tb, r.IP, "Expected ip %s to match, actual: %v", ip, r.IP) - assert.Equalf(t, ip, r.IP.String(), "host %q", hostname) + assert.Equalf(tb, ip, r.IP.String(), "host %q", hostname) } -func (d *DNSFilter) checkMatchEmpty(t *testing.T, hostname string, setts *Settings) { - t.Helper() +func (d *DNSFilter) checkMatchEmpty(tb testing.TB, hostname string, setts *Settings) { + tb.Helper() res, err := d.CheckHost(hostname, dns.TypeA, setts) - require.NoErrorf(t, err, "host %q", hostname) + require.NoErrorf(tb, err, "host %q", hostname) - assert.Falsef(t, res.IsFiltered, "host %q", hostname) + assert.Falsef(tb, res.IsFiltered, "host %q", hostname) } func TestDNSFilter_CheckHost_hostRules(t *testing.T) { diff --git a/internal/filtering/hosts_test.go b/internal/filtering/hosts_test.go index de93394e..9385314a 100644 --- a/internal/filtering/hosts_test.go +++ b/internal/filtering/hosts_test.go @@ -44,7 +44,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) { }, } watcher := &aghtest.FSWatcher{ - OnStart: func(_ context.Context) (_ error) { panic("not implemented") }, + OnStart: func(ctx context.Context) (_ error) { panic(testutil.UnexpectedCall(ctx)) }, OnEvents: func() (e <-chan struct{}) { return nil }, OnAdd: func(name string) (err error) { return nil }, OnShutdown: func(_ context.Context) (err error) { return nil }, diff --git a/internal/filtering/idgenerator_internal_test.go b/internal/filtering/idgenerator_internal_test.go index e9c0db2f..195e9976 100644 --- a/internal/filtering/idgenerator_internal_test.go +++ b/internal/filtering/idgenerator_internal_test.go @@ -75,13 +75,13 @@ func TestIDGenerator_Fix(t *testing.T) { // assertUniqueIDs is a test helper that asserts that the IDs of filters are // unique. -func assertUniqueIDs(t testing.TB, flts []FilterYAML) { - t.Helper() +func assertUniqueIDs(tb testing.TB, flts []FilterYAML) { + tb.Helper() uc := aghalg.UniqChecker[rulelist.URLFilterID]{} for _, f := range flts { uc.Add(f.ID) } - assert.NoError(t, uc.Validate()) + assert.NoError(tb, uc.Validate()) } diff --git a/internal/filtering/rewritehttp_test.go b/internal/filtering/rewritehttp_test.go index 4448a4c0..4b57c9db 100644 --- a/internal/filtering/rewritehttp_test.go +++ b/internal/filtering/rewritehttp_test.go @@ -209,20 +209,20 @@ func TestDNSFilter_handleRewriteHTTP(t *testing.T) { // assertRewritesList checks if rewrites list equals the list received from the // handler by listURL. -func assertRewritesList(t *testing.T, handler http.Handler, wantList []*rewriteJSON) { - t.Helper() +func assertRewritesList(tb testing.TB, handler http.Handler, wantList []*rewriteJSON) { + tb.Helper() r := httptest.NewRequest(http.MethodGet, listURL, nil) w := httptest.NewRecorder() handler.ServeHTTP(w, r) - require.Equal(t, http.StatusOK, w.Code) + require.Equal(tb, http.StatusOK, w.Code) var actual []*rewriteJSON err := json.NewDecoder(w.Body).Decode(&actual) - require.NoError(t, err) + require.NoError(tb, err) - assert.Equal(t, wantList, actual) + assert.Equal(tb, wantList, actual) } // rewriteEntriesToLegacyRewrites gets legacy rewrites from json entries. diff --git a/internal/filtering/rulelist/rulelist_test.go b/internal/filtering/rulelist/rulelist_test.go index 85a3d362..0e966da2 100644 --- a/internal/filtering/rulelist/rulelist_test.go +++ b/internal/filtering/rulelist/rulelist_test.go @@ -52,8 +52,8 @@ func newURLFilterID() (id rulelist.URLFilterID) { // newFilter is a helper for creating new filters in tests. It does not // register the closing of the filter using t.Cleanup; callers must do that // either directly or by using the filter in an engine. -func newFilter(t testing.TB, u *url.URL, name string) (f *rulelist.Filter) { - t.Helper() +func newFilter(tb testing.TB, u *url.URL, name string) (f *rulelist.Filter) { + tb.Helper() f, err := rulelist.NewFilter(&rulelist.FilterConfig{ URL: u, @@ -62,7 +62,7 @@ func newFilter(t testing.TB, u *url.URL, name string) (f *rulelist.Filter) { URLFilterID: newURLFilterID(), Enabled: true, }) - require.NoError(t, err) + require.NoError(tb, err) return f } @@ -71,24 +71,24 @@ func newFilter(t testing.TB, u *url.URL, name string) (f *rulelist.Filter) { // file and the HTTP-server. It also registers file removal and server stopping // using t.Cleanup. func newFilterLocations( - t testing.TB, + tb testing.TB, cacheDir string, fileData string, httpData string, ) (fileURL, srvURL *url.URL) { - t.Helper() + tb.Helper() f, err := os.CreateTemp(cacheDir, "") - require.NoError(t, err) + require.NoError(tb, err) err = f.Close() - require.NoError(t, err) + require.NoError(tb, err) filePath := f.Name() err = os.WriteFile(filePath, []byte(fileData), 0o644) - require.NoError(t, err) + require.NoError(tb, err) - testutil.CleanupAndRequireSuccess(t, func() (err error) { + testutil.CleanupAndRequireSuccess(tb, func() (err error) { return os.Remove(filePath) }) @@ -98,10 +98,10 @@ func newFilterLocations( } srv := newStringHTTPServer(httpData) - t.Cleanup(srv.Close) + tb.Cleanup(srv.Close) srvURL, err = url.Parse(srv.URL) - require.NoError(t, err) + require.NoError(tb, err) return fileURL, srvURL } diff --git a/internal/home/authhttp_internal_test.go b/internal/home/authhttp_internal_test.go index 8215bd28..ceb13c25 100644 --- a/internal/home/authhttp_internal_test.go +++ b/internal/home/authhttp_internal_test.go @@ -7,7 +7,6 @@ import ( "encoding/binary" "encoding/hex" "encoding/json" - "fmt" "maps" "net/http" "net/http/httptest" @@ -48,20 +47,20 @@ var _ aghuser.SessionStorage = (*testSessionStorage)(nil) // panic. func newTestSessionStorage() (ts *testSessionStorage) { return &testSessionStorage{ - onNew: func(_ context.Context, u *aghuser.User) (_ *aghuser.Session, _ error) { - panic(fmt.Errorf("unexpected call to testSessionStorage.New(%v)", u)) + onNew: func(ctx context.Context, u *aghuser.User) (_ *aghuser.Session, _ error) { + panic(testutil.UnexpectedCall(ctx, u)) }, onFindByToken: func( - _ context.Context, + ctx context.Context, t aghuser.SessionToken, ) (_ *aghuser.Session, err error) { - panic(fmt.Errorf("unexpected call to testSessionStorage.FindByToken(%v)", t)) + panic(testutil.UnexpectedCall(ctx, t)) }, - onDeleteByToken: func(_ context.Context, t aghuser.SessionToken) (_ error) { - panic(fmt.Errorf("unexpected call to testSessionStorage.DeleteByToken(%v)", t)) + onDeleteByToken: func(ctx context.Context, t aghuser.SessionToken) (_ error) { + panic(testutil.UnexpectedCall(ctx, t)) }, onClose: func() (_ error) { - panic("unexpected call to testSessionStorage.Close") + panic(testutil.UnexpectedCall()) }, } } @@ -110,17 +109,17 @@ type testUsersDB struct { // newTestUsersDB returns a new *testUsersDB all methods of which panic. func newTestUsersDB() (ts *testUsersDB) { return &testUsersDB{ - onAll: func(_ context.Context) (_ []*aghuser.User, _ error) { - panic("unexpected call to testUsersDB.All") + onAll: func(ctx context.Context) (_ []*aghuser.User, _ error) { + panic(testutil.UnexpectedCall(ctx)) }, - onByLogin: func(_ context.Context, l aghuser.Login) (_ *aghuser.User, _ error) { - panic(fmt.Errorf("unexpected call to testUsersDB.ByLogin(%v)", l)) + onByLogin: func(ctx context.Context, l aghuser.Login) (_ *aghuser.User, _ error) { + panic(testutil.UnexpectedCall(ctx, l)) }, - onByUUID: func(_ context.Context, id aghuser.UserID) (_ *aghuser.User, _ error) { - panic(fmt.Errorf("unexpected call to testUsersDB.ByUUID(%v)", id)) + onByUUID: func(ctx context.Context, id aghuser.UserID) (_ *aghuser.User, _ error) { + panic(testutil.UnexpectedCall(ctx, id)) }, - onCreate: func(_ context.Context, u *aghuser.User) (_ error) { - panic(fmt.Errorf("unexpected call to testUsersDB.Create(%v)", u)) + onCreate: func(ctx context.Context, u *aghuser.User) (_ error) { + panic(testutil.UnexpectedCall(ctx, u)) }, } } @@ -574,11 +573,11 @@ func TestAuth_ServeHTTP_auth(t *testing.T) { // generateAuthCookie is a helper function that logs in with the provided // credentials and returns the resulting authentication cookie. -func generateAuthCookie(t *testing.T, mux http.Handler, name, password string) (ac *http.Cookie) { - t.Helper() +func generateAuthCookie(tb testing.TB, mux http.Handler, name, password string) (ac *http.Cookie) { + tb.Helper() creds, err := json.Marshal(&loginJSON{Name: name, Password: password}) - require.NoError(t, err) + require.NoError(tb, err) r := httptest.NewRequest(http.MethodPost, "/control/login", bytes.NewReader(creds)) r.Header.Set(httphdr.ContentType, aghhttp.HdrValApplicationJSON) @@ -594,20 +593,20 @@ func generateAuthCookie(t *testing.T, mux http.Handler, name, password string) ( } } - require.NotNil(t, ac) + require.NotNil(tb, ac) return ac } // assertHandlerStatusCode is a helper function that asserts the response status // code of a HTTP handler. -func assertHandlerStatusCode(t *testing.T, h http.Handler, r *http.Request, wantCode int) { - t.Helper() +func assertHandlerStatusCode(tb testing.TB, h http.Handler, r *http.Request, wantCode int) { + tb.Helper() w := httptest.NewRecorder() h.ServeHTTP(w, r) - assert.Equal(t, wantCode, w.Code) + assert.Equal(tb, wantCode, w.Code) } func TestAuth_ServeHTTP_logout(t *testing.T) { diff --git a/internal/home/clients_internal_test.go b/internal/home/clients_internal_test.go index adf84870..69f24315 100644 --- a/internal/home/clients_internal_test.go +++ b/internal/home/clients_internal_test.go @@ -12,12 +12,12 @@ import ( // newClientsContainer is a helper that creates a new clients container for // tests. -func newClientsContainer(t *testing.T) (c *clientsContainer) { - t.Helper() +func newClientsContainer(tb testing.TB) (c *clientsContainer) { + tb.Helper() c = &clientsContainer{} - ctx := testutil.ContextWithTimeout(t, testTimeout) + ctx := testutil.ContextWithTimeout(tb, testTimeout) err := c.Init( ctx, testLogger, @@ -32,7 +32,7 @@ func newClientsContainer(t *testing.T) (c *clientsContainer) { agh.EmptyConfigModifier{}, ) - require.NoError(t, err) + require.NoError(tb, err) return c } diff --git a/internal/home/middlewares_internal_test.go b/internal/home/middlewares_internal_test.go index 0b8d7db3..1d3a6b9c 100644 --- a/internal/home/middlewares_internal_test.go +++ b/internal/home/middlewares_internal_test.go @@ -39,14 +39,14 @@ func TestLimitRequestBody(t *testing.T) { want: []byte(nil), }} - makeHandler := func(t *testing.T, err *error) http.HandlerFunc { - t.Helper() + makeHandler := func(tb testing.TB, err *error) http.HandlerFunc { + tb.Helper() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var b []byte b, *err = io.ReadAll(r.Body) _, werr := w.Write(b) - require.NoError(t, werr) + require.NoError(tb, werr) }) } diff --git a/internal/home/mobileconfig_internal_test.go b/internal/home/mobileconfig_internal_test.go index 86710003..225ca53e 100644 --- a/internal/home/mobileconfig_internal_test.go +++ b/internal/home/mobileconfig_internal_test.go @@ -15,11 +15,11 @@ import ( // setupDNSIPs is a helper that sets up the server IP address configuration for // tests and also tears it down in a cleanup function. -func setupDNSIPs(t testing.TB) { - t.Helper() +func setupDNSIPs(tb testing.TB) { + tb.Helper() prevConfig := config - t.Cleanup(func() { + tb.Cleanup(func() { config = prevConfig }) diff --git a/internal/home/options_internal_test.go b/internal/home/options_internal_test.go index dbcf02cc..9a51aff8 100644 --- a/internal/home/options_internal_test.go +++ b/internal/home/options_internal_test.go @@ -9,26 +9,34 @@ import ( "github.com/stretchr/testify/require" ) -func testParseOK(t *testing.T, ss ...string) options { - t.Helper() +// testParseOK is a helper that parses the command-line options and returns the +// parsed options. +func testParseOK(tb testing.TB, ss ...string) (o options) { + tb.Helper() o, _, err := parseCmdOpts("", ss) - require.NoError(t, err) + require.NoError(tb, err) return o } -func testParseErr(t *testing.T, descr string, ss ...string) { - t.Helper() +// testParseErr is a helper that asserts that parsing the command-line options +// fails with error. +// +// TODO(a.garipov): Search descr within an error. +func testParseErr(tb testing.TB, descr string, ss ...string) { + tb.Helper() _, _, err := parseCmdOpts("", ss) - require.Error(t, err) + require.Errorf(tb, err, "should have got error: %s", descr) } -func testParseParamMissing(t *testing.T, param string) { - t.Helper() +// testParseParamMissing is a helper that asserts that parsing the command-line +// options fails with error due to missing parameter. +func testParseParamMissing(tb testing.TB, param string) { + tb.Helper() - testParseErr(t, fmt.Sprintf("%s parameter missing", param), param) + testParseErr(tb, fmt.Sprintf("%s parameter missing", param), param) } func TestParseVerbose(t *testing.T) { diff --git a/internal/next/websvc/dns_test.go b/internal/next/websvc/dns_test.go index 960bf024..c8362b0e 100644 --- a/internal/next/websvc/dns_test.go +++ b/internal/next/websvc/dns_test.go @@ -17,6 +17,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/next/websvc" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/golibs/netutil/urlutil" + "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -45,7 +46,7 @@ func TestService_HandlePatchSettingsDNS(t *testing.T) { return nil }, - OnShutdown: func(_ context.Context) (err error) { panic("not implemented") }, + OnShutdown: func(ctx context.Context) (_ error) { panic(testutil.UnexpectedCall(ctx)) }, OnConfig: func() (c *dnssvc.Config) { return &dnssvc.Config{} }, } } diff --git a/internal/next/websvc/websvc_test.go b/internal/next/websvc/websvc_test.go index 79e46ac6..979ef21b 100644 --- a/internal/next/websvc/websvc_test.go +++ b/internal/next/websvc/websvc_test.go @@ -19,7 +19,7 @@ import ( "github.com/AdguardTeam/golibs/netutil/httputil" "github.com/AdguardTeam/golibs/netutil/urlutil" "github.com/AdguardTeam/golibs/testutil" - "github.com/AdguardTeam/golibs/testutil/fakefs" + "github.com/AdguardTeam/golibs/testutil/fakeio/fakefs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -65,13 +65,17 @@ func (m *configManager) UpdateWeb(ctx context.Context, c *websvc.Config) (err er // newConfigManager returns a *configManager all methods of which panic. func newConfigManager() (m *configManager) { return &configManager{ - onDNS: func() (svc agh.ServiceWithConfig[*dnssvc.Config]) { panic("not implemented") }, - onWeb: func() (svc agh.ServiceWithConfig[*websvc.Config]) { panic("not implemented") }, - onUpdateDNS: func(_ context.Context, _ *dnssvc.Config) (err error) { - panic("not implemented") + onDNS: func() (_ agh.ServiceWithConfig[*dnssvc.Config]) { + panic(testutil.UnexpectedCall()) }, - onUpdateWeb: func(_ context.Context, _ *websvc.Config) (err error) { - panic("not implemented") + onWeb: func() (_ agh.ServiceWithConfig[*websvc.Config]) { + panic(testutil.UnexpectedCall()) + }, + onUpdateDNS: func(ctx context.Context, c *dnssvc.Config) (_ error) { + panic(testutil.UnexpectedCall(ctx, c)) + }, + onUpdateWeb: func(ctx context.Context, c *websvc.Config) (_ error) { + panic(testutil.UnexpectedCall(ctx, c)) }, } } @@ -80,10 +84,10 @@ func newConfigManager() (m *configManager) { // sole address. It also registers a cleanup procedure, which shuts the // instance down. func newTestServer( - t testing.TB, + tb testing.TB, confMgr websvc.ConfigManager, ) (svc *websvc.Service, addr netip.AddrPort) { - t.Helper() + tb.Helper() c := &websvc.Config{ Logger: slogutil.NewDiscardLogger(), @@ -103,17 +107,17 @@ func newTestServer( } svc, err := websvc.New(c) - require.NoError(t, err) + require.NoError(tb, err) - err = svc.Start(testutil.ContextWithTimeout(t, testTimeout)) - require.NoError(t, err) - testutil.CleanupAndRequireSuccess(t, func() (err error) { - return svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout)) + err = svc.Start(testutil.ContextWithTimeout(tb, testTimeout)) + require.NoError(tb, err) + testutil.CleanupAndRequireSuccess(tb, func() (err error) { + return svc.Shutdown(testutil.ContextWithTimeout(tb, testTimeout)) }) c = svc.Config() - require.NotNil(t, c) - require.Len(t, c.Addresses, 1) + require.NotNil(tb, c) + require.Len(tb, c.Addresses, 1) return svc, c.Addresses[0] } @@ -125,23 +129,23 @@ type jobj map[string]any // the response as well as checks that the status code is correct. // // TODO(a.garipov): Add helpers for other methods. -func httpGet(t testing.TB, u *url.URL, wantCode int) (body []byte) { - t.Helper() +func httpGet(tb testing.TB, u *url.URL, wantCode int) (body []byte) { + tb.Helper() req, err := http.NewRequest(http.MethodGet, u.String(), nil) - require.NoErrorf(t, err, "creating req") + require.NoErrorf(tb, err, "creating req") httpCli := &http.Client{ Timeout: testTimeout, } resp, err := httpCli.Do(req) - require.NoErrorf(t, err, "performing req") - require.Equal(t, wantCode, resp.StatusCode) + require.NoErrorf(tb, err, "performing req") + require.Equal(tb, wantCode, resp.StatusCode) - testutil.CleanupAndRequireSuccess(t, resp.Body.Close) + testutil.CleanupAndRequireSuccess(tb, resp.Body.Close) body, err = io.ReadAll(resp.Body) - require.NoErrorf(t, err, "reading body") + require.NoErrorf(tb, err, "reading body") return body } @@ -151,26 +155,26 @@ func httpGet(t testing.TB, u *url.URL, wantCode int) (body []byte) { // checks that the status code is correct. // // TODO(a.garipov): Add helpers for other methods. -func httpPatch(t testing.TB, u *url.URL, reqBody any, wantCode int) (body []byte) { - t.Helper() +func httpPatch(tb testing.TB, u *url.URL, reqBody any, wantCode int) (body []byte) { + tb.Helper() b, err := json.Marshal(reqBody) - require.NoErrorf(t, err, "marshaling reqBody") + require.NoErrorf(tb, err, "marshaling reqBody") req, err := http.NewRequest(http.MethodPatch, u.String(), bytes.NewReader(b)) - require.NoErrorf(t, err, "creating req") + require.NoErrorf(tb, err, "creating req") httpCli := &http.Client{ Timeout: testTimeout, } resp, err := httpCli.Do(req) - require.NoErrorf(t, err, "performing req") - require.Equal(t, wantCode, resp.StatusCode) + require.NoErrorf(tb, err, "performing req") + require.Equal(tb, wantCode, resp.StatusCode) - testutil.CleanupAndRequireSuccess(t, resp.Body.Close) + testutil.CleanupAndRequireSuccess(tb, resp.Body.Close) body, err = io.ReadAll(resp.Body) - require.NoErrorf(t, err, "reading body") + require.NoErrorf(tb, err, "reading body") return body } diff --git a/internal/querylog/qlog_internal_test.go b/internal/querylog/qlog_internal_test.go index 2a688552..65b81708 100644 --- a/internal/querylog/qlog_internal_test.go +++ b/internal/querylog/qlog_internal_test.go @@ -390,20 +390,20 @@ func addEntry(l *queryLog, host string, answerStr, client net.IP) { l.Add(params) } -func assertLogEntry(t *testing.T, entry *logEntry, host string, answer, client net.IP) { - t.Helper() +func assertLogEntry(tb testing.TB, entry *logEntry, host string, answer, client net.IP) { + tb.Helper() - require.NotNil(t, entry) + require.NotNil(tb, entry) - assert.Equal(t, host, entry.QHost) - assert.Equal(t, client, entry.IP) - assert.Equal(t, "A", entry.QType) - assert.Equal(t, "IN", entry.QClass) + assert.Equal(tb, host, entry.QHost) + assert.Equal(tb, client, entry.IP) + assert.Equal(tb, "A", entry.QType) + assert.Equal(tb, "IN", entry.QClass) msg := &dns.Msg{} - require.NoError(t, msg.Unpack(entry.Answer)) - require.Len(t, msg.Answer, 1) + require.NoError(tb, msg.Unpack(entry.Answer)) + require.Len(tb, msg.Answer, 1) - a := testutil.RequireTypeAssert[*dns.A](t, msg.Answer[0]) - assert.Equal(t, answer, a.A.To16()) + a := testutil.RequireTypeAssert[*dns.A](tb, msg.Answer[0]) + assert.Equal(tb, answer, a.A.To16()) } diff --git a/internal/querylog/qlogfile_internal_test.go b/internal/querylog/qlogfile_internal_test.go index 087d43aa..b80b9ce3 100644 --- a/internal/querylog/qlogfile_internal_test.go +++ b/internal/querylog/qlogfile_internal_test.go @@ -20,17 +20,17 @@ import ( // prepareTestFile prepares one test query log file with the specified lines // count. -func prepareTestFile(t *testing.T, dir string, linesNum int) (name string) { - t.Helper() +func prepareTestFile(tb testing.TB, dir string, linesNum int) (name string) { + tb.Helper() f, err := os.CreateTemp(dir, "*.txt") - require.NoError(t, err) + require.NoError(tb, err) // Use defer and not t.Cleanup to make sure that the file is closed // after this function is done. defer func() { derr := f.Close() - require.NoError(t, derr) + require.NoError(tb, derr) }() const ans = `"AAAAAAABAAEAAAAAB2V4YW1wbGUDb3JnAAABAAEHZXhhbXBsZQNvcmcAAAEAAQAAAAAABAECAwQ="` @@ -49,7 +49,7 @@ func prepareTestFile(t *testing.T, dir string, linesNum int) (name string) { line := fmt.Sprintf(format, ip, lineTime.Format(time.RFC3339Nano)) _, err = f.WriteString(line) - require.NoError(t, err) + require.NoError(tb, err) } return f.Name() @@ -57,18 +57,18 @@ func prepareTestFile(t *testing.T, dir string, linesNum int) (name string) { // prepareTestFiles prepares several test query log files, each with the // specified lines count. -func prepareTestFiles(t *testing.T, filesNum, linesNum int) []string { - t.Helper() +func prepareTestFiles(tb testing.TB, filesNum, linesNum int) []string { + tb.Helper() if filesNum == 0 { return []string{} } - dir := t.TempDir() + dir := tb.TempDir() files := make([]string, filesNum) for i := range files { - files[filesNum-i-1] = prepareTestFile(t, dir, linesNum) + files[filesNum-i-1] = prepareTestFile(tb, dir, linesNum) } return files @@ -76,17 +76,17 @@ func prepareTestFiles(t *testing.T, filesNum, linesNum int) []string { // newTestQLogFile creates new *qLogFile for tests and registers the required // cleanup functions. -func newTestQLogFile(t *testing.T, linesNum int) (file *qLogFile) { - t.Helper() +func newTestQLogFile(tb testing.TB, linesNum int) (file *qLogFile) { + tb.Helper() - testFile := prepareTestFiles(t, 1, linesNum)[0] + testFile := prepareTestFiles(tb, 1, linesNum)[0] // Create the new qLogFile instance. file, err := newQLogFile(testFile) - require.NoError(t, err) + require.NoError(tb, err) - assert.NotNil(t, file) - testutil.CleanupAndRequireSuccess(t, file.Close) + assert.NotNil(tb, file) + testutil.CleanupAndRequireSuccess(tb, file.Close) return file } diff --git a/internal/querylog/qlogreader_internal_test.go b/internal/querylog/qlogreader_internal_test.go index bb3ce164..8a1ed009 100644 --- a/internal/querylog/qlogreader_internal_test.go +++ b/internal/querylog/qlogreader_internal_test.go @@ -13,20 +13,20 @@ import ( // newTestQLogReader creates new *qLogReader for tests and registers the // required cleanup functions. -func newTestQLogReader(t *testing.T, filesNum, linesNum int) (reader *qLogReader) { - t.Helper() +func newTestQLogReader(tb testing.TB, filesNum, linesNum int) (reader *qLogReader) { + tb.Helper() - testFiles := prepareTestFiles(t, filesNum, linesNum) + testFiles := prepareTestFiles(tb, filesNum, linesNum) logger := slogutil.NewDiscardLogger() - ctx := testutil.ContextWithTimeout(t, testTimeout) + ctx := testutil.ContextWithTimeout(tb, testTimeout) // Create the new qLogReader instance. reader, err := newQLogReader(ctx, logger, testFiles) - require.NoError(t, err) + require.NoError(tb, err) - assert.NotNil(t, reader) - testutil.CleanupAndRequireSuccess(t, reader.Close) + assert.NotNil(tb, reader) + testutil.CleanupAndRequireSuccess(tb, reader.Close) return reader } diff --git a/internal/stats/stats_test.go b/internal/stats/stats_test.go index 06aa36f3..662d9be0 100644 --- a/internal/stats/stats_test.go +++ b/internal/stats/stats_test.go @@ -26,25 +26,25 @@ import ( // constUnitID is the UnitIDGenFunc which always return 0. func constUnitID() (id uint32) { return 0 } -func assertSuccessAndUnmarshal(t *testing.T, to any, handler http.Handler, req *http.Request) { - t.Helper() +func assertSuccessAndUnmarshal(tb testing.TB, to any, handler http.Handler, req *http.Request) { + tb.Helper() - require.NotNil(t, handler) + require.NotNil(tb, handler) rw := httptest.NewRecorder() handler.ServeHTTP(rw, req) - require.Equal(t, http.StatusOK, rw.Code) + require.Equal(tb, http.StatusOK, rw.Code) data := rw.Body.Bytes() if to == nil { - assert.Empty(t, data) + assert.Empty(tb, data) return } err := json.Unmarshal(data, to) - require.NoError(t, err) + require.NoError(tb, err) } func TestStats(t *testing.T) { diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index 12e19412..2e2448ac 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -3,7 +3,7 @@ # This comment is used to simplify checking local copies of the script. Bump # this number every time a significant change is made to this script. # -# AdGuard-Project-Version: 13 +# AdGuard-Project-Version: 14 verbose="${VERBOSE:-0}" readonly verbose @@ -26,11 +26,11 @@ set -f -u # Simple analyzers -# blocklist_imports is a simple check against unwanted packages. The following -# packages are banned: +# blocklist_imports is a simple best-effort check against unwanted packages. +# The following packages are banned: # # * Package errors is replaced by our own package in the -# github.com/AdguardTeam/golibs module. +# github.com/AdguardTeam/golibs module. # # * Packages log and github.com/AdguardTeam/golibs/log are replaced by # stdlib's new package log/slog and AdGuard's new utilities package @@ -67,7 +67,10 @@ set -f -u # # TODO(a.garipov): Add golibs/log. blocklist_imports() { - find . \ + import_or_tab="$(printf '^\\(import \\|\t\\)')" + readonly import_or_tab + + find_with_ignore \ -type 'f' \ -name '*.go' \ '!' '(' \ @@ -77,16 +80,16 @@ blocklist_imports() { -exec \ 'grep' \ '-H' \ - '-e' '[[:space:]]"errors"$' \ - '-e' '[[:space:]]"github.com/prometheus/client_golang/prometheus/promauto"$' \ - '-e' '[[:space:]]"golang.org/x/exp/maps"$' \ - '-e' '[[:space:]]"golang.org/x/exp/slices"$' \ - '-e' '[[:space:]]"golang.org/x/net/context"$' \ - '-e' '[[:space:]]"io/ioutil"$' \ - '-e' '[[:space:]]"log"$' \ - '-e' '[[:space:]]"reflect"$' \ - '-e' '[[:space:]]"sort"$' \ - '-e' '[[:space:]]"unsafe"$' \ + '-e' "$import_or_tab"'"errors"$' \ + '-e' "$import_or_tab"'"github.com/prometheus/client_golang/prometheus/promauto"$' \ + '-e' "$import_or_tab"'"golang.org/x/exp/maps"$' \ + '-e' "$import_or_tab"'"golang.org/x/exp/slices"$' \ + '-e' "$import_or_tab"'"golang.org/x/net/context"$' \ + '-e' "$import_or_tab"'"io/ioutil"$' \ + '-e' "$import_or_tab"'"log"$' \ + '-e' "$import_or_tab"'"reflect"$' \ + '-e' "$import_or_tab"'"sort"$' \ + '-e' "$import_or_tab"'"unsafe"$' \ '-n' \ '{}' \ ';' @@ -94,8 +97,11 @@ blocklist_imports() { # method_const is a simple check against the usage of some raw strings and # numbers where one should use named constants. +# +# NOTE: Flag -H for grep is non-POSIX but all of Busybox, GNU, macOS, and +# OpenBSD support it. method_const() { - find . \ + find_with_ignore \ -type 'f' \ -name '*.go' \ -exec \ @@ -116,10 +122,11 @@ method_const() { # use of filenames like client_manager.go. underscores() { underscore_files="$( - find . \ + find_with_ignore \ -type 'f' \ -name '*_*.go' \ - '!' '(' -name '*_bsd.go' \ + '!' '(' \ + -name '*_bsd.go' \ -o -name '*_darwin.go' \ -o -name '*_freebsd.go' \ -o -name '*_generate.go' \ @@ -206,13 +213,7 @@ run_linter ineffassign ./... run_linter unparam ./... -find . \ - '(' \ - -name 'node_modules' \ - -type 'd' \ - -prune \ - ')' \ - -o \ +find_with_ignore \ -type 'f' \ '(' \ -name 'Makefile' \ diff --git a/scripts/make/helper.sh b/scripts/make/helper.sh index 8caa0477..f2ccb57a 100644 --- a/scripts/make/helper.sh +++ b/scripts/make/helper.sh @@ -8,13 +8,13 @@ # This comment is used to simplify checking local copies of the script. Bump # this number every time a remarkable change is made to this script. # -# AdGuard-Project-Version: 4 +# AdGuard-Project-Version: 5 # Deferred helpers not_found_msg=' looks like a binary not found error. -make sure you have installed the linter binaries using: +make sure you have installed the linter binaries, including using: $ make go-tools ' @@ -73,3 +73,41 @@ run_linter() ( return "$exitcode" ) + +# find_with_ignore is a wrapper around find that does not descend into ignored +# directories, such as ./tmp/. +# +# NOTE: The arguments must contain on of -exec, -ok, or -print; see +# https://pubs.opengroup.org/onlinepubs/9799919799/utilities/find.html. +# +# TODO(a.garipov): Find a way to integrate the entire gitignore, including the +# global one, without using git, as .git is not copied into the build container. +# +# Keep in sync with .gitignore. +find_with_ignore() { + find . \ + '(' \ + -type 'd' \ + '(' \ + -name '.git' \ + -o -path '/agh-backup' \ + -o -path './bin' \ + -o -path './build' \ + -o -path './client/blob-report' \ + -o -path './client/playwright-report' \ + -o -path './client/playwright/.cache' \ + -o -path './client/test-results' \ + -o -path './data' \ + -o -path './dist' \ + -o -path './launchpad_credentials' \ + -o -path './snapcraft_login' \ + -o -name 'node_modules' \ + -o -name 'test-reports' \ + -o -name 'tmp' \ + ')' \ + -prune \ + ')' \ + -o \ + "$@" \ + ; +} diff --git a/scripts/make/txt-lint.sh b/scripts/make/txt-lint.sh index ed4bb327..7df3bf1a 100644 --- a/scripts/make/txt-lint.sh +++ b/scripts/make/txt-lint.sh @@ -3,7 +3,7 @@ # This comment is used to simplify checking local copies of the script. Bump # this number every time a remarkable change is made to this script. # -# AdGuard-Project-Version: 8 +# AdGuard-Project-Version: 9 verbose="${VERBOSE:-0}" readonly verbose @@ -33,19 +33,7 @@ trailing_newlines() ( nl="$(printf '\n')" readonly nl - find . \ - '(' \ - -type 'd' \ - '(' \ - -name 'node_modules' \ - -o -path './.git' \ - -o -path './bin' \ - -o -path './build' \ - -o -path './client/playwright-report' \ - ')' \ - -prune \ - ')' \ - -o \ + find_with_ignore \ -type 'f' \ '!' '(' \ -name '*.db' \ @@ -71,7 +59,7 @@ trailing_newlines() ( # trailing_whitespace is a simple check that makes sure that there are no # trailing whitespace in plain-text files. trailing_whitespace() { - find . \ + find_with_ignore \ -type 'f' \ '!' '(' \ -name '*.db' \ @@ -84,11 +72,8 @@ trailing_whitespace() { -o -name '*.zip' \ -o -name 'AdGuardHome' \ -o -name 'adguard-home' \ - -o -path '*/node_modules/*' \ - -o -path './.git/*' \ - -o -path './bin/*' \ - -o -path './build/*' \ ')' \ + -print \ | while read -r f; do grep -e '[[:space:]]$' -n -- "$f" \ | sed -e "s:^:${f}\::" -e 's/ \+$/>>>&<<