Skip to content

Commit

Permalink
Completion of API tests plus websockets (#16)
Browse files Browse the repository at this point in the history
* move audio response to conftest and 1 assert headers

* add websocket mock

* websocket test

* use fixtures from pytest-aiohttp plugin

* try using real files in tmp dir

* check real file

* mock_open influenced on ws!!! fix

* fix assert

* fix var name

* fix await
  • Loading branch information
alekssamos authored Oct 17, 2022
1 parent 739788b commit 1410aa4
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 18 deletions.
10 changes: 10 additions & 0 deletions tests/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,13 @@ async def test_get_voices_list_api(cli_srv_mss):
client, server, mss = cli_srv_mss
voices = await mss.get_voices_list()
assert len(voices) == 3 # check API mock

@pytest.mark.asyncio
async def test_synthesize_api(cli_srv_mss):
client, server, mss = cli_srv_mss
vn = (await mss.get_voices_by_substring("Guy"))[0]["Name"]
await mss.set_voice(vn)
filename = "test.opus"
await mss.synthesize("hi!", filename)
with open(filename, "rb") as f:
assert f.read() == b"theaudiofile"
79 changes: 74 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import asyncio
from typing import AsyncGenerator, Generator, Tuple
from aiohttp.test_utils import TestClient, TestServer
import aiohttp
import pytest
import pytest_asyncio
from msspeech import MSSpeech
Expand Down Expand Up @@ -46,13 +47,47 @@ async def fake_get_voices_list(obj):
yield mss


@pytest.fixture
def sp_audio()->bytes:
return (
b".."
+ b"X-RequestId:586e68cb7617113bee75\r\n"
+ b"Content-Type:audio/webm; codec=opus\r\n"
+ b"X-StreamId:D9C8CDE8B3E2451D84D416C9A44310CC\r\n"
+ b"Path:audio\r\n"
+ b"theaudiofile"
)

@pytest.fixture
def sp_config()->dict:
return {
"context": {
"synthesis": {
"audio": {
"metadataoptions": {
"sentenceBoundaryEnabled": "false",
"wordBoundaryEnabled": "true",
},
"outputFormat": "audio-24khz-48kbitrate-mono-mp3",
}
}
}
}



@pytest_asyncio.fixture
async def cli_srv_mss(
monkeypatch,
sp_audio,
sp_config,
aiohttp_client,
aiohttp_server,
tmp_path,
) -> AsyncGenerator[Tuple[TestClient, TestServer, MSSpeech], None]:
"Create and return mock client and server for msspeech API and return mocked MSSpeech class instance"
from aiohttp import web
from unittest.mock import mock_open, patch
import json

@web.middleware
async def check_request(request, handler):
Expand Down Expand Up @@ -120,18 +155,52 @@ async def get_voices_list_handler(request):
]
)

@routes.get("/consumer/speech/synthesize/readaloud/edge/v1")
async def websocket_handler(request):

ws = web.WebSocketResponse()
await ws.prepare(request)

async for msg in ws:
if msg.type == aiohttp.WSMsgType.TEXT:
if msg.data == 'close':
await ws.close()
else:
headers, body = msg.data.split("\r\n\r\n", 1)
if "Content-Type:application/json" in headers and "Path:speech.config" in headers:
body = json.loads(body)
assert body == sp_config
await ws.send_str("""Content-Type:application/json\r\nPath:qwe.rty\r\n\r\n{"something":"not_used_for_me"}""")
if "Content-Type:application/ssml+xml" in headers and "Path:ssml" in headers:
for x in [
"<speak", "<voice", "</prosody>",
"</speak>", "</voice>", "</prosody>",
]:
assert x in body
await ws.send_bytes(sp_audio)
await ws.send_str("""Content-Type:application/json\r\nPath:qwe.rty\r\n\r\n{"something":"not_used_for_me"}""")
await ws.send_str("""Content-Type:application/json\r\nPath:qwe.rty\r\n\r\n{}""")
elif msg.type == aiohttp.WSMsgType.ERROR:
print('ws connection closed with exception %s' %
ws.exception())

print('websocket connection closed')

return ws

app.add_routes(routes)

test_server = TestServer(app)
test_server = await aiohttp_server(app)
await test_server.start_server()
test_client = TestClient(test_server)
test_client = await aiohttp_client(test_server)
monkeypatch.setattr("msspeech.os.path.isfile", lambda x: False)
monkeypatch.setattr("msspeech._voices_list", [])
monkeypatch.setattr(
"msspeech.MSSpeech.endpoint",
f"{test_server.scheme}://{test_server.host}:{test_server.port}/",
)
monkeypatch.setattr("msspeech.MSSpeech.trustedclienttoken", "testtoken")
with patch("builtins.open", new_callable=mock_open):
yield (test_client, test_server, MSSpeech())
monkeypatch.setattr("msspeech.msspeech_dir", str(tmp_path))
monkeypatch.chdir(tmp_path)
yield (test_client, test_server, MSSpeech())
await test_client.close()
16 changes: 3 additions & 13 deletions tests/extract_response_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,15 @@ async def test_extract_response_str(mss):

@pytest.mark.asyncio
# @pytest.mark.xfail()
async def test_extract_response_bytes(mss):
async def test_extract_response_bytes(mss, sp_audio):
expected_headers = {
"X-RequestId": "586e68cb7617113bee75",
"Content-Type": "audio/webm; codec=opus",
"X-StreamId": "D9C8CDE8B3E2451D84D416C9A44310CC",
"Path": "audio",
}
expected_body = b"theaudiofile"
response = (
b".."
+ b"X-RequestId:586e68cb7617113bee75\r\n"
+ b"Content-Type:audio/webm; codec=opus\r\n"
+ b"X-StreamId:D9C8CDE8B3E2451D84D416C9A44310CC\r\n"
+ b"Path:audio\r\n"
+ b"theaudiofile"
)
response = sp_audio
headers, body = mss._extract_response(response)
assert body == expected_body
# assert headers["X-RequestId"] == expected_headers["X-RequestId"]
assert headers["X-StreamId"] == expected_headers["X-StreamId"]
assert headers["Content-Type"] == expected_headers["Content-Type"]
assert headers["Path"] == expected_headers["Path"]
assert headers == expected_headers

0 comments on commit 1410aa4

Please sign in to comment.