com.bmc.gibraltar.automation.dataprovider.RestDataProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.bmc.gibraltar.automation.dataprovider.RestDataProvider.java

Source

package com.bmc.gibraltar.automation.dataprovider;

import com.bmc.gibraltar.automation.api.*;
import com.bmc.gibraltar.automation.framework.utils.PropertiesUtils;
import com.bmc.gibraltar.automation.items.component.Component;
import com.bmc.gibraltar.automation.items.element.Property;
import com.bmc.gibraltar.automation.items.parameter.DataType;
import com.bmc.gibraltar.automation.items.record.RecordField;
import com.bmc.gibraltar.automation.utils.JsonUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.path.json.JsonPath;
import com.jayway.restassured.specification.RequestSpecification;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.log4j.Logger;
import ru.yandex.qatools.allure.annotations.Step;

import java.io.*;
import java.net.HttpURLConnection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.lang.String.format;

public class RestDataProvider {
    protected static final Logger LOG = Logger.getLogger(RestDataProvider.class);
    private static String appServerUrl = PropertiesUtils.getAppServerUrl();
    private AssociationApi associationApi;
    private OrganizationApi organizationApi;
    private ProcessApi processApi;
    private RecordApi recordApi;
    private UserManagementApi userManagementApi;
    private ViewApi viewApi;
    private RuleApi ruleApi;

    public RestDataProvider() {
        RestAssured.baseURI = appServerUrl;
        userManagementApi = new UserManagementApi();
        initializeRestData(userManagementApi.getRequestSpecification());
    }

    public RestDataProvider(String loginName, String userPassword) {
        RestAssured.baseURI = appServerUrl;
        userManagementApi = new UserManagementApi(loginName, userPassword);
        initializeRestData(userManagementApi.getRequestSpecification());
    }

    private static JsonObject generateJsonForUserCreation(String fullName, String loginName, String password,
            String emailAddress, String[] permissionGroups) {
        JsonObject request = new JsonObject();
        request.addProperty("fullName", fullName);
        request.addProperty("loginName", loginName);
        request.addProperty("password", password);
        request.addProperty("emailAddress", emailAddress);
        request.add("groups", new Gson().toJsonTree(permissionGroups));
        return request;
    }

    private void initializeRestData(RequestSpecification requestSpecification) {
        associationApi = new AssociationApi(requestSpecification);
        organizationApi = new OrganizationApi(requestSpecification);
        processApi = new ProcessApi(requestSpecification);
        recordApi = new RecordApi(requestSpecification);
        viewApi = new ViewApi(requestSpecification);
        ruleApi = new RuleApi(requestSpecification);
    }

    private List<String> getBundleScopeHeaders() {
        return processApi.getBundleScopeHeaders();
    }

    private String generateAbsoluteDefinitionNameBasedOnHeader(String header, String recordDefinitionName) {
        return processApi.generateAbsoluteDefinitionNameBasedOnHeader(header, recordDefinitionName);
    }

    public String getCurrentUserLoginName() {
        return getUserProfilePart("$USER$", "loginName");
    }

    private String getUserProfilePart(String user, String infoPart) {
        return JsonPath.from(userManagementApi.getUserInfo(user).and().extract().asString()).get(infoPart);
    }

    /**
     * This method allows to get user groups or computedGroups
     *
     * @param userLoginName $USER$ if current logged user, or 'username'
     * @param groups        should equal to 'groups' or 'computedGroups'
     * @return list of the user's groups
     */
    public List<String> getUserGroups(String userLoginName, String groups) {
        return JsonPath.from(userManagementApi.getUserInfo(userLoginName).extract().asString()).get(groups);
    }

    public boolean isUserExistent(String userLoginName) {
        int statusCode = userManagementApi.getUserInfo(userLoginName).extract().statusCode();
        return statusCode == HttpURLConnection.HTTP_OK;
    }

    /**
     * Will create a user with the specified info.
     *
     * @param fullName         the user's full name
     * @param loginName        the user's loginName (<loginname>@<tenant domain identifier>)
     *                         the user will be created in the same tenant group as the admin who creates him,
     *                         so  <tenant domain identifier> is set automatically
     * @param password         the user's password
     * @param emailAddress     the user's email address
     * @param permissionGroups groups to which the user belongs to.
     *                         To get all available permitted groups for currently logged user:
     *                         GET /api/rx/application/datapage?dataPageType=com.bmc.arsys.rx.application.group
     *                         .datapage.GroupDataPageQuery&pageSize=-1&startIndex=0
     */
    public void createUser(String fullName, String loginName, String password, String emailAddress,
            String[] permissionGroups) {
        JsonObject request = generateJsonForUserCreation(fullName, loginName, password, emailAddress,
                permissionGroups);
        String jsonString = new GsonBuilder().create().toJson(request);
        if (!isUserExistent(loginName)) {
            userManagementApi.createUserRequest(jsonString);
        }
    }

    /**
     * Allows to create a user for organizations.
     *
     * @param name             example "CokeHRUser".
     * @param license          there are 4 types("Read", "Restricted", "Fixed", "Floating") .
     * @param domain           there are 2 types("pepsi", "coke").
     * @param permissionGroups example(..., "Administrator", "CokeHR" ), where "CokeHR" - organization name.
     */
    public String createUserByLicense(String name, String password, String domain, String license,
            String... permissionGroups) {
        String loginName = format("%s@%s.com", name, domain);
        JsonObject request = generateJsonForUserCreation(name, name, password, loginName, permissionGroups);
        request.addProperty("status", "Current");
        request.addProperty("password", password);
        request.addProperty("licenseType", license);
        String jsonString = new GsonBuilder().create().toJson(request);
        userManagementApi.createUserRequest(jsonString);
        return loginName;
    }

    // TODO: Rewrite for all record definitions.
    /**
     * The method creates an association with name []To[] example createAssociation("A", "B") creates AToB association.
     *
     * @param fromRecordDefinitionName a name of special Record Definition, with hardcoded id. Was send by server side.
     *                                 AssociationRecordDefinition.json - template of mentioned record.
     * @param toRecordDefinitionName   the same as fromRecordDefinitionName.
     */
    public void createAssociation(String fromRecordDefinitionName, String toRecordDefinitionName) {
        String json = JsonUtils.getJsonFromFile("AssociationTemplate.json")
                .replaceAll("APoint", fromRecordDefinitionName).replaceAll("BPoint", toRecordDefinitionName);
        associationApi.createAssociationDefinition(json);
    }

    public String createOrganization(String json) {
        return organizationApi.createOrganization(json).toString();
    }

    private String createJsonForDefinition(String definitionName, String jsonTemplateFileName) {
        String json = JsonUtils.getJsonFromFile(jsonTemplateFileName);
        return json.replace("UniqueNameShouldBeChanged", definitionName).replaceAll("IDShouldBeGenerated",
                RandomStringUtils.randomAlphanumeric(16));
    }

    /**
     * Creates a new rule, based on json template. Template includes trigger and is based on Task record.
     * Before creation, it should post createProcessAndRecordForRulesCreation() only once for a build!
     */
    public void createRuleByTemplate(String ruleName) {
        ruleApi.createRuleDefinition(createJsonForDefinition(ruleName, "RuleTemplate.json"));
    }

    public String createProcessDefinition(String requestBody) {
        return processApi.createProcessDefinition(requestBody).extract().asString();
    }

    public void createProcessDefinition(String definitionName, String jsonTemplateFileName) {
        processApi.createProcessDefinition(createJsonForDefinition(definitionName, jsonTemplateFileName));
    }

    public void createRecordDefinition(String definitionName, String jsonTemplateFileName) {
        recordApi.createRecordDefinition(createJsonForDefinition(definitionName, jsonTemplateFileName));
    }

    public void createRecordDefinition(String requestBody) {
        recordApi.createRecordDefinition(requestBody);
    }

    public boolean isUserInComputedGroup(String user, String computedGroup) {
        List<String> group = getUserGroups(user, "computedGroups");
        return group != null && group.contains(computedGroup);
    }

    public boolean isUserInGroup(String user, String group) {
        List<String> groups = getUserGroups(user, "groups");
        return groups != null && groups.contains(group);
    }

    public String getProcessDefinitionID(String processDefinitionName) {
        return JsonPath.from(getProcessDefinitionInfo(processDefinitionName)).get("id");
    }

    public String getProcessDefinitionInfo(String processDefinitionName) {
        try {
            return processApi.getProcessDefinitionJson(processDefinitionName).extract().asString();
        } catch (AssertionError e) {
            String definitionName = getBundleScopeHeaders().stream()
                    .map(header -> generateAbsoluteDefinitionNameBasedOnHeader(header, processDefinitionName))
                    .filter(absoluteDefinitionName -> processApi.getProcessDefinition(absoluteDefinitionName)
                            .extract().statusCode() == HttpURLConnection.HTTP_OK)
                    .findFirst().get();
            return processApi.getProcessDefinitionJson(definitionName).extract().asString();
        }
    }

    public List<String> getProcessDefinitionsNamesByState(boolean isEnabled) {
        String processDefinitionsInfo = processApi.getAllProcessDefinitionsInfo().extract().asString();
        List<String> processDefinitionNames = JsonPath.from(processDefinitionsInfo)
                .getList(" data.findAll { it.isEnabled == '" + isEnabled + "' }.name");
        return processDefinitionsWithoutBundle(processDefinitionNames);
    }

    /**
     * @return list of all created process definitions
     */
    public List<String> getProcessDefinitionsNames(boolean isAbsoluteName) {
        List<String> processDefinitionNames = processApi.getAllProcessDefinitionsInfo().extract().path("data.name");
        if (isAbsoluteName) {
            return processDefinitionNames;
        } else {
            return processDefinitionsWithoutBundle(processDefinitionNames);
        }
    }

    private List<String> processDefinitionsWithoutBundle(List<String> processDefinitionNames) {
        return processDefinitionNames.stream().map(pd -> pd.replaceAll(RestApiData.TASK_MANAGER_HEADER + ":", ""))
                .map(pd -> pd.replaceAll(RestApiData.APPROVAL_HEADER + ":", ""))
                .map(pd -> pd.replaceAll(RestApiData.FOUNDATION_HEADER + ":", "")).collect(Collectors.toList());
    }

    /**
     * Start a process instance for the process definition with {@param processDefinitionId} and returns the response body
     *
     * @param processDefinitionId process definition ID for which a process instance will be started
     * @return response body
     */
    @Step
    public String startProcess(String processDefinitionId) {
        String bodyOfRequest = new GsonBuilder().create()
                .toJson(buildRequestToStartProcessInstance(processDefinitionId));
        return processApi.startProcessInstance(bodyOfRequest).extract().toString();
    }

    private JsonObject buildRequestToStartProcessInstance(String processDefinitionId) {
        JsonObject request = new JsonObject();
        request.addProperty("processDefinitionId", processDefinitionId);
        request.addProperty("resourceType",
                "com.bmc.arsys.rx.application.process.command.StartProcessInstanceCommand");
        return request;
    }

    public String startProcessWithInputs(String processDefinitionId, HashMap<String, String> inputs) {
        JsonObject request = buildRequestToStartProcessInstance(processDefinitionId);
        JsonObject inputsOfProcessDefinition = new JsonObject();
        for (Map.Entry<String, String> entry : inputs.entrySet()) {
            inputsOfProcessDefinition.addProperty(entry.getKey(), entry.getValue());
        }
        request.add("processInputValues", inputsOfProcessDefinition);
        String bodyOfRequest = new GsonBuilder().create().toJson(request);
        return processApi.startProcessInstance(bodyOfRequest).extract().toString();
    }

    /**
     * Returns JSon of the specified process definition with the {@param processDefinitionName}
     *
     * @param processDefinitionName process definition name
     * @return json of the process definition with the {@param processDefinitionName}
     */
    public String getJsonOfProcess(String processDefinitionName) {
        return processApi.getProcessDefinitionJson(processDefinitionName).extract().asString();
    }

    /**
     * Sends request to get all Group Data and extracts all existed Permissions.
     *
     * @return List of all existed Permissions from server side.
     */
    @Step("user extracted all existed Permissions")
    public List<String> getGroupNames() {
        return JsonPath.from(userManagementApi.getAllPermittedGroups().toString()).get("groupName");
    }

    /**
     * In the Process Designer should be present groups which 'groupId > 9'
     *
     * @return list of permitted groups visible for the currently logged user
     */
    public List<String> getPermittedGroups() {
        return JsonPath.from(userManagementApi.getAllPermittedGroups().toString())
                .getList(" data.findAll { it.groupId > 9 }.groupName");
    }

    /**
     * This method collects process inputs of the specified process definition
     *
     * @param processDefinitionName process definition name
     * @return process inputs of the specific process definition with the {@param processDefinitionName}
     */
    public String getInputsOfProcessDefinition(String bundle, String processDefinitionName) {
        return processApi.getInputsOfProcessDefinition(bundle + processDefinitionName).extract().asString();
    }

    public List<String> getRequiredInputsOfProcessDefinition(String bundle, String decodedProcessDefinitionName) {
        return JsonPath.from(getInputsOfProcessDefinition(bundle, decodedProcessDefinitionName))
                .<String>getList(" findAll { it.fieldOption == 'REQUIRED' "
                        + "&& (it.defaultValue == null || it.defaultValue == '')}.name");
    }

    public List<String> getCustomFieldDefinitionTypes() {
        return processApi.getCustomFieldDefinition().extract().path("data.fieldDefinitionType");
    }

    /**
     * Returns all Record Definitions names, visible for current user
     */
    public List<String> getRecordDefinitionNames() {
        List<String> parsedRecords = recordApi.getAbsoluteRecordDefinitionNames().and().extract().body()
                .path("data");
        parsedRecords.stream()
                .map(line -> line.replaceAll(RestApiData.APPROVAL_HEADER + ":", "")
                        .replaceAll(RestApiData.TASK_MANAGER_HEADER + ":", "")
                        .replaceAll(RestApiData.USER_MESSAGE_HEADER + ":", "")
                        .replaceAll(RestApiData.FOUNDATION_HEADER + ":", "")
                        .replaceAll(RestApiData.RXN_HEADER, "/"))
                .collect(Collectors.toList());
        LOG.info("\n All Records: \n" + parsedRecords);
        return parsedRecords;
    }

    /**
     * Returns list of  Record Field names for a particular Record Definition name
     *
     * @param record record definition name
     */
    public List<String> getRecordFields(String record) {
        String response = getRecFields(record);
        List<String> output = JsonPath.from(response).getList("fieldDefinitions.name");
        LOG.info("\n Record Definition: '" + record + "'  has such [ALL] RecordFields: " + output.toString());
        return output;
    }

    private List<String> getListOfFields(String record, String propertyName, String expectedPropertyValue) {
        String response = getRecFields(record);
        List<String> output = JsonPath.from(response).getList(
                "fieldDefinitions.findAll { it." + propertyName + " == '" + expectedPropertyValue + "'}.name");
        LOG.info("\n Record Definition '" + record + "'  has such fields :" + output.toString() + " that have "
                + propertyName + " with '" + expectedPropertyValue + "' value.");
        return output;
    }

    public List<String> getListOfFieldsWithoutDefaultValue(RecordField.Option option, String recordDefinitionName) {
        String response = getRecFields(recordDefinitionName);
        return JsonPath.from(response).getList("fieldDefinitions.findAll { it.fieldOption == '" + option
                + "' && (it.defaultValue == null || it.defaultValue == '')}.name");
    }

    public List<String> getListOfFieldsByType(String recordDefinitionName, DataType type) {
        String response = getRecFields(recordDefinitionName);
        return JsonPath.from(response)
                .getList("fieldDefinitions.findAll { it.resourceType == '" + type.getResourceType() + "'}.name");
    }

    /**
     * Returns list of  Record Field names of a particular fieldOption (SYSTEM/REQUIRED/OPTIONAL)
     * and for a particular Record Definition name
     *
     * @param option should be be SYSTEM, REQUIRED or OPTIONAL
     * @param record record definition name
     * @return list of the fields
     */
    public List<String> getRecordFieldsNamesByFieldOption(RecordField.Option option, String record) {
        return getListOfFields(record, "fieldOption", option.name());
    }

    public List<String> getRecordFieldsNamesByProperty(String record, String propertyName,
            String expectedPropertyValue) {
        return getListOfFields(record, propertyName, expectedPropertyValue);
    }

    /**
     * Collect all selection fields and their options from the specified {@param record} record definition name
     *
     * @param record record definition name
     * @return HashMap where 'String' is a name of the selection field, and 'List<String>' - its options
     */
    public Map<String, List<String>> getSelectionFieldsAndOptions(String record) {
        JsonPath response = JsonPath.from(getRecFields(record));
        String optionsPath = "fieldDefinitions.find { it.name == '%s'}.options";
        List<String> selectionFields = getRecordFieldsNamesByProperty(record, "resourceType",
                DataType.SELECTION.getResourceType());
        return selectionFields.stream().collect(Collectors.toMap(selectionField -> selectionField,
                selectionField -> response.getList(String.format(optionsPath, selectionField))));
    }

    private String getRecFields(String recordDefinitionName) {
        try {
            return recordApi.getRecordDefinitionJson(recordDefinitionName).extract().asString();
        } catch (AssertionError e) {
            String definitionName = getBundleScopeHeaders().stream()
                    .map(header -> generateAbsoluteDefinitionNameBasedOnHeader(header, recordDefinitionName))
                    .filter(absoluteDefinitionName -> recordApi.getRecordDefinition(absoluteDefinitionName)
                            .extract().statusCode() == HttpURLConnection.HTTP_OK)
                    .findFirst().get();
            return recordApi.getRecordDefinitionJson(definitionName).extract().asString();
        }
    }

    @Step
    public String getTaskInfo(String taskGuid) {
        return recordApi.getRecordInstance(RestApiData.TASK_RECORD_DEFINITION, taskGuid).extract().asString();
    }

    @Step
    public String getTasks() {
        return recordApi.getRecordInstances(RestApiData.TASK_RECORD_DEFINITION).extract().asString();
    }

    @Step
    public int getTasksCount() {
        return JsonPath.from(getTasks()).get("totalSize");
    }

    @Step
    public String getTaskByTaskName(String taskName) {
        return recordApi.getRecordInstancesByFieldValue(RestApiData.TASK_RECORD_DEFINITION, "10007000", taskName)
                .extract().asString();
    }

    @Step
    public List<String> getInstanceIds(String recordDefinitionName) {
        return JsonPath.from(recordApi.getRecordInstances(recordDefinitionName).extract().asString())
                .get("data.id");
    }

    @Step
    public void createTask(String recordDefinitionName, String submitter, String assignee, String statusCode,
            String summary, String notes, String taskName, String priorityCode, String dueDate) {
        JsonObject bodyRequest = new JsonObject();
        bodyRequest.addProperty("resourceType", "com.bmc.arsys.rx.services.record.domain.RecordInstance");
        bodyRequest.addProperty("recordDefinitionName", recordDefinitionName);
        // fields to create a record instance
        JsonObject recordProperty = new JsonObject();
        addRecordFieldToRequest(recordProperty, "2", submitter); // submitter of the record instance
        addRecordFieldToRequest(recordProperty, "4", assignee); // assignee
        addRecordFieldToRequest(recordProperty, "7", statusCode); // status: 0 ( staged )
        addRecordFieldToRequest(recordProperty, "8", summary); // summary
        addRecordFieldToRequest(recordProperty, "10000101", notes); // notes
        addRecordFieldToRequest(recordProperty, "10007000", taskName); // task-name
        addRecordFieldToRequest(recordProperty, "10007122", priorityCode); // priority: 2 ( medium )
        addRecordFieldToRequest(recordProperty, "536870913", dueDate); // due date
        bodyRequest.add("fieldInstances", recordProperty);
        String request = new GsonBuilder().create().toJson(bodyRequest);
        recordApi.createRecordInstance(request);
    }

    @Step
    public void updateTask(String taskGuid, String fieldToUpdate, String newFieldValue) {
        JsonObject bodyRequest = new JsonObject();
        bodyRequest.addProperty("resourceType", "com.bmc.arsys.rx.services.record.domain.RecordInstance");
        bodyRequest.addProperty("id", taskGuid);
        bodyRequest.addProperty("recordDefinitionName", RestApiData.TASK_RECORD_DEFINITION);
        JsonObject recordProperty = new JsonObject();
        addRecordFieldToRequest(recordProperty, fieldToUpdate, newFieldValue); // submitter of the record instance
        bodyRequest.add("fieldInstances", recordProperty);
        String request = new GsonBuilder().create().toJson(bodyRequest);
        recordApi.updateRecordInstance(RestApiData.TASK_RECORD_DEFINITION, taskGuid, request);
    }

    private JsonObject addRecordFieldToRequest(JsonObject recordProperty, String fieldId, String fieldValue) {
        JsonObject nestedArray = new JsonObject();
        nestedArray.addProperty("resourceType", "com.bmc.arsys.rx.services.record.domain.FieldInstance");
        nestedArray.addProperty("id", fieldId);
        nestedArray.addProperty("value", fieldValue);
        recordProperty.add(fieldId, nestedArray);
        return recordProperty;
    }

    /**
     * Get all existing view definitions
     *
     * @return list of all created view definitions
     */
    public String getAllViewDefinitions() {
        return viewApi.getAllViewDefinitions().extract().asString();
    }

    /**
     * Get ID of the specified view definition with the {@param viewDefinitionName}
     * View definition should be in the task-manager bundle.
     *
     * @param viewDefinitionName view definition name
     * @return view definition ID
     */
    public String getViewDefinitionId(String viewDefinitionName) {
        String absoluteViewDefinitionName = RestApiData.TASK_MANAGER_HEADER + ":" + viewDefinitionName;
        return JsonPath.from(getAllViewDefinitions())
                .get("data.find { it.name == '" + absoluteViewDefinitionName + "' }.id");
    }

    /**
     * Get json of the view definition with the {@param viewDefinitionId}
     *
     * @param viewDefinitionId ID of the view definition
     * @return view definition json
     */
    public String getViewDefinition(String viewDefinitionId) {
        return viewApi.getViewDefinition(viewDefinitionId).extract().asString();
    }

    /**
     * @param viewDefinitionName name of View Definition
     * @return list of names for all Components, present in viewDefinitionName
     */
    public List<String> getAllComponentsForViewDefinition(String viewDefinitionName) {
        List<String> allComponents = JsonPath.from(getViewDefinition(getViewDefinitionId(viewDefinitionName)))
                .getList("componentDefinitions.type");
        for (String componentType : allComponents) {
            Collections.replaceAll(allComponents, componentType, Component.getNameByType(componentType));
        }
        LOG.info("\n--> Components for View '" + viewDefinitionName + "': " + allComponents);
        return allComponents;
    }

    /**
     * Get ID of the specified {@param componentDefinitionType} from the view definition with {@param viewDefinitionId}
     * If there are more than one the same typed component on a Canvas, this method returns the first one ID
     *
     * @param viewDefinitionId        ID of the view definition
     * @param componentDefinitionType type of the component (e.g. 'rx-activity-feed')
     * @return ID of the component
     */
    public String getComponentDefinitionId(String viewDefinitionId, String componentDefinitionType) {
        return JsonPath.from(getViewDefinition(viewDefinitionId))
                .getList("componentDefinitions.findAll " + "{ it.type == '" + componentDefinitionType + "' }.id")
                .get(0).toString();
    }

    /**
     * @param viewDefinitionName
     * @param componentName
     * @return Map of properties and their values for required {@viewDefinitionName} and {@componentName}.
     * Where keys - properties of component, values - values of property correspondingly
     */
    public HashMap<String, String> getMapOfComponentProperties(String viewDefinitionName, String componentName) {
        String componentType = Component.getTypeByName(componentName);
        Map<String, String> propertiesMap = JsonPath
                .from(getViewDefinition(getViewDefinitionId(viewDefinitionName)))
                .getMap("componentDefinitions.find " + "{ it.type == '" + componentType + "' }.propertiesByName");
        //Replacing all Map's keys from camelCaseFormat to Property Names Format
        HashMap<String, String> formattedMap = new HashMap<>();
        for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
            formattedMap.put(Property.splitCamelCase(entry.getKey()), entry.getValue());
        }
        return formattedMap;
    }

    /**
     * Download file with the {@param attachmentName} name that was uploaded for the task
     *
     * @param taskGuid       task GUID
     * @param attachmentName name of the file that was attached to the task
     * @return downloaded file
     */
    @Step
    public File getTaskAttachment(String taskGuid, String attachmentName) {
        LOG.info("Downloading an attachment with the name: " + attachmentName + " of the task with GUID: "
                + taskGuid);
        File downloadedFile = null;
        try {
            InputStream is = recordApi
                    .getRecordInstanceContent(RestApiData.TASK_RECORD_DEFINITION, taskGuid, attachmentName)
                    .extract().asInputStream();
            downloadedFile = new File(System.getProperty("java.io.tmpdir"), attachmentName);
            BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(downloadedFile));
            byte[] b = new byte[1024 * 1024];
            int read;
            while ((read = is.read(b)) > -1) {
                bout.write(b, 0, read);
            }
            bout.flush();
            bout.close();
            is.close();
        } catch (IOException e) {
            LOG.error("Cannot download a file " + attachmentName + " from server: " + e);
            e.printStackTrace();
        }
        return downloadedFile;
    }

    public void logout() {
        userManagementApi.logout();
    }
}