maksaska commented on code in PR #13470: URL: https://github.com/apache/ignite/pull/13470#discussion_r3956800508
########## modules/ducktests/tests/checks/utils/check_pause.py: ########## @@ -0,0 +1,407 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Checks demo breakpoints. +""" + +import json +import os +import threading +import time +from types import SimpleNamespace + +import pytest + +from ignitetest.services.utils.path import IgnitePathAware +from ignitetest.utils.pause import ALL, CONTINUE_ALL, ABORT, DemoPause, RUNNER_TIMEOUT_MARGIN_SEC, STATUS_JSON, \ + STATUS_TXT, continue_file, parse_selector + + +class FakeLogger: + """ + Collects what a paused test would have logged. + """ + def __init__(self): + self.messages = [] + + def info(self, msg): + """Records an info message.""" + self.messages.append(msg) + + def warn(self, msg): + """Records a warning.""" + self.messages.append(msg) + + debug = info + error = warn + + +def _fake_nodes(*hostnames): + return [SimpleNamespace(account=SimpleNamespace(hostname=host, externally_routable_ip=host)) + for host in hostnames] + + +class FakeService: + """ + Stands in for a non-Ignite service of the test registry, e.g. a zookeeper one: it carries + paths of its own, which the banner must not hand out for Ignite nodes. + """ + log_dir = "/mnt/service/zk-logs" + config_file = "/mnt/service/zookeeper.properties" + + def __init__(self, *hostnames): + self.nodes = _fake_nodes(*hostnames) + + def who_am_i(self, node): + """Names the node the way a ducktape service does.""" + return f"{self.__class__.__name__}-{node.account.hostname}" + + +class FakeIgniteService(IgnitePathAware): + """ + Stands in for an Ignite service, with the real path layout behind it. + """ + def __init__(self, *hostnames): + self.nodes = _fake_nodes(*hostnames) + + def who_am_i(self, node): + """Names the node the way a ducktape service does.""" + return f"{self.__class__.__name__}-{node.account.hostname}" + + @property + def product(self): + return "ignite-dev" + + @property + def globals(self): + return {} + + +class FakeRegistry: + """ + Stands in for ducktape's ServiceRegistry, which is what a test hands the breakpoint: it is + iterable and nothing else, so a banner may not index it or ask it for a length. + """ + def __init__(self, *services): + self._services = services + + def __iter__(self): + return iter(self._services) + + +def _pause(control_dir, started_at=None, runner_timeout_sec=None, **test_globals): + return DemoPause(FakeLogger(), test_globals, "check.CheckPause.check_something", control_dir=str(control_dir), + started_at=started_at, runner_timeout_sec=runner_timeout_sec) + + +def _read_published(control_dir, resume_with=None, timeout_sec=30): + """ + Reads the published breakpoint while the test blocks on it, the way the host console does, + and optionally resumes it. + + Polls for the file rather than reading it once after a fixed delay: a breakpoint that is + only held for a fraction of a second - which is what these checks hold them for - would + otherwise be a race against the machine the checks happen to run on. + + :return: The dict that is filled in once the breakpoint has been published, and the reader + to join before reading it. + """ + published = {} + + def act(): + deadline = time.monotonic() + timeout_sec + + while time.monotonic() < deadline: + try: + with open(os.path.join(str(control_dir), STATUS_JSON), encoding="utf-8") as file: + published.update(json.load(file)) + + break + except (OSError, ValueError): + time.sleep(.01) + + if resume_with: + open(os.path.join(str(control_dir), resume_with), "w").close() + + reader = threading.Thread(target=act, daemon=True) + reader.start() + + return published, reader + + +def _resume_with(control_dir, name, delay_sec=.05): + """ + Creates a resume file from another thread, the way the host does while the test blocks. + """ + timer = threading.Timer(delay_sec, lambda: open(os.path.join(str(control_dir), name), "w").close()) + timer.daemon = True + timer.start() + + return timer + + +def check_selector_parsing(): Review Comment: It's a tradition to write unit tests with 'check'. tox is configured to discover all tests -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
