Пример #1
0
    def test_multiple_matches(self):
        with patch("sys.stdout", new=StringIO()) as output:
            data = {
                "id": "test",
                "request": {
                    "url": "",
                    "method": "get",
                },
                "response": {
                    "text": "Hello World",
                },
            }

            mapping = MappingItem(data, "dummy.yml", os.getcwd())

            Log.multiple_matches([
                mapping,
                mapping,
            ])

            self.assertIn(
                "- dummy.yml\nID: test\nScenario: default\nURL: \nMethod: GET\nQuery String: \n- dummy.yml\nID: "
                "test\nScenario: default\nURL: \nMethod: GET\nQuery String:",
                output.getvalue().strip(),
            )
Пример #2
0
    def __init__(self):
        self.handler = MappingItemsManager()

        Log.ok("Server started successfully at {0}:{1}".format(
            "http://" + socket.gethostbyname(socket.gethostname()),
            cherrypy.config["server.socket_port"],
        ))
Пример #3
0
    def mapping_item_for_mapping_request(self, request):
        # try find by scenario
        mappings = [
            item for item in self.mappings
            if item.mock_scenario == Config.scenario
            and item.handles_mapping_request(request)
        ]

        if mappings:
            if Config.verbose:
                Log.info("Mapping found by scenario: {0}".format(
                    Config.scenario))

            return mappings

        # try find by default scenario
        mappings = [
            item for item in self.mappings
            if item.mock_scenario == Constants.DEFAULT_SCENARIO
            and item.handles_mapping_request(request)
        ]

        if mappings:
            if Config.verbose:
                Log.info("Mapping found by default scenario")

            return mappings

        return []
Пример #4
0
    def start():
        Log.info("Initializing server...")

        # update config
        cherrypy.config.update({
            "server.socket_port": Config.port,
            "server.socket_host": Config.host,
            "environment": "embedded",
            "tools.encode.text_only": False,
            "cors.expose.on": Config.cors,
        })

        # update config for verbose mode
        if Config.verbose:
            cherrypy.config.update({
                "log.screen": True,
            })

        # cors
        if Config.cors:
            cherrypy_cors.install()
            Log.info("CORS enabled")

        # listen for signal
        def signal_handler(signal, frame):
            Log.info("Shutting down server...")
            cherrypy.engine.exit()
            Log.ok("Server shutdown successfully")

        signal.signal(signal.SIGINT, signal_handler)

        # start server
        cherrypy.quickstart(CherryPyServer())
Пример #5
0
    def setup(self):
        is_image = self.body.body_type == BodyResponse.IMAGE
        is_file = self.body.body_type == BodyResponse.FILE
        is_json = self.body.body_type == BodyResponse.JSON

        if is_image or is_file:
            full_path = self.body_file_path()

            if os.path.isfile(full_path):
                self.headers["Accept-Ranges"] = "bytes"
                self.headers["Pragma"] = "public"
                self.headers["Content-Length"] = os.path.getsize(full_path)

                mimetype = mimetypes.guess_type(full_path)

                if mimetype:
                    self.headers["Content-Type"] = mimetype[0]

                if is_file:
                    self.headers[
                        "Content-Disposition"] = 'attachment; filename="{0}"'.format(
                            os.path.basename(full_path))
            else:
                Log.error("File not found: {0}".format(full_path), False)

                self.clear()
                self.status = 404
        elif is_json:
            self.headers["Content-Type"] = "application/json"
Пример #6
0
    def on_any_event(self, event):
        Log.info("Directory changed, rebuilding mapping settings...\n"
                 "Path: %s" % event.src_path +
                 "\nEvent type: %s" % event.event_type)

        Config.reload_sys_path_list()

        self.mapping_manager.parse_yaml_files()

        Log.ok("Mapping settings rebuilt successfully")
Пример #7
0
    def test_fail_with_fatal(self):
        with patch("sys.stdout", new=StringIO()) as output:
            exited = False

            try:
                Log.fail("fail message", True)
            except SystemExit as e:
                if e.code == 10:
                    exited = True

            self.assertIn("fail message", output.getvalue().strip())
            self.assertEqual(exited, True)
Пример #8
0
    def __init__(self, dic, base_path):
        self.base_path = base_path
        self.value = ""
        self._body_type = BodyResponse.NONE

        if dic:
            if "body_raw" in dic:
                self._body_type = BodyResponse.RAW
                self.file_name = ""
                self.value_from_raw(dic["body_raw"])

            elif "body_file" in dic:
                self._body_type = BodyResponse.FILE
                self.file_name = dic["body_file"]
                self.value_from_file(self.file_name)

            elif "body_image" in dic:
                self._body_type = BodyResponse.IMAGE
                self.file_name = dic["body_image"]
                self.value_from_image(self.file_name)

            elif "body_json" in dic:
                self._body_type = BodyResponse.JSON
                self.file_name = ""
                self.value_from_object(dic["body_json"])

            elif "body_python" in dic:
                self._body_type = BodyResponse.PYTHON
                self.file_name = dic["body_python"]

                # add sys path item to sys path list
                sys_path_list = dic["sys_path"] if "sys_path" in dic else []

                if sys_path_list:
                    for sys_path_item in sys_path_list:
                        if sys_path_item == "auto":
                            # auto = dir of python file
                            full_path = File.real_path(self.base_path,
                                                       self.file_name)
                            full_path = os.path.dirname(full_path)
                        else:
                            # create path from item specified
                            full_path = File.real_path(self.base_path,
                                                       sys_path_item)

                        if full_path not in sys.path:
                            Log.info("Path added to sys.path: {0}".format(
                                full_path))
                            sys.path.append(full_path)
Пример #9
0
    def form_fields_matches(self, form_fields):
        has_form_fields = self.form_fields != {}

        if has_form_fields:
            for key in self.form_fields.keys():
                if isinstance(form_fields, dict):
                    if key not in form_fields:
                        return False

                    try:
                        if not re.match(self.form_fields[key],
                                        form_fields[key]):
                            return False
                    except TypeError:
                        Log.failed("Invalid regex: {0}".format(
                            self.form_fields[key]))
                        return False
                else:
                    return False

        return True
Пример #10
0
    def test_response(self):
        with patch("sys.stdout", new=StringIO()) as output:
            data = {
                "url": "http://localhost/pymocky",
                "method": "post",
                "body": "Hello World",
            }

            response = MappingResponse("test_id", "test_scenario", data,
                                       os.getcwd())

            Log.log_response(response)

            self.assertIn("'mock_id': 'test_id'", output.getvalue().strip())
            self.assertIn("'mock_scenario': 'test_scenario'",
                          output.getvalue().strip())
            self.assertIn("'method': 'post'", output.getvalue().strip())
            self.assertIn("'body': 'Hello World'", output.getvalue().strip())
            self.assertIn("'status': 200", output.getvalue().strip())
            self.assertIn("'headers': {}", output.getvalue().strip())
            self.assertIn("'headers': {}", output.getvalue().strip())
Пример #11
0
    def test_request(self):
        with patch("sys.stdout", new=StringIO()) as output:
            data = {
                "url": "http://localhost/pymocky",
                "method": "post",
                "body": "Hello World",
            }

            request = MappingRequest("test_id", "test_scenario", data)

            Log.log_request(request, "http://localhost/pymocky")

            self.assertIn("'mock_id': 'test_id'", output.getvalue().strip())
            self.assertIn("'mock_scenario': 'test_scenario'",
                          output.getvalue().strip())
            self.assertIn("'url': 'http://localhost/pymocky'",
                          output.getvalue().strip())
            self.assertIn("'method': 'post'", output.getvalue().strip())
            self.assertIn("'headers': {}", output.getvalue().strip())
            self.assertIn("'body': 'Hello World'", output.getvalue().strip())
            self.assertIn("'form_fields': {}", output.getvalue().strip())
            self.assertIn("'query_string': ''", output.getvalue().strip())
Пример #12
0
    def parse_yaml_files(self):
        self.yaml_files = File.get_yaml_files(Config.path)
        self.mappings = []

        for yaml_file in self.yaml_files:
            full_path = os.path.join(Config.path, yaml_file)

            with open(full_path, "r") as file:
                file_data = yaml.load(file, yaml.SafeLoader)

                if "mappings" in file_data:
                    mappings = file_data["mappings"]

                    if mappings and isinstance(mappings, list):
                        for mapping in mappings:
                            new_mapping = MappingItem(
                                mapping,
                                full_path,
                                os.path.dirname(full_path),
                            )

                            self.mappings.append(new_mapping)

        Log.info("Mappings loaded: {0:d}".format(len(self.mappings)))
Пример #13
0
    def test_return_correct_body_for_multiple_response(self):
        item1 = Mock(file_name="file1")
        item1.request = "request1"

        item2 = Mock(file_name="file2")
        item2.request = "request2"

        # Config = Mock(verbose=True)

        mapper = CherryPyMapper()
        mapper.cherrypy = Mock()
        mapper.cherrypy.url = Mock(return_value="some url")

        body = Log.multiple_matches([item1, item2])

        self.assertEqual(
            body,
            "- file1\nrequest1\n- file2\nrequest2\n",
        )
Пример #14
0
    def process_python_data(self, process_data):
        full_path = File.real_path(self.base_path, self.body.file_name)

        # execute module "run" function
        try:
            if os.path.isfile(full_path):
                # return a dict from python file
                module_name = File.get_filename_without_extension(full_path)

                spec = importlib.util.spec_from_file_location(
                    module_name,
                    full_path,
                )

                module = importlib.util.module_from_spec(spec)
                spec.loader.exec_module(module)

                returned_data = module.run(process_data)

                # fill class with dict data
                self.status = (returned_data["status"]
                               if "status" in returned_data else 500)
                self.headers = (returned_data["headers"]
                                if "headers" in returned_data else {})
                self.body.value = (returned_data["body"]
                                   if "body" in returned_data else "")
            else:
                Log.error("File not found: {0}".format(full_path), False)
                self.status = 404
        except Exception as e:
            Log.error(
                "Error when execute file: {0}".format(
                    os.path.basename(full_path)),
                False,
            )
            Log.normal("Path: {0}".format(full_path))
            Log.normal("Error: {0}".format(repr(e)))

            self.status = 500
Пример #15
0
 def test_failed(self):
     with patch("sys.stdout", new=StringIO()) as output:
         Log.failed("failed message")
         self.assertIn("failed message", output.getvalue().strip())
Пример #16
0
 def signal_handler(signal, frame):
     Log.info("Shutting down server...")
     cherrypy.engine.exit()
     Log.ok("Server shutdown successfully")
Пример #17
0
    def __init__(self):
        self.parse_yaml_files()

        if Config.watch:
            Log.info("Live reload enabled")
            self.install_watchers()
Пример #18
0
    def handle_request(self):
        request = self.cherrypy.to_mapper_request()

        if Config.verbose:
            Log.info("Request data:")
            Log.normal(request)
        else:
            Log.request_url(self.cherrypy.url())

        items = self.mapping_handler.mapping_item_for_mapping_request(request)

        if len(items) == 0:
            self.cherrypy.response.status = 500
            Log.failed("No response found for request: {0}".format(
                self.cherrypy.url()))
            return "No response found for request"

        if len(items) > 1:
            Log.warn("Matched {0:d} items, choosing the first one".format(
                len(items)))

            if Config.verbose:
                Log.multiple_matches(items)

        matched_item = items[0]
        response = matched_item.response

        if Config.verbose:
            Log.log_request(matched_item.request, self.cherrypy.url())

        delay = Config.delay

        if delay > 0:
            delay = delay / 1000

            if Config.verbose:
                Log.info("Delay: {0:.3f}ms".format(delay))

            sleep(delay)

        if response.body.body_type == BodyResponse.PYTHON:
            response.process_python_data({"request": request})

        self.cherrypy.response.status = response.status
        self.fill_headers(response.headers)

        if Config.verbose:
            Log.log_response(response)

        return response.body_response()
Пример #19
0
    def __eq__(self, other):
        matches_method = self.method_matches(other.method)
        matches_url = self.url_matches(other.url)
        matches_body = self.body_matches(other.body)
        matches_headers = HeaderMatcher(self.headers).matches(other.headers)
        matches_form_fields = self.form_fields_matches(other.form_fields)
        matches_query_string = self.query_string_matches(other.query_string)

        if Config.verbose:
            Log.info("Mock tested:")
            Log.normal("Mock ID: {0}".format(self.mock_id))
            Log.normal("Mock Scenario: {0}".format(self.mock_scenario))
            Log.normal("Request URL: {0}".format(other.url))
            Log.normal("Mock URL: {0}".format(self.url))
            Log.normal("Matches Method: {0}".format(
                ("Yes" if matches_method else "No")))
            Log.normal("Matches URL: {0}".format(
                ("Yes" if matches_url else "No")))
            Log.normal("Matches Body: {0}".format(
                ("Yes" if matches_body else "No")))
            Log.normal("Matches Headers: {0}".format(
                ("Yes" if matches_headers else "No")))
            Log.normal("Matches Form Fields: {0}".format(
                ("Yes" if matches_form_fields else "No")))
            Log.normal("Matches Query String: {0}".format(
                ("Yes" if matches_query_string else "No")))

        return (matches_method and matches_url and matches_body
                and matches_headers and matches_form_fields
                and matches_query_string)
Пример #20
0
 def test_separator(self):
     with patch("sys.stdout", new=StringIO()) as output:
         Log.separator()
         self.assertIn("-" * 80, output.getvalue().strip())
Пример #21
0
 def test_colored(self):
     with patch("sys.stdout", new=StringIO()) as output:
         Log.colored("colored message", Fore.YELLOW)
         self.assertIn("colored message", output.getvalue().strip())
Пример #22
0
 def test_normal(self):
     with patch("sys.stdout", new=StringIO()) as output:
         Log.normal("normal message")
         self.assertIn("normal message", output.getvalue().strip())
Пример #23
0
 def test_url(self):
     with patch("sys.stdout", new=StringIO()) as output:
         Log.request_url("http://localhost/pymocky")
         self.assertIn("Request with url: http://localhost/pymocky",
                       output.getvalue().strip())
Пример #24
0
 def test_error(self):
     with patch("sys.stdout", new=StringIO()) as output:
         Log.error("error message", False)
         self.assertIn("error message", output.getvalue().strip())
Пример #25
0
    def run(args):
        if args.update_scenario:
            scenario = args.update_scenario

            if not scenario:
                scenario = Constants.DEFAULT_SCENARIO

            Log.info("Changing to scenario {0}...".format(scenario))

            try:
                r = requests.get(
                    "{0}/pymocky/update-scenario?scenario={1}".format(
                        args.server_host,
                        scenario,
                    ))

                if r.status_code == 200:
                    Log.ok("Scenario updated")
                else:
                    Log.failed("Scenario not updated: {0:d}".format(
                        r.status_code))
            except requests.exceptions.RequestException as e:
                Log.error("Scenario update error: {0}".format(e))
        elif args.reload:
            Log.info("Reloading...")

            try:
                r = requests.get("{0}/pymocky/reload".format(args.server_host))

                if r.status_code == 200:
                    Log.ok("Reloaded")
                else:
                    Log.failed("Reload failed: {0:d}".format(r.status_code))
            except requests.exceptions.RequestException as e:
                Log.error("Reload error: {0}".format(e))
        elif args.version:
            Log.normal("Version: {0}".format(__version__))
        else:
            if not args.path:
                Log.error("Path argument is required (--path or -p)")

            Config.sys_path_list = sys.path.copy()

            CherryPyServer.start()
Пример #26
0
 def test_info(self):
     with patch("sys.stdout", new=StringIO()) as output:
         Log.info("info message")
         self.assertIn("info message", output.getvalue().strip())