Compare commits

..
2 Commits
Author SHA1 Message Date
fraujulian 13b0cb66d6 ci: isolate client smoke and hub tests
CI / Capabilities and shell quality (push) Successful in 11s
CI / Python tests and compilation (push) Successful in 12s
CI / PowerShell tests on Ubuntu (push) Failing after 14s
CI / CI configuration security checks (push) Successful in 3s
CI / Build and inspect generated packages (push) Successful in 7s
CI / Qwen retrieval integration (push) Failing after 9m38s
CI / Bash integration and installation guards (push) Successful in 16s
CI / Installed client configuration smoke tests (push) Successful in 12s
2026-09-18 12:57:28 +02:00
fraujulian acb53382a6 fix(tests): use portable plugin home 2026-09-18 12:57:17 +02:00
4 changed files with 29 additions and 4 deletions

No files matched your search

+2
View File
@@ -138,6 +138,8 @@ jobs:
needs: [build] needs: [build]
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build packages
run: bash scripts/commands/build.sh --summary
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0 - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0
with: with:
node-version: '24' node-version: '24'
+2
View File
@@ -138,6 +138,8 @@ jobs:
needs: [build] needs: [build]
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build packages
run: bash scripts/commands/build.sh --summary
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0 - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v22.16.0
with: with:
node-version: '24' node-version: '24'
+5 -4
View File
@@ -38,10 +38,11 @@ $env:AI_CONFIG_VERBOSE = $null
if (-not $failed -or $diagnostics -notcontains 'download progress' -or $diagnostics -notcontains 'WARN test warning') { throw 'Plugin failure must retain full diagnostics and fail.' } if (-not $failed -or $diagnostics -notcontains 'download progress' -or $diagnostics -notcontains 'WARN test warning') { throw 'Plugin failure must retain full diagnostics and fail.' }
$global:LASTEXITCODE = 0 $global:LASTEXITCODE = 0
function codex { $script:observedCodexHome = $env:CODEX_HOME; $script:observedProfile = $env:USERPROFILE; '{"installed":[{"pluginId":"ponytail@ponytail"},{"pluginId":"i-have-adhd@i-have-adhd"},{"pluginId":"superpowers@openai-curated-remote"},{"pluginId":"context7@context7-marketplace"},{"pluginId":"caveman@thinkhome-caveman"}],"available":[]}' } function codex { $script:observedCodexHome = $env:CODEX_HOME; $script:observedProfile = $env:USERPROFILE; '{"installed":[{"pluginId":"ponytail@ponytail"},{"pluginId":"i-have-adhd@i-have-adhd"},{"pluginId":"superpowers@openai-curated-remote"},{"pluginId":"context7@context7-marketplace"},{"pluginId":"caveman@thinkhome-caveman"}],"available":[]}' }
$testHome = Join-Path ([System.IO.Path]::GetTempPath()) 'ai-config-plugin-test-home'
$previousCodexHome = $env:CODEX_HOME $previousCodexHome = $env:CODEX_HOME
$previousProfile = $env:USERPROFILE $previousProfile = $env:USERPROFILE
$null = Get-InstalledPlugins -Client Codex -HomePath 'C:/temporary profile' $null = Get-InstalledPlugins -Client Codex -HomePath $testHome
if ($observedCodexHome -ne (Join-Path 'C:/temporary profile' '.codex') -or $observedProfile -ne 'C:/temporary profile') { throw 'Plugin inspection must use the requested user home.' } if ($observedCodexHome -ne (Join-Path $testHome '.codex') -or $observedProfile -ne $testHome) { throw 'Plugin inspection must use the requested user home.' }
if ($env:CODEX_HOME -ne $previousCodexHome -or $env:USERPROFILE -ne $previousProfile) { throw 'Plugin inspection must restore the process environment.' } if ($env:CODEX_HOME -ne $previousCodexHome -or $env:USERPROFILE -ne $previousProfile) { throw 'Plugin inspection must restore the process environment.' }
$script:answers.Enqueue('done') $script:answers.Enqueue('done')
$selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Mode Update $selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Mode Update
@@ -53,8 +54,8 @@ if (@($selection.Deselected | Where-Object { $_.name -eq 'Context7' }).Count -ne
$script:managedArguments = @() $script:managedArguments = @()
function python { $script:managedArguments = @($args); $global:LASTEXITCODE = 0 } function python { $script:managedArguments = @($args); $global:LASTEXITCODE = 0 }
$entry = [pscustomobject]@{ name = 'Test'; codex_method = 'plugin'; codex_marketplace = '-'; codex_plugin = 'test@market' } $entry = [pscustomobject]@{ name = 'Test'; codex_method = 'plugin'; codex_marketplace = '-'; codex_plugin = 'test@market' }
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -HomePath 'C:/temporary home' -Update -Summary -Entries @($entry) Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -HomePath $testHome -Update -Summary -Entries @($entry)
if ($managedArguments -notcontains 'sync' -or $managedArguments -notcontains '--update' -or $managedArguments -notcontains 'Test' -or $managedArguments -notcontains 'C:/temporary home') { throw 'Managed reconciliation must receive selection, home, and update mode.' } if ($managedArguments -notcontains 'sync' -or $managedArguments -notcontains '--update' -or $managedArguments -notcontains 'Test' -or $managedArguments -notcontains $testHome) { throw 'Managed reconciliation must receive selection, home, and update mode.' }
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Entries @() Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Entries @()
if ($managedArguments[-1] -ne '--selected') { throw 'Empty selection must reach reconciliation for managed cleanup.' } if ($managedArguments[-1] -ne '--selected') { throw 'Empty selection must reach reconciliation for managed cleanup.' }
function Get-InstalledPlugins { throw 'Empty selection must not query installed plugins.' } function Get-InstalledPlugins { throw 'Empty selection must not query installed plugins.' }
+20
View File
@@ -4,6 +4,7 @@ from concurrent.futures import ThreadPoolExecutor
import os import os
from pathlib import Path from pathlib import Path
import re import re
import socket
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from types import SimpleNamespace from types import SimpleNamespace
import time import time
@@ -26,12 +27,29 @@ def embedding():
return array('f', [1.0] + [0.0] * (MODULE.EMBEDDING_DIMENSIONS - 1)) return array('f', [1.0] + [0.0] * (MODULE.EMBEDDING_DIMENSIONS - 1))
def huggingface_available():
try:
socket.getaddrinfo('huggingface.co', 443)
except socket.gaierror:
return False
return True
class RetrievalServerTests(unittest.TestCase): class RetrievalServerTests(unittest.TestCase):
def test_huggingface_availability_handles_dns_failure(self):
with patch('socket.getaddrinfo', side_effect=socket.gaierror):
self.assertFalse(huggingface_available())
def test_ci_disables_xet_for_model_downloads(self): def test_ci_disables_xet_for_model_downloads(self):
for workflow in ('.github/workflows/ci.yml', '.gitea/workflows/ci.yml'): for workflow in ('.github/workflows/ci.yml', '.gitea/workflows/ci.yml'):
content = (ROOT / workflow).read_text(encoding='utf-8') content = (ROOT / workflow).read_text(encoding='utf-8')
self.assertIn("HF_HUB_DISABLE_XET: '1'", content) self.assertIn("HF_HUB_DISABLE_XET: '1'", content)
def test_client_smoke_builds_packages(self):
for workflow in ('.github/workflows/ci.yml', '.gitea/workflows/ci.yml'):
content = (ROOT / workflow).read_text(encoding='utf-8')
self.assertIn('name: Build packages\n run: bash scripts/commands/build.sh --summary', content)
def test_runtime_python_uses_adjacent_virtualenv(self): def test_runtime_python_uses_adjacent_virtualenv(self):
with TemporaryDirectory() as temporary: with TemporaryDirectory() as temporary:
script = Path(temporary) / 'semantic-retrieval' / 'server.py' script = Path(temporary) / 'semantic-retrieval' / 'server.py'
@@ -49,6 +67,8 @@ class RetrievalServerTests(unittest.TestCase):
@unittest.skipUnless(os.environ.get('QWEN_TEST_MODEL_CACHE'), 'Set QWEN_TEST_MODEL_CACHE to run the real-model check.') @unittest.skipUnless(os.environ.get('QWEN_TEST_MODEL_CACHE'), 'Set QWEN_TEST_MODEL_CACHE to run the real-model check.')
def test_real_models(self): def test_real_models(self):
if not huggingface_available():
self.skipTest('huggingface.co DNS is unavailable')
os.environ['HF_HOME'] = os.environ['QWEN_TEST_MODEL_CACHE'] os.environ['HF_HOME'] = os.environ['QWEN_TEST_MODEL_CACHE']
with TemporaryDirectory() as temporary: with TemporaryDirectory() as temporary:
root = Path(temporary) root = Path(temporary)