Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 426498c

Browse files
Add tests for TokenlessAzureHandler timestamp handling
1 parent ad92471 commit 426498c

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import pytest
2+
from datetime import datetime, timedelta
3+
from unittest.mock import patch
4+
from rest_framework.exceptions import NotFound
5+
6+
from upload.tokenless.azure import TokenlessAzureHandler
7+
8+
@pytest.fixture
9+
def upload_params():
10+
return {
11+
"job": "899861",
12+
"project": "public",
13+
"server_uri": "https://dev.azure.com/dnceng-public/",
14+
"build": "20241219.14",
15+
"commit": "0f6e31fec5876be932f9e52f739ce1a2e04f11e3"
16+
}
17+
18+
def test_verify_handles_nanosecond_timestamp(upload_params):
19+
"""
20+
Test that the handler correctly processes timestamps with nanosecond precision
21+
from the Azure DevOps API.
22+
"""
23+
handler = TokenlessAzureHandler(upload_params)
24+
25+
# Mock a response with nanosecond precision timestamp (7 digits after decimal)
26+
current_time = datetime.now()
27+
timestamp = current_time.strftime("%Y-%m-%dT%H:%M:%S.1234567Z")
28+
29+
mock_build_response = {
30+
"status": "completed",
31+
"finishTime": timestamp,
32+
"buildNumber": "20241219.14",
33+
"sourceVersion": "0f6e31fec5876be932f9e52f739ce1a2e04f11e3",
34+
"repository": {"type": "GitHub"}
35+
}
36+
37+
with patch.object(handler, 'get_build', return_value=mock_build_response):
38+
service = handler.verify()
39+
assert service == "github"
40+
41+
def test_verify_handles_microsecond_timestamp(upload_params):
42+
"""
43+
Test that the handler still works correctly with regular microsecond precision
44+
timestamps.
45+
"""
46+
handler = TokenlessAzureHandler(upload_params)
47+
48+
# Mock a response with microsecond precision (6 digits after decimal)
49+
current_time = datetime.now()
50+
timestamp = current_time.strftime("%Y-%m-%dT%H:%M:%S.123456Z")
51+
52+
mock_build_response = {
53+
"status": "completed",
54+
"finishTime": timestamp,
55+
"buildNumber": "20241219.14",
56+
"sourceVersion": "0f6e31fec5876be932f9e52f739ce1a2e04f11e3",
57+
"repository": {"type": "GitHub"}
58+
}
59+
60+
with patch.object(handler, 'get_build', return_value=mock_build_response):
61+
service = handler.verify()
62+
assert service == "github"
63+
64+
def test_verify_rejects_old_timestamp(upload_params):
65+
"""
66+
Test that the handler correctly rejects timestamps older than 4 minutes,
67+
even with nanosecond precision.
68+
"""
69+
handler = TokenlessAzureHandler(upload_params)
70+
71+
# Create a timestamp that's more than 4 minutes old
72+
old_time = datetime.now() - timedelta(minutes=5)
73+
timestamp = old_time.strftime("%Y-%m-%dT%H:%M:%S.1234567Z")
74+
75+
mock_build_response = {
76+
"status": "completed",
77+
"finishTime": timestamp,
78+
"buildNumber": "20241219.14",
79+
"sourceVersion": "0f6e31fec5876be932f9e52f739ce1a2e04f11e3",
80+
"repository": {"type": "GitHub"}
81+
}
82+
83+
with patch.object(handler, 'get_build', return_value=mock_build_response):
84+
with pytest.raises(NotFound, match="Azure build has already finished"):
85+
handler.verify()

upload/tokenless/azure.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ def verify(self):
7878
# Build should have finished within the last 4 mins OR should have an 'inProgress' flag
7979
if build["status"] == "completed":
8080
finishTimestamp = build["finishTime"].replace("T", " ").replace("Z", "")
81+
# Azure DevOps API returns nanosecond precision (7 digits), but Python only supports
82+
# microsecond precision (6 digits). Truncate to 6 digits after decimal.
83+
if "." in finishTimestamp:
84+
base, fraction = finishTimestamp.rsplit(".", 1)
85+
finishTimestamp = f"{base}.{fraction[:6]}"
8186
buildFinishDateObj = datetime.strptime(
8287
finishTimestamp, "%Y-%m-%d %H:%M:%S.%f"
8388
)

0 commit comments

Comments
 (0)