Skip to content

Commit

Permalink
[CI] When the CI is starting the server (chip-tool or darwin-framewor…
Browse files Browse the repository at this point in the history
…k-tool) wait to see for the websocket message ready before trying to connect
  • Loading branch information
vivien-apple committed Feb 8, 2024
1 parent 0d5170d commit a9034d6
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
5 changes: 5 additions & 0 deletions examples/common/websocket-server/WebSocketServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

constexpr uint16_t kDefaultWebSocketServerPort = 9002;
constexpr uint16_t kMaxMessageBufferLen = 8192;
constexpr char kWebSocketServerReadyMessage[] = "== WebSocket Server Ready";

namespace {
lws * gWebSocketInstance = nullptr;
Expand Down Expand Up @@ -153,6 +154,10 @@ static int OnWebSocketCallback(lws * wsi, lws_callback_reasons reason, void * us
{
gWebSocketInstance = nullptr;
}
else if (LWS_CALLBACK_PROTOCOL_INIT == reason)
{
ChipLogProgress(chipTool, "%s", kWebSocketServerReadyMessage);
}

return 0;
}
Expand Down
50 changes: 45 additions & 5 deletions scripts/py_matter_yamltests/matter_yamltests/websocket_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import re
import select
import subprocess
import time
from dataclasses import dataclass
Expand All @@ -24,6 +27,10 @@

_KEEP_ALIVE_TIMEOUT_IN_SECONDS = 120
_MAX_MESSAGE_SIZE_IN_BYTES = 10485760 # 10 MB
_CONNECT_MAX_RETRIES_DEFAULT = 3
_WEBSOCKET_SERVER_MESSAGE = '== WebSocket Server Ready'
_WEBSOCKET_SERVER_MESSAGE_TIMEOUT = 30 # seconds
_WEBSOCKET_SERVER_TERMINATE_TIMEOUT = 10 # seconds


@dataclass
Expand Down Expand Up @@ -54,7 +61,7 @@ def is_connected(self) -> bool:
return self._client.state == websockets.protocol.State.OPEN

async def start(self):
self._server = await self._start_server(self._server_startup_command)
self._server = await self._start_server(self._server_startup_command, self._server_connection_url)
self._client = await self._start_client(self._server_connection_url)

async def stop(self):
Expand All @@ -70,7 +77,7 @@ async def execute(self, request):
return await instance.recv()
return None

async def _start_client(self, url, max_retries=5, interval_between_retries=1):
async def _start_client(self, url, max_retries=_CONNECT_MAX_RETRIES_DEFAULT, interval_between_retries=1):
if max_retries:
start = time.time()
try:
Expand All @@ -93,15 +100,48 @@ async def _stop_client(self, instance):
if instance:
await instance.close()

async def _start_server(self, command):
async def _start_server(self, command, url):
instance = None
if command:
instance = subprocess.Popen(command, stdout=subprocess.DEVNULL)
start_time = time.time()

command = ['stdbuf', '-o0', '-i0'] + command # disable buffering
instance = subprocess.Popen(
command, text=True, bufsize=1, stdout=subprocess.PIPE)

# Loop to read the subprocess output with a timeout
lines = []
while True:
if time.time() - start_time > _WEBSOCKET_SERVER_MESSAGE_TIMEOUT:
for line in lines:
print(line, end='')
self._hooks.abort(url)
instance.kill()
raise Exception(
f'Connecting to {url} failed. The websocket startup has not been detected.')

ready, _, _ = select.select([instance.stdout], [], [], 1)
if ready:
line = instance.stdout.readline()
if line:
if re.search(_WEBSOCKET_SERVER_MESSAGE, line):
break # Exit the loop if the pattern is found
lines.append(line)
else:
continue
instance.stdout.close()

return instance

async def _stop_server(self, instance):
if instance:
instance.kill()
instance.terminate() # sends SIGTERM
try:
instance.wait(_WEBSOCKET_SERVER_TERMINATE_TIMEOUT)
except subprocess.TimeoutExpired:
logging.debug(
'Subprocess did not terminate on SIGTERM, killing it now')
instance.kill()

def _make_server_connection_url(self, address: str, port: int):
return 'ws://' + address + ':' + str(port)
Expand Down

0 comments on commit a9034d6

Please sign in to comment.