Initial commit — StreamStack v1
Five-service streaming platform: auth, catalogue, streaming, ingest, thumbnailer. Includes React frontend served by nginx, NATS JetStream event bus, aiobotocore async S3, PyAV video metadata + thumbnail extraction, service-to-service JWT auth, and a full unit + e2e test suite.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import io
|
||||
|
||||
import boto3
|
||||
import pytest
|
||||
from moto import mock_aws
|
||||
|
||||
from streamstack.core.s3 import S3SeekableFile, open_s3_buffered
|
||||
|
||||
BUCKET = "test-bucket"
|
||||
KEY = "test/video.mp4"
|
||||
CONTENT = b"Hello World! This is seekable S3 content for testing purposes."
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def s3_object():
|
||||
with mock_aws():
|
||||
s3 = boto3.client("s3", region_name="us-east-1")
|
||||
s3.create_bucket(Bucket=BUCKET)
|
||||
s3.put_object(Bucket=BUCKET, Key=KEY, Body=CONTENT)
|
||||
yield s3
|
||||
|
||||
|
||||
def test_readable_and_seekable(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
assert f.readable() is True
|
||||
assert f.seekable() is True
|
||||
|
||||
|
||||
def test_size(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
assert f.size == len(CONTENT)
|
||||
|
||||
|
||||
def test_initial_position(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
assert f.tell() == 0
|
||||
|
||||
|
||||
def test_read_from_start(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
data = f.read(5)
|
||||
assert data == CONTENT[:5]
|
||||
assert f.tell() == 5
|
||||
|
||||
|
||||
def test_seek_set(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
pos = f.seek(7)
|
||||
assert pos == 7
|
||||
assert f.tell() == 7
|
||||
data = f.read(5)
|
||||
assert data == CONTENT[7:12]
|
||||
|
||||
|
||||
def test_seek_cur(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
f.read(5)
|
||||
f.seek(2, io.SEEK_CUR)
|
||||
assert f.tell() == 7
|
||||
|
||||
|
||||
def test_seek_end(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
pos = f.seek(-5, io.SEEK_END)
|
||||
assert pos == len(CONTENT) - 5
|
||||
data = f.read()
|
||||
assert data == CONTENT[-5:]
|
||||
|
||||
|
||||
def test_seek_beyond_end_clamps(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
pos = f.seek(len(CONTENT) + 100)
|
||||
assert pos == len(CONTENT)
|
||||
|
||||
|
||||
def test_read_at_eof_returns_empty(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
f.seek(0, io.SEEK_END)
|
||||
buf = bytearray(10)
|
||||
n = f.readinto(buf)
|
||||
assert n == 0
|
||||
|
||||
|
||||
def test_full_read(s3_object):
|
||||
f = S3SeekableFile(BUCKET, KEY, s3_client=s3_object)
|
||||
data = f.read()
|
||||
assert data == CONTENT
|
||||
|
||||
|
||||
def test_open_s3_buffered(s3_object):
|
||||
with mock_aws():
|
||||
s3 = boto3.client("s3", region_name="us-east-1")
|
||||
s3.create_bucket(Bucket=BUCKET)
|
||||
s3.put_object(Bucket=BUCKET, Key=KEY, Body=CONTENT)
|
||||
with patch_s3_client(s3):
|
||||
buf = open_s3_buffered(BUCKET, KEY)
|
||||
assert isinstance(buf, io.BufferedReader)
|
||||
data = buf.read(5)
|
||||
assert data == CONTENT[:5]
|
||||
|
||||
|
||||
def patch_s3_client(client):
|
||||
from unittest.mock import patch
|
||||
|
||||
return patch("streamstack.core.s3.get_s3_client", return_value=client)
|
||||
Reference in New Issue
Block a user