def get_amount_of_workloads(self, topic: str, **kwargs) -> int:
        """
        Retrieves count of tasks. By default expects a topic name, but all parameters from the original endpoint
        may be provided: https://docs.camunda.org/manual/latest/reference/rest/external-task/get-query-count/
        """
        with self._shared_resources.api_client as api_client:
            api_instance = openapi_client.ExternalTaskApi(api_client)

            try:
                response: CountResultDto = api_instance.get_external_tasks_count(
                    topic_name=topic, **kwargs)
            except ApiException as e:
                raise ApiException(
                    f'Failed to count workload for topic "{topic}":\n{e}')

        logger.info(f'Amount of workloads for "{topic}":\t{response.count}')
        return response.count
    def deploy(self, *args):
        """Creates a deployment from all given files and uploads them to camunda.

        Return response from camunda rest api as dictionary.
        Further documentation: https://docs.camunda.org/manual/7.14/reference/rest/deployment/post-deployment/

        By default, this keyword only deploys changed models and filters duplicates. Deployment name is the filename of
        the first file.

        Example:
            | ${response} | *Deploy model from file* | _../bpmn/my_model.bpnm_ | _../forms/my_forms.html_ |
        """
        if not args:
            raise ValueError(
                'Failed deploying model, because no file provided.')

        if len(args) > 1:
            # We have to use plain REST then when uploading more than 1 file.
            return self.deploy_multiple_files(*args)

        filename = os.path.basename(args[0])

        with self._shared_resources.api_client as api_client:
            api_instance = openapi_client.DeploymentApi(api_client)
            data = [*args]
            deployment_name = filename

            try:
                response: DeploymentWithDefinitionsDto = api_instance.create_deployment(
                    deploy_changed_only=True,
                    enable_duplicate_filtering=True,
                    deployment_name=deployment_name,
                    data=data)
                logger.info(f'Response from camunda:\t{response}')
            except ApiException as e:
                logger.error(f'Failed to upload {filename}:\n{e}')
                raise e

        return response.to_dict()
    def get_deployments(self, deployment_id: str = None, **kwargs):
        """
        Retrieves all deployments that match given criteria. All parameters are available from https://docs.camunda.org/manual/latest/reference/rest/deployment/get-query/

        Example:
            | ${list_of_deployments} | get deployments | ${my_deployments_id} |
            | ${list_of_deployments} | get deployments | id=${my_deployments_id} |
            | ${list_of_deployments} | get deployments | after=2013-01-23T14:42:45.000+0200 |
        """
        if deployment_id:
            kwargs['id'] = deployment_id

        with self._shared_resources.api_client as api_client:
            api_instance = openapi_client.DeploymentApi(api_client)

            try:
                response: List[DeploymentDto] = api_instance.get_deployments(
                    **kwargs)
                logger.info(f'Response from camunda:\t{response}')
            except ApiException as e:
                raise ApiException(f'Failed get deployments:\n{e}')

        return [r.to_dict() for r in response]
    def start_process(self,
                      process_key: str,
                      variables: Dict = None,
                      files: Dict = None,
                      before_activity_id: str = None,
                      after_activity_id: str = None,
                      **kwargs) -> Dict:
        """
        Starts a new process instance from a process definition with given key.

        variables: _optional_ dictionary like: {'variable name' : 'value'}

        files: _optional_ dictionary like: {'variable name' : path}. will be attached to variables in Camunda

        before_activity_id: _optional_ id of activity at which the process starts before. *CANNOT BE USED TOGETHER WITH _after_activity_id_*

        after_activity_id: _optional_ id of activity at which the process starts after. *CANNOT BE USED TOGETHER WITH _before_activity_id_*

        Returns response from Camunda as dictionary

        == Examples ==
        | `start process`      | apply for job promotion    | _variables_= { 'employee' : 'John Doe', 'permission_for_application_granted' : True}   | _files_ = { 'cv' : 'documents/my_life.md'}  | _after_activity_id_ = 'Activity_ask_boss_for_persmission'   |
        | `start process` | apply for promotion | business_key=John again |
        """
        if not process_key:
            raise ValueError(
                'Error starting process. No process key provided.')

        if before_activity_id and after_activity_id:
            raise AssertionError(
                '2 activity ids provided. Cannot start before and after an activity.'
            )

        with self._shared_resources.api_client as api_client:
            api_instance: ProcessDefinitionApi = openapi_client.ProcessDefinitionApi(
                api_client)
            openapi_variables = CamundaResources.convert_dict_to_openapi_variables(
                variables)
            openapi_files = CamundaResources.convert_file_dict_to_openapi_variables(
                files)
            openapi_variables.update(openapi_files)

            if before_activity_id or after_activity_id:
                instruction: ProcessInstanceModificationInstructionDto = ProcessInstanceModificationInstructionDto(
                    type='startBeforeActivity'
                    if before_activity_id else 'startAfterActivity',
                    activity_id=before_activity_id
                    if before_activity_id else after_activity_id,
                )
                kwargs.update(start_instructions=[instruction])

            start_process_instance_dto: StartProcessInstanceDto = StartProcessInstanceDto(
                variables=openapi_variables, **kwargs)

            try:
                response: ProcessInstanceWithVariablesDto = api_instance.start_process_instance_by_key(
                    key=process_key,
                    start_process_instance_dto=start_process_instance_dto)
            except ApiException as e:
                logger.error(f'Failed to start process {process_key}:\n{e}')
                raise e
        logger.info(f'Response:\n{response}')

        return response.to_dict()
    def fetch_workload(self,
                       topic: str,
                       async_response_timeout=None,
                       use_priority=None,
                       **kwargs) -> Dict:
        """
        Locks and fetches workloads from camunda on a given topic. Returns a list of variable dictionary.
        Each dictionary representing 1 workload from a process instance.

        If a process instance was fetched, the process instance is cached and can be retrieved by keyword
        `Get recent process instance`

        The only mandatory parameter for this keyword is *topic* which is the name of the topic to fetch workload from.
        More parameters can be added from the Camunda documentation: https://docs.camunda.org/manual/7.14/reference/rest/external-task/fetch/

        If not provided, this keyword will use a lock_duration of 60000 ms (10 minutes) and set {{deserialize_value=True}}

        Examples:
            | ${input_variables} | *Create Dictionary* | _name=Robot_ |
            | | *start process* | _my_demo_ | _${input_variables}_ |
            | ${variables} | *fetch and lock workloads* | _first_task_in_demo_ |
            | | *Dictionary Should Contain Key* | _${variables}_ | _name_ |
            | | *Should Be Equal As String* | _Robot_ | _${variables}[name]_ |

        Example deserializing only some variables:
            | ${input_variables} | *Create Dictionary* | _name=Robot_ | _profession=Framework_ |
            | | *start process* | _my_demo_ | _${input_variables}_ |
            | ${variables_of_interest} | *Create List* | _profession_ |
            | ${variables} | *Fetch Workload* | _first_task_in_demo_ | _variables=${variables_of_interest}_ |
            | | *Dictionary Should Not Contain Key* | _${variables}_ | _name_ |
            | | *Dictionary Should Contain Key* | _${variables}_ | _profession_ |
            | | *Should Be Equal As String* | _Framework_ | _${variables}[profession]_ |
        """
        api_response = []
        with self._shared_resources.api_client as api_client:
            # Create an instance of the API class
            api_instance = openapi_client.ExternalTaskApi(api_client)
            if 'lock_duration' not in kwargs:
                kwargs['lock_duration'] = 60000
            if 'deserialize_values' not in kwargs:
                kwargs['deserialize_values'] = True
            topic_dto = FetchExternalTaskTopicDto(topic_name=topic, **kwargs)
            fetch_external_tasks_dto = FetchExternalTasksDto(
                worker_id=self.WORKER_ID,
                max_tasks=1,
                async_response_timeout=async_response_timeout,
                use_priority=use_priority,
                topics=[topic_dto])

            try:
                api_response = api_instance.fetch_and_lock(
                    fetch_external_tasks_dto=fetch_external_tasks_dto)
                logger.info(api_response)
            except ApiException as e:
                logger.error(
                    "Exception when calling ExternalTaskApi->fetch_and_lock: %s\n"
                    % e)

        work_items: List[LockedExternalTaskDto] = api_response
        if work_items:
            logger.debug(
                f'Received {len(work_items)} work_items from camunda engine for topic:\t{topic}'
            )
        else:
            logger.debug(
                f'Received no work items from camunda engine for topic:\t{topic}'
            )

        if not work_items:
            return {}

        self.FETCH_RESPONSE = work_items[0]

        variables: Dict[str, VariableValueDto] = self.FETCH_RESPONSE.variables
        return CamundaResources.convert_openapi_variables_to_dict(variables)