Skip to content
Merged
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
3 changes: 3 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[pytest]
testpaths = tests
asyncio_mode = auto
Empty file added tests/app/flags/__init__.py
Empty file.
Empty file.
151 changes: 111 additions & 40 deletions tests/app/flags/advanced/test_flag0.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,132 @@
"""Exhaustive tests for advanced flag_0 (AdvancedFlag0)."""
import pytest
from unittest.mock import MagicMock, AsyncMock

from plugins.training.app.flags.advanced.flag_0 import AdvancedFlag0


class TestFlag:
def test_valid_external_http_contact(self):
test_contact = 'http://10.10.10.10:8888'
assert AdvancedFlag0.valid_external_http_contact(test_contact)
class TestValidExternalHttpContact:
def test_valid_external_http(self):
assert AdvancedFlag0.valid_external_http_contact('http://10.10.10.10:8888')

def test_valid_external_https_contact(self):
test_contact = 'https://10.10.10.10:8888'
assert AdvancedFlag0.valid_external_http_contact(test_contact)
def test_valid_external_https(self):
assert AdvancedFlag0.valid_external_http_contact('https://10.10.10.10:8888')

def test_valid_external_http_contact_no_port(self):
test_contact = 'http://10.10.10.10'
assert AdvancedFlag0.valid_external_http_contact(test_contact)
def test_valid_http_no_port(self):
assert AdvancedFlag0.valid_external_http_contact('http://10.10.10.10')

def test_valid_external_https_contact_no_port(self):
test_contact = 'https://10.10.10.10'
assert AdvancedFlag0.valid_external_http_contact(test_contact)
def test_valid_https_no_port(self):
assert AdvancedFlag0.valid_external_http_contact('https://10.10.10.10')

def test_internal_http_contact_loopback(self):
test_contact = 'http://127.0.0.1:8888'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
def test_loopback_rejected(self):
assert not AdvancedFlag0.valid_external_http_contact('http://127.0.0.1:8888')

def test_internal_http_contact_loopback_no_port(self):
test_contact = 'http://127.0.0.1'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
def test_loopback_no_port(self):
assert not AdvancedFlag0.valid_external_http_contact('http://127.0.0.1')

def test_internal_https_contact_loopback(self):
test_contact = 'https://127.0.0.1:12345'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
def test_loopback_https(self):
assert not AdvancedFlag0.valid_external_http_contact('https://127.0.0.1:12345')

def test_internal_http_contact_loopback_other(self):
test_contact = 'http://127.10.10.10'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
def test_loopback_other(self):
assert not AdvancedFlag0.valid_external_http_contact('http://127.10.10.10')

def test_internal_http_contact_0000(self):
test_contact = 'http://0.0.0.0:8888'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
def test_zero_ip(self):
assert not AdvancedFlag0.valid_external_http_contact('http://0.0.0.0:8888')

def test_internal_http_contact_0000_no_port(self):
test_contact = 'http://0.0.0.0'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
def test_zero_ip_no_port(self):
assert not AdvancedFlag0.valid_external_http_contact('http://0.0.0.0')

def test_invalid_port(self):
test_contact = 'http://10.10.10.10:abcd'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
assert not AdvancedFlag0.valid_external_http_contact('http://10.10.10.10:abcd')

def test_out_of_range_port(self):
test_contact = 'http://10.10.10.10:123456'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
assert not AdvancedFlag0.valid_external_http_contact('http://10.10.10.10:123456')

def test_not_ip_addr(self):
test_contact = 'http://myhostname.tld:1234'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
def test_hostname_rejected(self):
assert not AdvancedFlag0.valid_external_http_contact('http://myhostname.tld:1234')

def test_wrong_protocol(self):
test_contact = 'nothttp://10.10.10.10:12345'
assert not AdvancedFlag0.valid_external_http_contact(test_contact)
assert not AdvancedFlag0.valid_external_http_contact('nothttp://10.10.10.10:12345')

def test_ftp_rejected(self):
assert not AdvancedFlag0.valid_external_http_contact('ftp://10.10.10.10:21')

def test_empty_string(self):
assert not AdvancedFlag0.valid_external_http_contact('')

def test_no_scheme(self):
assert not AdvancedFlag0.valid_external_http_contact('10.10.10.10:8888')

def test_private_192_168(self):
assert AdvancedFlag0.valid_external_http_contact('http://192.168.1.1:443')

def test_private_172(self):
assert AdvancedFlag0.valid_external_http_contact('http://172.16.0.1:8080')

def test_port_zero(self):
# Port 0 is technically valid in URL parsing
result = AdvancedFlag0.valid_external_http_contact('http://10.10.10.10:0')
# Should still pass since port 0 is in range
assert isinstance(result, bool)

def test_max_valid_port(self):
assert AdvancedFlag0.valid_external_http_contact('http://10.10.10.10:65535')

def test_boundary_ip_255(self):
assert AdvancedFlag0.valid_external_http_contact('http://255.255.255.255:80')

def test_ip_1_0_0_1(self):
assert AdvancedFlag0.valid_external_http_contact('http://1.0.0.1:80')


class TestExternalFacingIp:
def test_external(self):
assert AdvancedFlag0.external_facing_ip('10.0.0.1')

def test_loopback(self):
assert not AdvancedFlag0.external_facing_ip('127.0.0.1')

def test_loopback_range(self):
assert not AdvancedFlag0.external_facing_ip('127.255.0.1')

def test_zero(self):
assert not AdvancedFlag0.external_facing_ip('0.0.0.0')


class TestAdvancedFlag0Verify:
@pytest.mark.asyncio
async def test_verify_valid_contact(self):
flag = AdvancedFlag0(number=1)
services = {'app_svc': MagicMock()}
services['app_svc'].get_config = MagicMock(return_value='http://10.10.10.10:8888')
result = await flag.verify(services)
assert result is True

@pytest.mark.asyncio
async def test_verify_loopback_contact(self):
flag = AdvancedFlag0(number=1)
services = {'app_svc': MagicMock()}
services['app_svc'].get_config = MagicMock(return_value='http://127.0.0.1:8888')
result = await flag.verify(services)
assert result is False

@pytest.mark.asyncio
async def test_verify_none_contact(self):
flag = AdvancedFlag0(number=1)
services = {'app_svc': MagicMock()}
services['app_svc'].get_config = MagicMock(return_value=None)
result = await flag.verify(services)
assert not result

@pytest.mark.asyncio
async def test_verify_empty_contact(self):
flag = AdvancedFlag0(number=1)
services = {'app_svc': MagicMock()}
services['app_svc'].get_config = MagicMock(return_value='')
result = await flag.verify(services)
assert not result

def test_name_and_challenge(self):
flag = AdvancedFlag0(number=1)
assert flag.name == 'Update configs'
assert 'app.contact.http' in flag.challenge
49 changes: 49 additions & 0 deletions tests/app/flags/advanced/test_flag1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Tests for advanced flag_1 (AdvancedFlag1)."""
import pytest
from unittest.mock import MagicMock, AsyncMock

from plugins.training.app.flags.advanced.flag_1 import AdvancedFlag1


class TestAdvancedFlag1:

def test_name(self):
f = AdvancedFlag1(number=1)
assert f.name == 'Adjust sources'

@pytest.mark.asyncio
async def test_verify_source_with_facts_and_rules(self):
f = AdvancedFlag1(number=1)
source = MagicMock()
source.facts = [MagicMock()]
source.rules = [MagicMock()]
services = {'data_svc': AsyncMock()}
services['data_svc'].locate = AsyncMock(return_value=[source])
assert await f.verify(services) is True

@pytest.mark.asyncio
async def test_verify_no_source(self):
f = AdvancedFlag1(number=1)
services = {'data_svc': AsyncMock()}
services['data_svc'].locate = AsyncMock(return_value=[])
assert await f.verify(services) is False

@pytest.mark.asyncio
async def test_verify_source_no_facts(self):
f = AdvancedFlag1(number=1)
source = MagicMock()
source.facts = []
source.rules = [MagicMock()]
services = {'data_svc': AsyncMock()}
services['data_svc'].locate = AsyncMock(return_value=[source])
assert await f.verify(services) is False

@pytest.mark.asyncio
async def test_verify_source_no_rules(self):
f = AdvancedFlag1(number=1)
source = MagicMock()
source.facts = [MagicMock()]
source.rules = []
services = {'data_svc': AsyncMock()}
services['data_svc'].locate = AsyncMock(return_value=[source])
assert await f.verify(services) is False
49 changes: 49 additions & 0 deletions tests/app/flags/advanced/test_flag2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Tests for advanced flag_2 (AdvancedFlag2)."""
import pytest
from unittest.mock import MagicMock, AsyncMock

from plugins.training.app.flags.advanced.flag_2 import AdvancedFlag2


class TestAdvancedFlag2:

def test_name(self):
f = AdvancedFlag2(number=1)
assert f.name == 'Add new user'

@pytest.mark.asyncio
async def test_verify_correct_user(self):
f = AdvancedFlag2(number=1)
user = MagicMock()
user.password = 'test'
user.permissions = ['red']
services = {'auth_svc': MagicMock()}
services['auth_svc'].user_map = {'test': user}
assert await f.verify(services) is True

@pytest.mark.asyncio
async def test_verify_no_user(self):
f = AdvancedFlag2(number=1)
services = {'auth_svc': MagicMock()}
services['auth_svc'].user_map = {}
assert not await f.verify(services)

@pytest.mark.asyncio
async def test_verify_wrong_password(self):
f = AdvancedFlag2(number=1)
user = MagicMock()
user.password = 'wrong'
user.permissions = ['red']
services = {'auth_svc': MagicMock()}
services['auth_svc'].user_map = {'test': user}
assert await f.verify(services) is False

@pytest.mark.asyncio
async def test_verify_no_red_permission(self):
f = AdvancedFlag2(number=1)
user = MagicMock()
user.password = 'test'
user.permissions = ['blue']
services = {'auth_svc': MagicMock()}
services['auth_svc'].user_map = {'test': user}
assert await f.verify(services) is False
Empty file.
Loading
Loading