Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
207 lines
7.9 KiB
Python
207 lines
7.9 KiB
Python
# Copyright (c) 2023-present Plane Software, Inc. and contributors
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# See the LICENSE file for details.
|
|
|
|
import os
|
|
from unittest.mock import Mock, patch
|
|
import pytest
|
|
from plane.settings.storage import S3Storage
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestS3StorageSignedURLExpiration:
|
|
"""Test the configurable signed URL expiration in S3Storage"""
|
|
|
|
@patch.dict(os.environ, {}, clear=True)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_default_expiration_without_env_variable(self, mock_boto3):
|
|
"""Test that default expiration is 3600 seconds when env variable is not set"""
|
|
# Mock the boto3 client
|
|
mock_boto3.client.return_value = Mock()
|
|
|
|
# Create S3Storage instance without SIGNED_URL_EXPIRATION env variable
|
|
storage = S3Storage()
|
|
|
|
# Assert default expiration is 3600
|
|
assert storage.signed_url_expiration == 3600
|
|
|
|
@patch.dict(os.environ, {"SIGNED_URL_EXPIRATION": "30"}, clear=True)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_custom_expiration_with_env_variable(self, mock_boto3):
|
|
"""Test that expiration is read from SIGNED_URL_EXPIRATION env variable"""
|
|
# Mock the boto3 client
|
|
mock_boto3.client.return_value = Mock()
|
|
|
|
# Create S3Storage instance with SIGNED_URL_EXPIRATION=30
|
|
storage = S3Storage()
|
|
|
|
# Assert expiration is 30
|
|
assert storage.signed_url_expiration == 30
|
|
|
|
@patch.dict(os.environ, {"SIGNED_URL_EXPIRATION": "300"}, clear=True)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_custom_expiration_multiple_values(self, mock_boto3):
|
|
"""Test that expiration works with different custom values"""
|
|
# Mock the boto3 client
|
|
mock_boto3.client.return_value = Mock()
|
|
|
|
# Create S3Storage instance with SIGNED_URL_EXPIRATION=300
|
|
storage = S3Storage()
|
|
|
|
# Assert expiration is 300
|
|
assert storage.signed_url_expiration == 300
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"AWS_ACCESS_KEY_ID": "test-key",
|
|
"AWS_SECRET_ACCESS_KEY": "test-secret",
|
|
"AWS_S3_BUCKET_NAME": "test-bucket",
|
|
"AWS_REGION": "us-east-1",
|
|
},
|
|
clear=True,
|
|
)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_generate_presigned_post_uses_default_expiration(self, mock_boto3):
|
|
"""Test that generate_presigned_post uses the configured default expiration"""
|
|
# Mock the boto3 client and its response
|
|
mock_s3_client = Mock()
|
|
mock_s3_client.generate_presigned_post.return_value = {
|
|
"url": "https://test-url.com",
|
|
"fields": {},
|
|
}
|
|
mock_boto3.client.return_value = mock_s3_client
|
|
|
|
# Create S3Storage instance
|
|
storage = S3Storage()
|
|
|
|
# Call generate_presigned_post without explicit expiration
|
|
storage.generate_presigned_post("test-object", "image/png", 1024)
|
|
|
|
# Assert that the boto3 method was called with the default expiration (3600)
|
|
mock_s3_client.generate_presigned_post.assert_called_once()
|
|
call_kwargs = mock_s3_client.generate_presigned_post.call_args[1]
|
|
assert call_kwargs["ExpiresIn"] == 3600
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"AWS_ACCESS_KEY_ID": "test-key",
|
|
"AWS_SECRET_ACCESS_KEY": "test-secret",
|
|
"AWS_S3_BUCKET_NAME": "test-bucket",
|
|
"AWS_REGION": "us-east-1",
|
|
"SIGNED_URL_EXPIRATION": "60",
|
|
},
|
|
clear=True,
|
|
)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_generate_presigned_post_uses_custom_expiration(self, mock_boto3):
|
|
"""Test that generate_presigned_post uses custom expiration from env variable"""
|
|
# Mock the boto3 client and its response
|
|
mock_s3_client = Mock()
|
|
mock_s3_client.generate_presigned_post.return_value = {
|
|
"url": "https://test-url.com",
|
|
"fields": {},
|
|
}
|
|
mock_boto3.client.return_value = mock_s3_client
|
|
|
|
# Create S3Storage instance with SIGNED_URL_EXPIRATION=60
|
|
storage = S3Storage()
|
|
|
|
# Call generate_presigned_post without explicit expiration
|
|
storage.generate_presigned_post("test-object", "image/png", 1024)
|
|
|
|
# Assert that the boto3 method was called with custom expiration (60)
|
|
mock_s3_client.generate_presigned_post.assert_called_once()
|
|
call_kwargs = mock_s3_client.generate_presigned_post.call_args[1]
|
|
assert call_kwargs["ExpiresIn"] == 60
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"AWS_ACCESS_KEY_ID": "test-key",
|
|
"AWS_SECRET_ACCESS_KEY": "test-secret",
|
|
"AWS_S3_BUCKET_NAME": "test-bucket",
|
|
"AWS_REGION": "us-east-1",
|
|
},
|
|
clear=True,
|
|
)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_generate_presigned_url_uses_default_expiration(self, mock_boto3):
|
|
"""Test that generate_presigned_url uses the configured default expiration"""
|
|
# Mock the boto3 client and its response
|
|
mock_s3_client = Mock()
|
|
mock_s3_client.generate_presigned_url.return_value = "https://test-url.com"
|
|
mock_boto3.client.return_value = mock_s3_client
|
|
|
|
# Create S3Storage instance
|
|
storage = S3Storage()
|
|
|
|
# Call generate_presigned_url without explicit expiration
|
|
storage.generate_presigned_url("test-object")
|
|
|
|
# Assert that the boto3 method was called with the default expiration (3600)
|
|
mock_s3_client.generate_presigned_url.assert_called_once()
|
|
call_kwargs = mock_s3_client.generate_presigned_url.call_args[1]
|
|
assert call_kwargs["ExpiresIn"] == 3600
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"AWS_ACCESS_KEY_ID": "test-key",
|
|
"AWS_SECRET_ACCESS_KEY": "test-secret",
|
|
"AWS_S3_BUCKET_NAME": "test-bucket",
|
|
"AWS_REGION": "us-east-1",
|
|
"SIGNED_URL_EXPIRATION": "30",
|
|
},
|
|
clear=True,
|
|
)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_generate_presigned_url_uses_custom_expiration(self, mock_boto3):
|
|
"""Test that generate_presigned_url uses custom expiration from env variable"""
|
|
# Mock the boto3 client and its response
|
|
mock_s3_client = Mock()
|
|
mock_s3_client.generate_presigned_url.return_value = "https://test-url.com"
|
|
mock_boto3.client.return_value = mock_s3_client
|
|
|
|
# Create S3Storage instance with SIGNED_URL_EXPIRATION=30
|
|
storage = S3Storage()
|
|
|
|
# Call generate_presigned_url without explicit expiration
|
|
storage.generate_presigned_url("test-object")
|
|
|
|
# Assert that the boto3 method was called with custom expiration (30)
|
|
mock_s3_client.generate_presigned_url.assert_called_once()
|
|
call_kwargs = mock_s3_client.generate_presigned_url.call_args[1]
|
|
assert call_kwargs["ExpiresIn"] == 30
|
|
|
|
@patch.dict(
|
|
os.environ,
|
|
{
|
|
"AWS_ACCESS_KEY_ID": "test-key",
|
|
"AWS_SECRET_ACCESS_KEY": "test-secret",
|
|
"AWS_S3_BUCKET_NAME": "test-bucket",
|
|
"AWS_REGION": "us-east-1",
|
|
"SIGNED_URL_EXPIRATION": "30",
|
|
},
|
|
clear=True,
|
|
)
|
|
@patch("plane.settings.storage.boto3")
|
|
def test_explicit_expiration_overrides_default(self, mock_boto3):
|
|
"""Test that explicit expiration parameter overrides the default"""
|
|
# Mock the boto3 client and its response
|
|
mock_s3_client = Mock()
|
|
mock_s3_client.generate_presigned_url.return_value = "https://test-url.com"
|
|
mock_boto3.client.return_value = mock_s3_client
|
|
|
|
# Create S3Storage instance with SIGNED_URL_EXPIRATION=30
|
|
storage = S3Storage()
|
|
|
|
# Call generate_presigned_url with explicit expiration=120
|
|
storage.generate_presigned_url("test-object", expiration=120)
|
|
|
|
# Assert that the boto3 method was called with explicit expiration (120)
|
|
mock_s3_client.generate_presigned_url.assert_called_once()
|
|
call_kwargs = mock_s3_client.generate_presigned_url.call_args[1]
|
|
assert call_kwargs["ExpiresIn"] == 120
|