318 lines
8.6 KiB
Python
318 lines
8.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Tests for vendor_update.py
|
|
"""
|
|
|
|
import hashlib
|
|
import json
|
|
import tempfile
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch, mock_open
|
|
|
|
import pytest
|
|
import responses
|
|
|
|
# Import the module (adjust path as needed)
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / 'scripts'))
|
|
|
|
from vendor_update import GitHubAPI, compute_sha256, download_file, update_manifest_entry
|
|
|
|
|
|
@pytest.fixture
|
|
def temp_dir():
|
|
"""Create a temporary directory for tests."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
yield Path(tmpdir)
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_manifest_entry():
|
|
"""Sample manifest entry for testing."""
|
|
return {
|
|
'id': 'test-entry',
|
|
'source_repo': 'owner/repo',
|
|
'source_path': 'path/to/file.stl',
|
|
'source_ref': 'main',
|
|
'pinned_sha': None,
|
|
'pinned_raw_url': None,
|
|
'local_path': 'vendor/owner-repo/path/to/file.stl',
|
|
'checksum_sha256': None,
|
|
'last_checked': None,
|
|
'upstream_latest_sha': None,
|
|
'status': 'unknown',
|
|
'license': None
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def github_api():
|
|
"""Create a GitHubAPI instance for testing."""
|
|
return GitHubAPI(token='test-token')
|
|
|
|
|
|
def test_compute_sha256(temp_dir):
|
|
"""Test SHA256 computation."""
|
|
test_file = temp_dir / 'test.txt'
|
|
test_file.write_text('test content')
|
|
|
|
checksum = compute_sha256(test_file)
|
|
|
|
# Verify it's a valid SHA256 hex string
|
|
assert len(checksum) == 64
|
|
assert all(c in '0123456789abcdef' for c in checksum.lower())
|
|
|
|
# Verify it matches expected hash
|
|
expected = hashlib.sha256(b'test content').hexdigest()
|
|
assert checksum == expected
|
|
|
|
|
|
@responses.activate
|
|
def test_download_file_success(temp_dir):
|
|
"""Test successful file download."""
|
|
test_url = 'https://example.com/file.stl'
|
|
test_content = b'STL file content'
|
|
dest_path = temp_dir / 'downloaded.stl'
|
|
|
|
responses.add(
|
|
responses.GET,
|
|
test_url,
|
|
body=test_content,
|
|
status=200
|
|
)
|
|
|
|
result = download_file(test_url, dest_path)
|
|
|
|
assert result is True
|
|
assert dest_path.exists()
|
|
assert dest_path.read_bytes() == test_content
|
|
|
|
|
|
@responses.activate
|
|
def test_download_file_failure():
|
|
"""Test file download failure."""
|
|
test_url = 'https://example.com/missing.stl'
|
|
dest_path = Path('/tmp/test.stl')
|
|
|
|
responses.add(
|
|
responses.GET,
|
|
test_url,
|
|
status=404
|
|
)
|
|
|
|
result = download_file(test_url, dest_path)
|
|
|
|
assert result is False
|
|
|
|
|
|
@responses.activate
|
|
def test_github_api_get_file_sha(github_api):
|
|
"""Test getting file SHA from GitHub API."""
|
|
owner = 'test-owner'
|
|
repo = 'test-repo'
|
|
path = 'file.stl'
|
|
ref = 'main'
|
|
|
|
# Mock Contents API response
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
|
|
json={'sha': 'blob-sha-123'},
|
|
match=[responses.matchers.query_param_matcher({'ref': ref})]
|
|
)
|
|
|
|
# Mock Commits API response
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/commits',
|
|
json=[{'sha': 'commit-sha-456'}],
|
|
match=[responses.matchers.query_param_matcher({
|
|
'path': path,
|
|
'sha': ref,
|
|
'per_page': 1
|
|
})]
|
|
)
|
|
|
|
sha = github_api.get_file_sha(owner, repo, path, ref)
|
|
|
|
assert sha == 'commit-sha-456'
|
|
|
|
|
|
@responses.activate
|
|
def test_github_api_get_license(github_api):
|
|
"""Test getting license information."""
|
|
owner = 'test-owner'
|
|
repo = 'test-repo'
|
|
sha = 'abc123'
|
|
|
|
# Mock LICENSE file found
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/contents/LICENSE',
|
|
json={'type': 'file'},
|
|
match=[responses.matchers.query_param_matcher({'ref': sha})]
|
|
)
|
|
|
|
license_url = github_api.get_license(owner, repo, sha)
|
|
|
|
assert license_url == f'https://raw.githubusercontent.com/{owner}/{repo}/{sha}/LICENSE'
|
|
|
|
|
|
@responses.activate
|
|
def test_update_manifest_entry_dry_run(temp_dir, sample_manifest_entry):
|
|
"""Test updating manifest entry in dry-run mode."""
|
|
owner = 'owner'
|
|
repo = 'repo'
|
|
path = 'path/to/file.stl'
|
|
ref = 'main'
|
|
|
|
# Mock API responses
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
|
|
json={'sha': 'blob-sha'},
|
|
match=[responses.matchers.query_param_matcher({'ref': ref})]
|
|
)
|
|
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/commits',
|
|
json=[{'sha': 'commit-sha-123'}],
|
|
match=[responses.matchers.query_param_matcher({
|
|
'path': path,
|
|
'sha': ref,
|
|
'per_page': 1
|
|
})]
|
|
)
|
|
|
|
api = GitHubAPI(token='test-token')
|
|
updated_entry = update_manifest_entry(
|
|
sample_manifest_entry,
|
|
api,
|
|
temp_dir,
|
|
dry_run=True
|
|
)
|
|
|
|
assert updated_entry['pinned_sha'] == 'commit-sha-123'
|
|
assert updated_entry['pinned_raw_url'] == f'https://raw.githubusercontent.com/{owner}/{repo}/commit-sha-123/{path}'
|
|
assert updated_entry['status'] == 'up-to-date'
|
|
assert updated_entry['last_checked'] is not None
|
|
assert updated_entry['upstream_latest_sha'] == 'commit-sha-123'
|
|
|
|
# In dry-run, file should not be downloaded
|
|
local_path = temp_dir / updated_entry['local_path']
|
|
assert not local_path.exists()
|
|
|
|
|
|
@responses.activate
|
|
def test_update_manifest_entry_with_download(temp_dir, sample_manifest_entry):
|
|
"""Test updating manifest entry with actual download."""
|
|
owner = 'owner'
|
|
repo = 'repo'
|
|
path = 'path/to/file.stl'
|
|
ref = 'main'
|
|
commit_sha = 'commit-sha-123'
|
|
file_content = b'STL file content here'
|
|
|
|
# Mock API responses
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
|
|
json={'sha': 'blob-sha'},
|
|
match=[responses.matchers.query_param_matcher({'ref': ref})]
|
|
)
|
|
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/commits',
|
|
json=[{'sha': commit_sha}],
|
|
match=[responses.matchers.query_param_matcher({
|
|
'path': path,
|
|
'sha': ref,
|
|
'per_page': 1
|
|
})]
|
|
)
|
|
|
|
# Mock file download
|
|
pinned_url = f'https://raw.githubusercontent.com/{owner}/{repo}/{commit_sha}/{path}'
|
|
responses.add(
|
|
responses.GET,
|
|
pinned_url,
|
|
body=file_content,
|
|
status=200
|
|
)
|
|
|
|
api = GitHubAPI(token='test-token')
|
|
updated_entry = update_manifest_entry(
|
|
sample_manifest_entry,
|
|
api,
|
|
temp_dir,
|
|
dry_run=False
|
|
)
|
|
|
|
assert updated_entry['pinned_sha'] == commit_sha
|
|
assert updated_entry['checksum_sha256'] is not None
|
|
assert updated_entry['status'] == 'up-to-date'
|
|
|
|
# Verify file was downloaded
|
|
local_path = temp_dir / updated_entry['local_path']
|
|
assert local_path.exists()
|
|
assert local_path.read_bytes() == file_content
|
|
|
|
# Verify checksum
|
|
expected_checksum = hashlib.sha256(file_content).hexdigest()
|
|
assert updated_entry['checksum_sha256'] == expected_checksum
|
|
|
|
|
|
@responses.activate
|
|
def test_update_manifest_entry_download_failure(temp_dir, sample_manifest_entry):
|
|
"""Test handling of download failure."""
|
|
owner = 'owner'
|
|
repo = 'repo'
|
|
path = 'path/to/file.stl'
|
|
ref = 'main'
|
|
commit_sha = 'commit-sha-123'
|
|
|
|
# Mock API responses
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/contents/{path}',
|
|
json={'sha': 'blob-sha'},
|
|
match=[responses.matchers.query_param_matcher({'ref': ref})]
|
|
)
|
|
|
|
responses.add(
|
|
responses.GET,
|
|
f'https://api.github.com/repos/{owner}/{repo}/commits',
|
|
json=[{'sha': commit_sha}],
|
|
match=[responses.matchers.query_param_matcher({
|
|
'path': path,
|
|
'sha': ref,
|
|
'per_page': 1
|
|
})]
|
|
)
|
|
|
|
# Mock file download failure
|
|
pinned_url = f'https://raw.githubusercontent.com/{owner}/{repo}/{commit_sha}/{path}'
|
|
responses.add(
|
|
responses.GET,
|
|
pinned_url,
|
|
status=404
|
|
)
|
|
|
|
api = GitHubAPI(token='test-token')
|
|
updated_entry = update_manifest_entry(
|
|
sample_manifest_entry,
|
|
api,
|
|
temp_dir,
|
|
dry_run=False
|
|
)
|
|
|
|
assert updated_entry['status'] == 'error'
|
|
assert updated_entry['pinned_sha'] == commit_sha # SHA was resolved
|
|
assert updated_entry['checksum_sha256'] is None # File not downloaded
|
|
|
|
|
|
if __name__ == '__main__':
|
|
pytest.main([__file__, '-v'])
|