mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
test(stalker): repoint two handshake tests at the path they claim to cover
Self-audit, prompted by the previous round: the reorder exposed one test that was asserting through a path it no longer reached, so I checked the rest of that class rather than assume it was the only one. Two more had the same defect, both mine. `still returns the static url when the handshake fails` (both specs) mocked `ensureToken` to reject, but used a FOREIGN-host command. Now that classification runs before authentication, that command returns before the handshake is ever attempted — the rejection was never exercised and the test passed on the early return instead of the mechanism in its name. Worse, the foreign case is already covered by the test added alongside the reorder, so these were asserting nothing new. Both now use a portal-owned command, which is what actually reaches the handshake, and assert what a throw really produces: `ensureStalkerSession` swallows it, the verdict is false, and the row falls back to `create_link` rather than being served as a known 401. Each asserts `ensureToken` was in fact called, so neither can silently drift back into testing an early return. Docs corrected with them: the "best-effort degrades to the token-less header set" wording described behaviour the reorder removed. A foreign-host URL is now returned before any handshake, and a failed one routes to `create_link`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
53f9446b87
commit
e2a7021046
3 files changed
+35
-18
No files matched your search
@@ -396,10 +396,10 @@ playback behind a request worth up to 15 s against a portal that may be slow
|
||||
or offline while the CDN is perfectly reachable — for a result that is then
|
||||
discarded.
|
||||
|
||||
The call is best-effort in one direction only. A **foreign-host** static URL
|
||||
never needed the session, so a failed or skipped handshake still serves it. A
|
||||
**portal-owned** one with no usable session would be served knowing it will
|
||||
401, so both call sites fall back to `create_link` instead — which mints a URL
|
||||
A **foreign-host** static URL is returned before the handshake is even
|
||||
attempted — it never needed the session. A **portal-owned** one with no usable
|
||||
session (handshake failed, or threw) would be served knowing it will 401, so
|
||||
both call sites fall back to `create_link` instead — which mints a URL
|
||||
carrying its own token and, crucially, is the only path that can observe a
|
||||
failure and trigger the lazy portal repair. That keeps a playlist still
|
||||
misclassified as token-free, or pointing at an unrepaired endpoint, on the
|
||||
@@ -407,7 +407,9 @@ self-healing path it was on before this change.
|
||||
|
||||
`ensureStalkerSession` returns that verdict: `true` for a portal that needs no
|
||||
token and for one holding a usable token, `false` for a full portal left
|
||||
without one.
|
||||
without one. It swallows a throwing handshake rather than propagating it — an
|
||||
unreachable portal must not surface as an exception mid-playback — which
|
||||
simply makes the verdict `false` and routes the row to `create_link`.
|
||||
|
||||
**Known trade-off: a cached token is not revalidated.** `ensureToken` returns a
|
||||
same-identity cache entry without touching the network, so the static path no
|
||||
|
||||
@@ -934,9 +934,11 @@ describe('StreamResolverService', () => {
|
||||
expect(stalkerSession.ensureToken).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('still plays a static stream when the session cannot be established', async () => {
|
||||
// The static URL may point at a CDN that needs no credentials, so a
|
||||
// failed handshake must not cost the user their playback.
|
||||
it('falls back to create_link when the handshake throws', async () => {
|
||||
// A throwing handshake must not propagate. It leaves the session
|
||||
// unusable, so a PORTAL-OWNED url goes to `create_link` rather than
|
||||
// being served as a known 401 — the url has to be portal-owned for
|
||||
// the handshake to run at all now that classification comes first.
|
||||
playlistsService.getPlaylistById.mockReturnValue(
|
||||
of({
|
||||
_id: 'stalker-1',
|
||||
@@ -947,25 +949,30 @@ describe('StreamResolverService', () => {
|
||||
} satisfies Partial<Playlist>)
|
||||
);
|
||||
stalkerSession.ensureToken.mockRejectedValue(new Error('portal down'));
|
||||
stalkerSession.makeAuthenticatedRequest.mockResolvedValue({
|
||||
js: { cmd: 'https://stalker.example.com/tmp/92.ts?tok=1' },
|
||||
});
|
||||
|
||||
const playback = await service.resolvePlayback({
|
||||
uid: 'stalker::stalker-1::92',
|
||||
name: 'Cdn Static Channel',
|
||||
name: 'Portal Static Channel',
|
||||
contentType: 'live',
|
||||
sourceType: 'stalker',
|
||||
playlistId: 'stalker-1',
|
||||
playlistName: 'Stalker',
|
||||
stalkerId: '92',
|
||||
stalkerCmd: 'ffrt3 https://cdn.example.com/live/92.m3u8',
|
||||
stalkerCmd: 'ffrt3 https://stalker.example.com/live/92.m3u8',
|
||||
stalkerItem: {
|
||||
id: '92',
|
||||
cmd: 'ffrt3 https://cdn.example.com/live/92.m3u8',
|
||||
cmd: 'ffrt3 https://stalker.example.com/live/92.m3u8',
|
||||
use_http_tmp_link: '0',
|
||||
},
|
||||
} as UnifiedCollectionItem);
|
||||
|
||||
expect(playback.streamUrl).toBe('https://cdn.example.com/live/92.m3u8');
|
||||
expect(playback.headers?.['Authorization']).toBeUndefined();
|
||||
expect(stalkerSession.ensureToken).toHaveBeenCalled();
|
||||
expect(playback.streamUrl).toBe(
|
||||
'https://stalker.example.com/tmp/92.ts?tok=1'
|
||||
);
|
||||
});
|
||||
|
||||
it('prefers the edited playlist coordinates over a stale favorite snapshot', async () => {
|
||||
|
||||
+13
-5
@@ -328,12 +328,19 @@ describe('stalker-player-request.utils', () => {
|
||||
expect(stalkerSession.ensureToken).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('still returns the static url when the handshake fails', async () => {
|
||||
// The static URL may need no credentials at all, so a portal
|
||||
// that cannot be reached must not cost the user their playback.
|
||||
it('falls back to create_link when the handshake throws', async () => {
|
||||
// A throwing handshake must not propagate — it leaves the session
|
||||
// unusable, and a portal-owned URL then goes to `create_link`
|
||||
// rather than being served as a known 401. The command has to be
|
||||
// portal-owned for the handshake to run at all.
|
||||
(
|
||||
stalkerSession.ensureToken as jest.Mock
|
||||
).mockRejectedValue(new Error('portal down'));
|
||||
(
|
||||
stalkerSession.makeAuthenticatedRequest as jest.Mock
|
||||
).mockResolvedValue({
|
||||
js: { cmd: 'http://demo.example/tmp/1.mkv?tok=1' },
|
||||
});
|
||||
|
||||
const streamUrl = await fetchStalkerPlaybackLink(deps(), {
|
||||
playlist: {
|
||||
@@ -341,11 +348,12 @@ describe('stalker-player-request.utils', () => {
|
||||
isFullStalkerPortal: true,
|
||||
} as PlaylistMeta,
|
||||
selectedContentType: 'vod',
|
||||
cmd: 'ffrt3 http://cdn.example/movies/1.mkv',
|
||||
cmd: 'ffrt3 http://demo.example/movies/1.mkv',
|
||||
linkFlags: { use_http_tmp_link: '0' },
|
||||
});
|
||||
|
||||
expect(streamUrl).toBe('http://cdn.example/movies/1.mkv');
|
||||
expect(stalkerSession.ensureToken).toHaveBeenCalled();
|
||||
expect(streamUrl).toBe('http://demo.example/tmp/1.mkv?tok=1');
|
||||
});
|
||||
|
||||
it('plays the static cmd of an unflagged row without asking the portal', async () => {
|
||||
|
||||
Reference in new issue
Block a user