Пример #1
0
    def test_validate_command_choices_dictionary_list_response(
            self, validator):
        mock_client = Mock()
        mock_client.send_bg_request.return_value.output = '[{"value": "value"}]'
        validator._client = mock_client

        request = Request(
            system="foo",
            command="command1",
            parameters={"key1": "value"},
            system_version="0.0.1",
            instance_name="instance_name",
        )
        command = Mock(parameters=[
            Parameter(
                key="key1",
                choices=Choices(type="command", value="command_name"),
                optional=False,
            )
        ])

        validator.get_and_validate_parameters(request, command)
        mock_client.send_bg_request.assert_called_with(
            _command="command_name",
            _system_name="foo",
            _system_version="0.0.1",
            _instance_name="instance_name",
        )
Пример #2
0
 def test_command_lookup(self, monkeypatch, validator):
     request = Request(parameters={})
     lookup_mock = Mock(return_value=Mock(parameters=[]))
     monkeypatch.setattr(validator, "get_and_validate_command_for_system",
                         lookup_mock)
     validator.get_and_validate_parameters(request)
     lookup_mock.assert_called_once_with(request)
Пример #3
0
    def setUp(self):
        self.request_mock = Mock()

        self.ts_epoch = 1451606400000
        self.ts_dt = datetime.datetime(2016, 1, 1)
        self.request_dict = {
            "children": [],
            "parent": None,
            "system": "system_name",
            "system_version": "0.0.1",
            "instance_name": "default",
            "command": "say",
            "id": "58542eb571afd47ead90d25f",
            "parameters": {},
            "comment": "bye!",
            "output": "nested output",
            "output_type": "STRING",
            "status": "IN_PROGRESS",
            "command_type": "ACTION",
            "created_at": self.ts_epoch,
            "updated_at": self.ts_epoch,
            "error_class": None,
            "metadata": {},
            "has_parent": True,
            "requester": None,
        }
        self.job_dict = {
            "name": "job_name",
            "trigger_type": "date",
            "trigger": {"run_date": self.ts_epoch, "timezone": "utc"},
            "request_template": {
                "system": "system",
                "system_version": "1.0.0",
                "instance_name": "default",
                "command": "speak",
                "parameters": {"message": "hey!"},
                "comment": "hi!",
                "metadata": {"request": "stuff"},
            },
            "misfire_grace_time": 3,
            "coalesce": True,
            "next_run_time": self.ts_epoch,
            "success_count": 0,
            "error_count": 0,
        }
        db_dict = copy.deepcopy(self.job_dict)
        db_dict["request_template"] = RequestTemplate(**db_dict["request_template"])
        db_dict["trigger"]["run_date"] = self.ts_dt
        db_dict["trigger"] = DateTrigger(**db_dict["trigger"])
        db_dict["next_run_time"] = self.ts_dt
        self.job = Job(**db_dict)

        db_dict = copy.deepcopy(self.request_dict)
        db_dict["created_at"] = self.ts_dt
        db_dict["updated_at"] = self.ts_dt
        self.request = Request(**db_dict)

        super(RequestAPITest, self).setUp()
Пример #4
0
 def test_save_update_updated_at(self):
     request = Request(
         system="foo",
         command="bar",
         status="CREATED",
         updated_at="this_will_be_updated",
     )
     request.save()
     self.assertNotEqual(request.updated_at, "this_will_be_updated")
Пример #5
0
 def test_validate_value_in_choices_no_choices(self, validator):
     req = Request(system="foo",
                   command="command1",
                   parameters={"key1": "value"})
     command_parameter = Mock(key="key1",
                              multi=False,
                              type="String",
                              choices=None)
     command = Mock(parameters=[command_parameter])
     validator.get_and_validate_parameters(req, command)
Пример #6
0
    def test_update_and_validate_parameter_extract_parameter_multi_not_list(
            self, validator):
        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": "NOT A LIST"})
        command_parameter = Mock(key="key1", multi=True)
        command = Mock(parameters=[command_parameter])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #7
0
    def __init__(self, clients, heartbeat_interval=10, timeout_seconds=30):
        self.logger = logging.getLogger(__name__)
        self.display_name = "Plugin Status Monitor"
        self.clients = clients
        self.heartbeat_interval = heartbeat_interval
        self.timeout = timedelta(seconds=timeout_seconds)
        self.status_request = Request(command="_status",
                                      command_type="EPHEMERAL")

        super(PluginStatusMonitor, self).__init__(logger=self.logger,
                                                  name="PluginStatusMonitor")
Пример #8
0
 def test_update_and_validate_parameter_extract_parameter_nullable_no_default(
         self, validator):
     req = Request(system="foo", command="command1", parameters={})
     command_parameter = Parameter(key="key1",
                                   multi=False,
                                   nullable=True,
                                   default=None)
     command = Mock(parameters=[command_parameter])
     validated_parameters = validator.get_and_validate_parameters(
         req, command)
     assert validated_parameters["key1"] is None
Пример #9
0
 def test_validate_regex_nullable(self, validator):
     req = Request(system="foo",
                   command="command1",
                   parameters={"key1": None})
     command_parameter = Parameter(key="key1",
                                   multi=False,
                                   type="String",
                                   regex=r"^Hi.*",
                                   nullable=True)
     command = Command("test", parameters=[command_parameter])
     validator.get_and_validate_parameters(req, command)
Пример #10
0
    def test_update_and_validate_parameter_extract_parameter_optional_no_default(
            self, validator):
        req = Request(system="foo", command="command1", parameters={})
        command_parameter = Parameter(key="key1",
                                      multi=False,
                                      optional=True,
                                      default=None)
        command = Mock(parameters=[command_parameter])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #11
0
 def setUp(self):
     brew_view.backend = Mock()
     brew_view.transport = Mock()
     self.default_request = Request(
         system="foo",
         command="bar",
         parameters={"baz": "bat"},
         output="output",
         status="CREATED",
     )
     self.default_request.validate_backend = Mock()
     self.app = brew_view.app.test_client()
Пример #12
0
 def test_validate_value_in_choices_multi_valid_choice(self, validator):
     req = Request(system="foo",
                   command="command1",
                   parameters={"key1": ["v1", "v2"]})
     command_parameter = Mock(
         key="key1",
         multi=True,
         type="String",
         choices=Mock(type="static", value=["v1", "v2"]),
     )
     command = Mock(parameters=[command_parameter])
     validator.get_and_validate_parameters(req, command)
Пример #13
0
 def test_validate_value_in_choices_optional_none_allowed(self, validator):
     req = Request(system="foo", command="command1", parameters={})
     command_parameter = Mock(
         key="key1",
         multi=False,
         type="String",
         optional=True,
         default=None,
         choices=Mock(type="static", value=["value1", "value3"]),
     )
     command = Mock(parameters=[command_parameter])
     validator.get_and_validate_parameters(req, command)
Пример #14
0
    def test_extract_parameter_non_multi_calls_with_default(
            self, validate_mock, validator):
        req = Request(system="foo", command="command1", parameters={})
        command_parameter = Mock(key="key1",
                                 multi=False,
                                 default="default_value")
        command = Mock(parameters=[command_parameter])
        validate_mock.side_effect = lambda w, x, y, z: w

        validator.get_and_validate_parameters(req, command)
        validate_mock.assert_called_once_with("default_value",
                                              command_parameter, command, req)
Пример #15
0
    def test_validate_parameter_based_on_type_null_not_nullable(
            self, validator):
        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": None})
        command_parameter = Mock(key="key1",
                                 multi=False,
                                 type="String",
                                 nullable=False)
        command = Mock(parameters=[command_parameter])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #16
0
 def test_validate_maximum_nullable(self, validator):
     req = Request(system="foo",
                   command="command1",
                   parameters={"key1": None})
     command_parameter = Parameter(
         key="key1",
         multi=False,
         type="Integer",
         optional=False,
         minimum=3,
         nullable=True,
     )
     command = Command("test", parameters=[command_parameter])
     validator.get_and_validate_parameters(req, command)
Пример #17
0
    def test_validate_value_in_choices_multi_invalid_choice(self, validator):
        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": ["v1", "v2"]})
        command_parameter = Mock(
            key="key1",
            multi=True,
            type="String",
            optional=False,
            choices=Mock(type="static", value=["v1", "v3"]),
        )
        command = Mock(parameters=[command_parameter])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #18
0
    def test_missing_nested_parameters(self, validator):
        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": {}})
        nested_parameter = Mock(key="foo",
                                multi=False,
                                type="String",
                                optional=False)
        command_parameter = Mock(key="key1",
                                 multi=False,
                                 type="Dictionary",
                                 parameters=[nested_parameter])
        command = Mock(parameters=[command_parameter])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #19
0
    def test_update_and_validate_parameter_extract_parameter_multi(
            self, validate_mock, validator):
        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": [1, 2]})
        command_parameter = Mock(key="key1", multi=True)
        command = Mock(parameters=[command_parameter])
        validate_mock.side_effect = lambda w, x, y, z: w

        validator.get_and_validate_parameters(req, command)
        validate_mock.assert_has_calls(
            [
                call(1, command_parameter, command, req),
                call(2, command_parameter, command, req),
            ],
            any_order=True,
        )
Пример #20
0
    def setUp(self):
        self.app = brew_view.app.test_client()

        self.default_request = Request(
            system="foo",
            command="bar",
            parameters={"baz": "bat"},
            output="output",
            status="CREATED",
        )
        self.default_request.validate_backend = Mock()

        objects_patch = patch("bg_utils.mongo.models.Request.objects")
        self.addCleanup(objects_patch.stop)
        self.objects_mock = objects_patch.start()
        self.objects_mock.return_value = None
        self.objects_mock.get = Mock(return_value=self.default_request)
Пример #21
0
    def test_validate_command_choices_bad_value_type(self, validator):
        mock_client = Mock()
        mock_client.send_bg_request.return_value.output = '["value"]'
        validator._client = mock_client

        request = Request(
            system="foo",
            command="command1",
            parameters={"key1": "value"},
            system_version="0.0.1",
            instance_name="instance_name",
        )
        command = Mock(parameters=[
            Parameter(key="key1",
                      optional=False,
                      choices=Choices(type="command", value=1))
        ])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(request, command)
Пример #22
0
    def test_validate_minimum_non_sequence(self, validator):
        req = Request(system="foo", command="command1", parameters={"key1": 5})

        command_parameter = Parameter(key="key1",
                                      multi=False,
                                      type="Integer",
                                      optional=False,
                                      minimum=3)
        command = Command("test", parameters=[command_parameter])
        validator.get_and_validate_parameters(req, command)

        command_parameter = Parameter(key="key1",
                                      multi=False,
                                      type="Integer",
                                      optional=False,
                                      minimum=10)
        command = Command("test", parameters=[command_parameter])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #23
0
    def test_validate_choices_static_bad_type(self, validator):
        command_parameter = Mock(
            key="key1",
            multi=False,
            type="String",
            optional=False,
            default=None,
            choices=Mock(type="static", value="bad str"),
            minimum=None,
            maximum=None,
            regex=None,
        )

        command = Mock(parameters=[command_parameter])

        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": "1"})

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #24
0
    def test_validate_url_choices(self, validator, response):
        session_mock = Mock()
        session_mock.get.return_value.text = response
        validator._session = session_mock

        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": "value"})
        command_parameter = Mock(
            key="key1",
            type="String",
            optional=False,
            multi=False,
            choices=Mock(type="url", value="http://localhost"),
            minimum=None,
            maximum=None,
            regex=None,
        )
        command = Mock(parameters=[command_parameter])

        validator.get_and_validate_parameters(req, command)
        session_mock.get.assert_called_with("http://localhost", params={})
Пример #25
0
    def test_validate_regex(self, validator):
        req = Request(system="foo",
                      command="command1",
                      parameters={"key1": "Hi World!"})

        command_parameter = Parameter(key="key1",
                                      multi=False,
                                      type="String",
                                      optional=False,
                                      regex=r"^Hi.*")
        command = Command("test", parameters=[command_parameter])
        validator.get_and_validate_parameters(req, command)

        command_parameter = Parameter(key="key1",
                                      multi=False,
                                      type="String",
                                      optional=False,
                                      regex=r"^Hello.*")
        command = Command("test", parameters=[command_parameter])

        with pytest.raises(ModelValidationError):
            validator.get_and_validate_parameters(req, command)
Пример #26
0
 def test_clean_fail_bad_status(self):
     request = Request(system="foo", command="bar", status="bad")
     self.assertRaises(ModelValidationError, request.clean)
Пример #27
0
    def post(self):
        """
        ---
        summary: Create a new Request
        parameters:
          - name: request
            in: body
            description: The Request definition
            schema:
              $ref: '#/definitions/Request'
          - name: blocking
            in: query
            required: false
            description: Flag indicating whether to wait for request completion
            type: boolean
            default: false
          - name: timeout
            in: query
            required: false
            description: Maximum time (seconds) to wait for request completion
            type: integer
            default: None (Wait forever)
        consumes:
          - application/json
          - application/x-www-form-urlencoded
        responses:
          201:
            description: A new Request has been created
            schema:
              $ref: '#/definitions/Request'
            headers:
              Instance-Status:
                type: string
                description: |
                    Current status of the Instance that will process the
                    created Request
          400:
            $ref: '#/definitions/400Error'
          50x:
            $ref: '#/definitions/50xError'
        tags:
          - Requests
        """
        self.request.event.name = Events.REQUEST_CREATED.name

        if self.request.mime_type == "application/json":
            request_model = self.parser.parse_request(
                self.request.decoded_body, from_string=True)
        elif self.request.mime_type == "application/x-www-form-urlencoded":
            args = {"parameters": {}}
            for key, value in self.request.body_arguments.items():
                if key.startswith("parameters."):
                    args["parameters"][key.replace("parameters.",
                                                   "")] = value[0].decode(
                                                       self.request.charset)
                else:
                    args[key] = value[0].decode(self.request.charset)
            request_model = Request(**args)
        else:
            raise ModelValidationError(
                "Unsupported or missing content-type header")

        if request_model.parent:
            request_model.parent = Request.objects.get(
                id=str(request_model.parent.id))
            if request_model.parent.status in Request.COMPLETED_STATUSES:
                raise ConflictError("Parent request has already completed")
            request_model.has_parent = True
        else:
            request_model.has_parent = False

        if self.current_user:
            request_model.requester = self.current_user.username

        # Ok, ready to save
        request_model.save()
        request_id = str(request_model.id)

        # Set up the wait event BEFORE yielding the processRequest call
        blocking = self.get_argument("blocking", default="").lower() == "true"
        if blocking:
            brew_view.request_map[request_id] = Event()

        with thrift_context() as client:
            try:
                yield client.processRequest(request_id)
            except bg_utils.bg_thrift.InvalidRequest as ex:
                request_model.delete()
                raise ModelValidationError(ex.message)
            except bg_utils.bg_thrift.PublishException as ex:
                request_model.delete()
                raise RequestPublishException(ex.message)
            except Exception:
                if request_model.id:
                    request_model.delete()
                raise

        # Query for request from body id
        req = Request.objects.get(id=request_id)

        # Now attempt to add the instance status as a header.
        # The Request is already created at this point so it's a best-effort thing
        self.set_header("Instance-Status", "UNKNOWN")

        try:
            # Since request has system info we can query for a system object
            system = System.objects.get(name=req.system,
                                        version=req.system_version)

            # Loop through all instances in the system until we find the instance that
            # matches the request instance
            for instance in system.instances:
                if instance.name == req.instance_name:
                    self.set_header("Instance-Status", instance.status)

        # The Request is already created at this point so adding the Instance status
        # header is a best-effort thing
        except Exception as ex:
            self.logger.exception(
                "Unable to get Instance status for Request %s: %s", request_id,
                ex)

        self.request.event_extras = {"request": req}

        # Metrics
        request_created(request_model)

        if blocking:
            # Publish metrics and event here here so they aren't skewed
            # See https://github.com/beer-garden/beer-garden/issues/190
            self.request.publish_metrics = False
            http_api_latency_total.labels(
                method=self.request.method.upper(),
                route=self.prometheus_endpoint,
                status=self.get_status(),
            ).observe(request_latency(self.request.created_time))

            self.request.publish_event = False
            brew_view.event_publishers.publish_event(
                self.request.event, **self.request.event_extras)

            try:
                timeout = self.get_argument("timeout", default=None)
                delta = timedelta(seconds=int(timeout)) if timeout else None

                event = brew_view.request_map.get(request_id)

                yield event.wait(delta)

                request_model.reload()
            except TimeoutError:
                raise TimeoutExceededError("Timeout exceeded for request %s" %
                                           request_id)
            finally:
                brew_view.request_map.pop(request_id, None)

        self.set_status(201)
        self.write(
            self.parser.serialize_request(request_model, to_string=False))
Пример #28
0
 def test_no_request_command(self, validator):
     with pytest.raises(ModelValidationError):
         validator.get_and_validate_command_for_system(
             Request(system="foo", parameters={}), Mock())
Пример #29
0
 def test_empty(self, validator):
     req = Request(system="foo", command="command1")
     command = Command(parameters=[])
     assert validator.get_and_validate_parameters(req, command) == {}
Пример #30
0
 def test_clean_fail_bad_output_type(self):
     request = Request(system="foo", command="bar", output_type="BAD")
     self.assertRaises(ModelValidationError, request.clean)