Skip to content
Open
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
20 changes: 20 additions & 0 deletions .github/workflows/test_sonic_xcvr_with_emu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Test sonic-xcvr with xcvr-emu

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: test sonic-xcvr with xcvr-emu
run: make test_sonic_xcvr_with_emu
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
DOCKER_CMD ?= docker
SONIC_XCVR_IMAGE ?= sonic-xcvr

.PHONY: test_sonic_xcvr_with_emu
test_sonic_xcvr_with_emu:
$(DOCKER_CMD) build -f docker/Dockerfile -t $(SONIC_XCVR_IMAGE) .
$(DOCKER_CMD) run -it \
-v `pwd`/docker/pyproject.toml:/sonic_platform_base/pyproject.toml \
-v `pwd`/sonic_platform_base:/sonic_platform_base/sonic_platform_base \
-v `pwd`/docker/tests:/sonic_platform_base/tests \
-w /sonic_platform_base \
$(SONIC_XCVR_IMAGE) \
python -m pytest -v --log-cli-level=INFO .
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ steps:
set -ex
pip3 install ".[testing]"
pip3 uninstall --yes sonic-platform-common
pytest
pytest --ignore docker
displayName: 'Test Python 3'

- task: PublishTestResults@2
Expand Down
12 changes: 12 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM ghcr.io/ishidawataru/xcvr-emu:latest

WORKDIR /sonic_platform_base

RUN --mount=type=bind,source=docker/sonic_py_common,target=/sonic_py_common,rw \
cd /sonic_py_common && pip install .

RUN mkdir sonic_platform_base && touch sonic_platform_base/__init__.py

COPY docker/pyproject.toml .

RUN pip install '.[dev]'
10 changes: 10 additions & 0 deletions docker/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "sonic-platform-common"
version = "1.0.0"

[project.optional-dependencies]
dev = ["pytest", "mock", "PyYAML", "pytest-asyncio"]
7 changes: 7 additions & 0 deletions docker/sonic_py_common/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "sonic-py-common"
version = "1.0.0"
Empty file.
3 changes: 3 additions & 0 deletions docker/sonic_py_common/sonic_py_common/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from unittest.mock import MagicMock

Logger = MagicMock()
132 changes: 132 additions & 0 deletions docker/tests/sonic_xcvr_with_emu/test_cmis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import pytest
import logging

from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom
from sonic_platform_base.sonic_xcvr.api.public.cmis import CmisApi
from sonic_platform_base.sonic_xcvr.mem_maps.public.cmis import CmisMemMap
from sonic_platform_base.sonic_xcvr.codes.public.cmis import CmisCodes

from xcvr_emu.transceiver import CMISTransceiver # type: ignore
from xcvr_emu.proto.emulator_pb2 import ( # type: ignore
ReadRequest,
WriteRequest,
)
from cmis import MemMap
from cmis.optoe import EEPROM

logger = logging.getLogger(__name__)



class XcvrEmuEeprom(XcvrEeprom):
def __init__(self, config: dict, mem_map=None):

codes = CmisCodes

self.xcvr = CMISTransceiver(
0,
{
"present": True,
"defaults": config,
},
mem_map,
)

super().__init__(self._read, self._write, CmisMemMap(codes))

def _read(self, offset, num_bytes):
if not self.xcvr.present:
return None
# convert optoe offset to SFF page and offset
# optoe maps the SFF 2D address to a linear address
page = offset // 128
if page > 0:
page = page - 1

if offset > 128:
offset = (offset % 128) + 128

return self.xcvr.read(
ReadRequest(index=0, offset=offset, page=page, length=num_bytes)
)

def _write(self, offset, num_bytes, write_buffer):
assert len(write_buffer) <= num_bytes
# convert optoe offset to SFF page and offset
# optoe maps the SFF 2D address to a linear address
page = offset // 128
if page > 0:
page = page - 1

if offset > 128:
offset = (offset % 128) + 128

return self.xcvr.write(
WriteRequest(
index=0,
page=page,
offset=offset,
length=num_bytes,
data=bytes(write_buffer),
)
)


@pytest.mark.asyncio
@pytest.mark.parametrize(
"emu_response, expected", [("1234567890", "1234567890"), ("ABCD", "ABCD")]
)
async def test_get_model(emu_response, expected):
eeprom = XcvrEmuEeprom(
{
"VendorPN": emu_response,
},
)
api = CmisApi(eeprom)
result = api.get_model()
result = result.rstrip("\x00")
await eeprom.xcvr.plugout()
assert result == expected

# hexdump taken from https://github.com/sonic-net/sonic-platform-common/issues/489#issue-2445591891
EEPROM_HEXDUMP = """00000000 18 40 00 07 00 00 00 00 00 00 00 00 00 00 17 00 |.@..............|
00000010 82 00 00 00 00 00 00 00 17 80 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 11 00 88 00 00 00 00 00 00 00 00 00 00 00 |................|
00000080 18 43 49 53 43 4f 20 20 20 20 20 20 20 20 20 20 |.CISCO |
00000090 20 00 06 f6 36 38 2d 31 30 33 32 30 35 2d 30 32 | ...68-103205-02|
000000a0 20 20 20 20 32 20 46 41 42 32 36 31 31 30 30 43 | 2 FAB261100C|
000000b0 51 20 20 20 20 20 32 32 31 30 31 38 20 20 00 00 |Q 221018 ..|
000000c0 00 00 00 00 00 00 00 00 e0 78 00 00 00 00 00 00 |.........x......|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f9 00 |................|
000000e0 1b 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|"""

@pytest.mark.asyncio
async def test_get_application_advertisement():
e = EEPROM()
e.load(EEPROM_HEXDUMP)
m = MemMap(e)
eeprom = XcvrEmuEeprom({}, m)
api = CmisApi(eeprom)

data = e.read(0, 0, 0, 256)
for f, v in m.decode(0, 0, data):
logger.info(f.to_str(value=v))

result = api.get_application_advertisement()
logger.info(f"Application Advertisement: {result}")

app_id = list(result.keys())[0]

with pytest.raises(KeyError):
result = api.get_media_lane_count()

result = api.get_media_lane_count(app_id)
logger.info(f"Media Lane Count: {result}")

await eeprom.xcvr.plugout()