Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/labview/test-dashboard-api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import ast
import http.client
import io
import json
import pathlib
import sys
import time
import unittest
import urllib.error
import urllib.request
from unittest.mock import patch


ROOT = pathlib.Path(__file__).resolve().parents[2]
SOURCE = ROOT / 'actions' / 'dashboard' / 'dashboard.py'
TREE = ast.parse(SOURCE.read_text(encoding='utf-8'))
FUNCTIONS = [
node for node in TREE.body
if isinstance(node, ast.FunctionDef) and node.name in {'_retry_delay', 'gh_get'}
]
DASHBOARD = {
'json': json,
'repo': 'owner/repo',
'sys': sys,
'time': time,
'token': 'test-token',
'urllib': urllib,
'_API': {'degraded': False},
}
exec(compile(ast.Module(body=FUNCTIONS, type_ignores=[]), str(SOURCE), 'exec'), DASHBOARD)


class DashboardApiTests(unittest.TestCase):
def test_remote_disconnect_retries_and_returns_response(self):
response = io.StringIO('{"ok": true}')
with patch('urllib.request.urlopen',
side_effect=[http.client.RemoteDisconnected('connection dropped'), response]) as request:
with patch('time.sleep') as sleep:
result = DASHBOARD['gh_get']('commits/sha', _tries=2)

self.assertEqual(result, {'ok': True})
self.assertEqual(request.call_count, 2)
sleep.assert_called_once_with(1)
self.assertFalse(DASHBOARD['_API']['degraded'])


if __name__ == '__main__':
unittest.main()
3 changes: 2 additions & 1 deletion .github/pages/documentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,8 @@ <h2 id="pages">9. The dashboard &amp; Pages site <a class="anchor" href="#pages"
keeps paging back through history — past the recent window it retains <em>only</em> project revisions —
until it has collected the project's revisions or reaches a large safety cap on how many commits it will
classify. Reading that history is resilient to a transient GitHub&nbsp;API failure: rate-limited
(<code>HTTP&nbsp;403</code>/<code>429</code>), server, and network errors are retried with backoff
(<code>HTTP&nbsp;403</code>/<code>429</code>), server, and network errors (including dropped connections)
are retried with backoff
(honoring <code>Retry-After</code>/<code>X-RateLimit-Reset</code>), and if a call still fails so the
revision list would be incomplete, the build <strong>refuses to publish</strong> and exits &mdash; the
previous good dashboard stays live and rebuilds automatically once the API recovers, so a burst of
Expand Down
2 changes: 1 addition & 1 deletion actions/dashboard/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def gh_get(path, _tries=4):
if transient:
_API['degraded'] = True
return None
except (urllib.error.URLError, TimeoutError) as e:
except (urllib.error.URLError, OSError) as e:
if attempt < n_tries - 1:
time.sleep(2 ** attempt)
continue
Expand Down
3 changes: 2 additions & 1 deletion actions/dashboard/documentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,8 @@ <h2 id="pages">9. The dashboard &amp; Pages site <a class="anchor" href="#pages"
keeps paging back through history — past the recent window it retains <em>only</em> project revisions —
until it has collected the project's revisions or reaches a large safety cap on how many commits it will
classify. Reading that history is resilient to a transient GitHub&nbsp;API failure: rate-limited
(<code>HTTP&nbsp;403</code>/<code>429</code>), server, and network errors are retried with backoff
(<code>HTTP&nbsp;403</code>/<code>429</code>), server, and network errors (including dropped connections)
are retried with backoff
(honoring <code>Retry-After</code>/<code>X-RateLimit-Reset</code>), and if a call still fails so the
revision list would be incomplete, the build <strong>refuses to publish</strong> and exits &mdash; the
previous good dashboard stays live and rebuilds automatically once the API recovers, so a burst of
Expand Down
Loading