com.formkiq.web.AbstractIntegrationTest.java Source code

Java tutorial

Introduction

Here is the source code for com.formkiq.web.AbstractIntegrationTest.java

Source

/*
 * Copyright (C) 2016 FormKiQ Inc.
 *
 * Licensed 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.
 */

package com.formkiq.web;

import static com.formkiq.core.api.AbstractRestController.ACCEPT_HEADER_V1_JSON;
import static com.formkiq.core.api.FolderFilesController.API_FOLDER_FILE;
import static com.formkiq.core.api.FolderFilesController.API_FOLDER_FILE_LIST;
import static com.formkiq.core.api.FoldersController.API_FOLDER;
import static com.formkiq.core.api.FoldersController.API_FOLDER_SAVE;
import static com.formkiq.core.api.ObjectEventsController.API_EVENTS_SAVE;
import static com.formkiq.core.api.QueueController.API_FOLDER_FILE_MESSAGES;
import static com.formkiq.core.api.SystemController.API_SYSTEM_PROPERTIES_DELETE;
import static com.formkiq.core.api.SystemController.API_SYSTEM_PROPERTIES_SAVE;
import static com.formkiq.core.api.UserNotificationController.API_USER_NOTIFICATION_LIST;
import static com.formkiq.core.api.UsersController.API_USER_GET;
import static com.formkiq.core.api.UsersController.API_USER_SAVE;
import static com.formkiq.core.api.UsersController.OAUTH_TOKEN;
import static com.formkiq.core.form.FormFinder.findValueByKey;
import static com.formkiq.core.service.SystemPropertyService.INVITE_ONLY;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.util.StringUtils.hasText;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.Before;
import org.junit.BeforeClass;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;

import com.formkiq.core.config.LoggerMailSender;
import com.formkiq.core.dao.DaoTests;
import com.formkiq.core.dao.SystemDao;
import com.formkiq.core.domain.SystemProperty;
import com.formkiq.core.domain.type.EventType;
import com.formkiq.core.domain.type.FolderFormStatus;
import com.formkiq.core.domain.type.FolderFormsListDTO;
import com.formkiq.core.domain.type.FolderPermission;
import com.formkiq.core.domain.type.OAuthGrantTypes;
import com.formkiq.core.domain.type.QueueListDTO;
import com.formkiq.core.domain.type.UserDTO;
import com.formkiq.core.domain.type.UserNotificationListDTO;
import com.formkiq.core.domain.type.UserRole;
import com.formkiq.core.domain.type.UserStatus;
import com.formkiq.core.form.JSONService;
import com.formkiq.core.form.dto.ArchiveDTO;
import com.formkiq.core.form.dto.FormJSON;
import com.formkiq.core.form.dto.Workflow;
import com.formkiq.core.form.dto.WorkflowOutput;
import com.formkiq.core.service.ArchiveService;
import com.formkiq.core.service.AssetServiceS3;
import com.formkiq.core.service.OAuthService;
import com.formkiq.core.service.dto.ApiMessageResponse;
import com.formkiq.core.service.dto.Setup;
import com.formkiq.core.service.dto.SystemConfig;
import com.formkiq.core.service.formInterceptor.SetupInterceptor;
import com.formkiq.core.service.formInterceptor.SystemConfigInterceptor;
import com.formkiq.core.service.notification.MailSenderService;
import com.formkiq.core.util.Resources;
import com.formkiq.core.util.Strings;
import com.formkiq.core.util.Zips;

/**
 * AbstractIntegrationTest.
 *
 */
public abstract class AbstractIntegrationTest extends DaoTests {

    /** Default email. */
    private static final String DEFAULT_EMAIL = "test@formkiq.com";

    /** Default pass. */
    private static final String DEFAULT_PASS = "pass";

    /** Test Client ID. */
    private static String clientID;

    /** Test client secret. */
    private static String clientSecret;

    /** Test Host. */
    private static final String DEFAULT_HOST = "localhost";

    /** Test Host. */
    private static final int DEFAULT_PORT = 8080;

    /** User Access Tokens lookup. */
    private static final Map<String, String> ACCESS_TOKENS = new HashMap<>();

    /** {@link SetupInterceptor}. */
    @Autowired
    private SetupInterceptor setupInterceptor;

    /** {@link SystemConfigInterceptor}. */
    @Autowired
    private SystemConfigInterceptor systemConfigInterceptor;

    /**
     * Before Class.
     */
    @BeforeClass
    public static void beforeClass() {
        System.setProperty("system.setup", "");
    }

    /**
     * Set Client information.
     * @param clientid {@link String}
     * @param clientsecret {@link String}
     */
    private static void setClient(final String clientid, final String clientsecret) {
        clientID = clientid;
        clientSecret = clientsecret;
    }

    /** Test Rest Template. */
    private TestRestTemplate template = new TestRestTemplate();

    /** {@link ArchiveService}. */
    @Autowired
    private ArchiveService archiveService;

    /** AssetServiceS3. */
    @Autowired
    private AssetServiceS3 assetServiceS3;

    /** EntityManager. */
    @Autowired
    private EntityManager entityManager;

    /** TransactionManager. */
    @Autowired
    private PlatformTransactionManager transactionManager;

    /** JSONService. */
    @Autowired
    private JSONService jsonService;

    /** OAuthService. */
    @Autowired
    private OAuthService oauthservice;

    /** MailSenderService. */
    @Autowired
    private MailSenderService mailsender;

    /** SystemDao. */
    @Autowired
    private SystemDao systemDao;

    /**
     * Add File to Folder.
     * @param token {@link String}
     * @param folder {@link String}
     * @param data byte[]
     * @return {@link ResponseEntity}
     */
    protected ResponseEntity<String> addFileToFolder(final String token, final String folder, final byte[] data) {

        String url = getDefaultHostAndPort() + API_FOLDER_FILE + "/" + folder + "?access_token=" + token;
        ResponseEntity<String> entity = exchangeRest(HttpMethod.POST, url, data, String.class);

        assertEquals("{\"message\":\"Save successful\"}", entity.getBody());

        assertEquals(SC_OK, entity.getStatusCode().value());

        return entity;
    }

    /**
     * Add File to Folder.
     * @param token {@link String}
     * @param folder {@link String}
     * @param form {@link FormJSON}
     * @return {@link ResponseEntity}
     * @throws IOException IOException
     */
    @Deprecated
    protected ResponseEntity<String> addFileToFolder(final String token, final String folder, final FormJSON form)
            throws IOException {

        String text = this.jsonService.writeValueAsString(form);
        byte[] data = Zips.zipFile(form.getUUID() + ".form", text);
        return addFileToFolder(token, folder, data);
    }

    /**
     * Add File to Folder.
     * @param token {@link String}
     * @param folder {@link String}
     * @param workflow {@link Workflow}
     * @param forms {@link Collection}
     * @return {@link ResponseEntity}
     * @throws IOException IOException
     */
    protected ResponseEntity<String> addFileToFolder(final String token, final String folder,
            final Workflow workflow, final Collection<FormJSON> forms) throws IOException {

        Map<String, byte[]> map = new HashMap<>();
        map.put(workflow.getUUID() + ".workflow", this.jsonService.writeValueAsBytes(workflow));

        for (FormJSON form : forms) {
            map.put(form.getUUID() + ".form", this.jsonService.writeValueAsBytes(form));
        }

        byte[] data = Zips.zipFile(map);
        return addFileToFolder(token, folder, data);
    }

    /**
     * Add File to Folder.
     * @param token {@link String}
     * @param folder {@link String}
     * @param archive {@link ArchiveDTO}
     * @return {@link ResponseEntity}
     * @throws IOException IOException
     */
    protected ResponseEntity<String> addFileToFolder(final String token, final String folder,
            final ArchiveDTO archive) throws IOException {

        byte[] data = this.archiveService.createZipFile(archive);
        return addFileToFolder(token, folder, data);
    }

    /**
     * Add File to Folder.
     * @param token {@link String}
     * @param folder {@link String}
     * @param workflow {@link Workflow}
     * @param forms {@link List}
     * @return {@link ResponseEntity}
     * @throws IOException IOException
     */
    protected ResponseEntity<String> addFileToFolder(final String token, final String folder,
            final Workflow workflow, final FormJSON... forms) throws IOException {

        List<FormJSON> list = forms == null ? Collections.emptyList() : Arrays.asList(forms);

        return addFileToFolder(token, folder, workflow, list);
    }

    /**
     * Adds User thru webservice.
     * @param email {@link String}
     */
    protected void addUser(final String email) {

        String token = login(getDefaultEmail());
        setProperty(token, INVITE_ONLY, "false");

        String url = getDefaultHostAndPort() + API_USER_SAVE + "?email=" + email + "&password=" + DEFAULT_PASS
                + "&confirmpassword=" + DEFAULT_PASS;

        ResponseEntity<String> entity = exchangeRestBasicAuth(HttpMethod.POST, url);

        assertEquals(SC_OK, entity.getStatusCode().value());
        assertEquals("{\"message\":\"User has been saved\"}", entity.getBody());
    }

    /**
     * Setup tests.
     * @throws Exception Exception
     */
    @Before
    public void before() throws Exception {

        String prop = System.getProperty("system.setup");

        if (!hasText(prop)) {

            truncateDatabase();

            Pair<String, String> client = setupSystem();

            setClient(client.getLeft(), client.getRight());

            ACCESS_TOKENS.clear();

            System.setProperty("system.setup", "true");
        }

        login(getDefaultEmail(), getDefaultPass());

        getMailSender().reset();
        this.assetServiceS3.reloadProperties();
    }

    /**
     * Creates New Form.
     *
     * @param token {@link String}
     * @param foldername {@link String}
     * @return {@link String}
     * @throws IOException IOException
     */
    protected String createFolder(final String token, final String foldername) throws IOException {
        return createFolder(token, foldername, getDefaultEmail());
    }

    /**
     * Creates New Form.
     *
     * @param token {@link String}
     * @param foldername {@link String}
     * @param email {@link String}
     * @return {@link String}
     * @throws IOException IOException
     */
    protected String createFolder(final String token, final String foldername, final String email)
            throws IOException {

        String url = getDefaultHostAndPort() + API_FOLDER_SAVE + "?foldername=" + foldername + "&access_token="
                + token;

        if (StringUtils.hasText(email)) {
            url += "&email=" + email;
        }

        ResponseEntity<String> entity = exchangeRest(HttpMethod.POST, url);

        assertEquals(SC_OK, entity.getStatusCode().value());

        ApiMessageResponse dto = this.jsonService.readValue(entity.getBody(), ApiMessageResponse.class);

        assertEquals("Folder added", dto.getMessage());

        return dto.getId();
    }

    /**
     * Create User.
     * @param token {@link String}
     * @param email {@link String}
     * @param pass {@link String}
     */
    protected void createUser(final String token, final String email, final String pass) {
        createUser(token, email, pass, null);
    }

    /**
     * Create User.
     * @param token {@link String}
     * @param email {@link String}
     * @param pass {@link String}
     * @param loginToken {@link String}
     */
    protected void createUser(final String token, final String email, final String pass, final String loginToken) {

        setProperty(token, INVITE_ONLY, "false");

        String url = getDefaultHostAndPort() + API_USER_SAVE + "?email=" + email + "&access_token=" + token
                + "&password=" + pass + "&confirmpassword=" + pass + "&role=" + UserRole.ROLE_USER + "&status="
                + UserStatus.ACTIVE;

        if (StringUtils.hasText(loginToken)) {
            url += "&logintoken=" + loginToken;
        }

        ResponseEntity<String> entity = exchangeRest(HttpMethod.POST, url);

        assertEquals("{\"message\":\"User has been saved\"}", entity.getBody());
        assertEquals(SC_OK, entity.getStatusCode().value());
    }

    /**
     * Deletes system property.
     * @param token {@link String}
     * @param key {@link String}
     */
    protected void deleteProperty(final String token, final String key) {
        String url = getDefaultHostAndPort() + API_SYSTEM_PROPERTIES_DELETE + "?access_token=" + token + "&key="
                + key;

        ResponseEntity<String> entity = exchangeRest(HttpMethod.POST, url);

        assertEquals(SC_OK, entity.getStatusCode().value());
    }

    /**
     * Sends Rest API.
     * @param method HttpMethod
     * @param url String
     * @return ResponseEntity&lt;String&gt;
     */
    protected ResponseEntity<String> exchangeRest(final HttpMethod method, final String url) {

        ResponseEntity<String> response = exchangeRest(method, url, String.class);
        return response;
    }

    /**
     * Sends Rest API.
     * @param <T> Type of Response
     * @param method HttpMethod
     * @param url String
     * @param responseType {@link Class}
     * @return ResponseEntity&lt;String&gt;
     */
    protected <T> ResponseEntity<T> exchangeRest(final HttpMethod method, final String url,
            final Class<T> responseType) {
        return exchangeRest(method, url, responseType, Arrays.asList(ACCEPT_HEADER_V1_JSON));
    }

    /**
     * Sends Rest API.
     * @param <T> Type of Response
     * @param method HttpMethod
     * @param url String
     * @param responseType {@link Class}
     * @param acceptableMediaTypes {@link List}
     * @return ResponseEntity&lt;String&gt;
     */
    protected <T> ResponseEntity<T> exchangeRest(final HttpMethod method, final String url,
            final Class<T> responseType, final List<MediaType> acceptableMediaTypes) {

        HttpHeaders headers = new HttpHeaders();
        headers.add("User-Agent", "Dummy User Agent");
        headers.setAccept(acceptableMediaTypes);
        HttpEntity<String> e = new HttpEntity<>("parameters", headers);

        ResponseEntity<T> entity = getTemplate().exchange(url, method, e, responseType);

        return entity;
    }

    /**
     * Send Rest API with object.
     * @param method HttpMethod
     * @param url String
     * @param obj Object
     * @param clazz Class&lt;T&gt;
     * @param <T> Type of class
     * @return ResponseEntity&lt;String&gt;
     */
    protected <T> ResponseEntity<T> exchangeRest(final HttpMethod method, final String url, final Object obj,
            final Class<T> clazz) {
        return exchangeRest(method, url, obj, clazz, MediaType.APPLICATION_JSON);
    }

    /**
     * Send Rest API with object.
     * @param method HttpMethod
     * @param url String
     * @param obj Object
     * @param clazz Class&lt;T&gt;
     * @param <T> Type of class
     * @param mediaType {@link MediaType}
     * @return ResponseEntity&lt;String&gt;
     */
    protected <T> ResponseEntity<T> exchangeRest(final HttpMethod method, final String url, final Object obj,
            final Class<T> clazz, final MediaType mediaType) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(mediaType);
        headers.setAccept(Arrays.asList(ACCEPT_HEADER_V1_JSON));
        HttpEntity<Object> entity = new HttpEntity<>(obj, headers);
        ResponseEntity<T> out = getTemplate().exchange(url, method, entity, clazz);

        return out;
    }

    /**
     * Sends Rest API.
     * @param method HttpMethod
     * @param url String
     * @return ResponseEntity&lt;String&gt;
     */
    protected ResponseEntity<String> exchangeRestBasicAuth(final HttpMethod method, final String url) {

        HttpHeaders headers = getBasicAuthorization(getClientId(), getClientSecret());

        headers.setAccept(Arrays.asList(ACCEPT_HEADER_V1_JSON));
        HttpEntity<String> e = new HttpEntity<>("parameters", headers);

        ResponseEntity<String> entity = getTemplate().exchange(url, method, e, String.class);

        return entity;
    }

    /**
     * Sends Rest API.
     * @param method HttpMethod
     * @param url String
     * @param acceptableMediaTypes {@link List}
     * @return ResponseEntity&lt;byte[]&gt;
     */
    protected ResponseEntity<byte[]> exchangeRestReturnBytes(final HttpMethod method, final String url,
            final List<MediaType> acceptableMediaTypes) {

        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(acceptableMediaTypes);
        HttpEntity<String> e = new HttpEntity<>("parameters", headers);

        ResponseEntity<byte[]> entity = getTemplate().exchange(url, method, e, byte[].class);

        return entity;
    }

    /**
     * Finds in body for key.
     * @param body String
     * @param key String
     * @return {@link String}
     */
    protected String findInBody(final String body, final String key) {

        String lastId = "";
        String regex = ".*\"" + key + "\":\"([\\w\\d\\-\\:]+)\".*";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(body);
        if (m.find()) {
            lastId = m.group(1);
        }

        return lastId;
    }

    /**
     * Returns a Basic Authorization Http Headers.
     * @param user String
     * @param password String
     * @return HttpHeaders
     */
    protected HttpHeaders getBasicAuthorization(final String user, final String password) {

        String plainCreds = user + ":" + password;
        byte[] plainCredsBytes = plainCreds.getBytes(StandardCharsets.UTF_8);
        byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
        String base64Creds = new String(base64CredsBytes, StandardCharsets.UTF_8);

        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Basic " + base64Creds);

        return headers;
    }

    /**
     * Get Bearer Authorization.
     * @param token String
     * @return HttpHeaders
     */
    protected HttpHeaders getBearerAuthorization(final String token) {

        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Bearer " + token);

        return headers;
    }

    /**
     * @return {@link String}
     */
    public String getClientId() {
        return clientID;
    }

    /**
     * @return {@link String}
     */
    public String getClientSecret() {
        return clientSecret;
    }

    /**
     * Get DB Migration Scripts.
     * @return {@link String}
     * @throws IOException IOException
     */
    protected List<String> getDBSystemPropertiesMigrationScripts() throws IOException {

        List<String> list = new ArrayList<>();
        ClassLoader cl = this.getClass().getClassLoader();
        ResourcePatternResolver r = new PathMatchingResourcePatternResolver(cl);
        Resource[] resources = r.getResources("classpath:db/migration/*.sql");
        for (Resource resource : resources) {
            list.add("/db/migration/" + resource.getFilename());
        }

        Collections.sort(list);

        List<String> sqls = new ArrayList<>();
        for (String s : list) {

            String txt = Resources.getResourceAsString(s);
            String[] lines = Strings.splitByNewLine(txt);
            for (String l : lines) {
                if (l.contains("system_properties") && l.contains("update")) {
                    sqls.add(l);
                } else if (l.contains("system_properties") && l.contains("key.public")) {
                    sqls.add(l);
                }
            }
        }

        return sqls;
    }

    /**
     * @return {@link String}
     */
    public String getDefaultEmail() {
        return DEFAULT_EMAIL;
    }

    /**
     * @return {@link String}
     */
    public String getDefaultHost() {
        return DEFAULT_HOST;
    }

    /**
     * Test Host.
     * @return {@link String}
     */
    public String getDefaultHostAndPort() {
        return "http://" + DEFAULT_HOST + ":" + DEFAULT_PORT;
    }

    //    /**
    //     * @return {@link List}
    //     */
    //    protected List<FolderPermission> getDefaultPermissions() {
    //        return DEFAULT_PERMISSIONS;
    //    }

    /**
     * @return {@link String}
     */
    public String getDefaultPass() {
        return DEFAULT_PASS;
    }

    /**
     * @return {@link Integer}
     */
    public int getDefaultPort() {
        return DEFAULT_PORT;
    }

    /**
     * @return {@link EntityManager}
     */
    @Override
    public EntityManager getEntityManager() {
        return this.entityManager;
    }

    /**
     * Get Folder File.
     * @param token {@link String}
     * @param folder {@link String}
     * @param uuid {@link String}
     * @param mediaType {@link MediaType}
     * @param resetuuid boolean
     * @return {@link ResponseEntity}
     */
    protected ResponseEntity<byte[]> getFolderFile(final String token, final String folder, final String uuid,
            final MediaType mediaType, final boolean resetuuid) {

        String url = getDefaultHostAndPort() + API_FOLDER_FILE + "/" + folder + "/" + uuid + "?access_token="
                + token + "&resetuuid=" + resetuuid;

        ResponseEntity<byte[]> entity = exchangeRestReturnBytes(HttpMethod.GET, url, Arrays.asList(mediaType));

        assertEquals(SC_OK, entity.getStatusCode().value());
        return entity;
    }

    /**
     * Get Folder File Outputs.
     * @param token {@link String}
     * @param folder {@link String}
     * @param uuid {@link String}
     * @return {@link List} of {@link WorkflowOutput}
     * @throws IOException IOException
     */
    protected List<WorkflowOutput> getFolderFileOutputs(final String token, final String folder, final String uuid)
            throws IOException {

        String url = getDefaultHostAndPort() + API_FOLDER_FILE + "/" + folder + "/" + uuid
                + "/outputs?access_token=" + token;

        ResponseEntity<String> entity = exchangeRest(HttpMethod.GET, url);

        assertEquals(SC_OK, entity.getStatusCode().value());

        Workflow dto = this.jsonService.readValue(entity.getBody(), Workflow.class);

        return dto.getOutputs();
    }

    /**
     * Get Folder Files List.
     * @param token {@link String}
     * @param folder {@link String}
     * @param uuid {@link String}
     * @return {@link FolderFormsListDTO}
     * @throws IOException IOException
     */
    public FolderFormsListDTO getFolderFileList(final String token, final String folder, final String uuid)
            throws IOException {

        String url = getDefaultHostAndPort() + API_FOLDER_FILE_LIST + "?access_token=" + token + "&folder="
                + folder;

        if (StringUtils.hasText(uuid)) {
            url += "&uuid=" + uuid;
        }

        url += "&status=" + FolderFormStatus.ACTIVE;
        url += "&status=" + FolderFormStatus.ROUTED;

        // when
        ResponseEntity<String> entity = exchangeRest(HttpMethod.GET, url);

        // then
        assertEquals(SC_OK, entity.getStatusCode().value());
        FolderFormsListDTO dto = this.jsonService.readValue(entity.getBody(), FolderFormsListDTO.class);

        return dto;
    }

    /**
     * @return {@link LoggerMailSender}
     */
    protected LoggerMailSender getMailSender() {
        return (LoggerMailSender) this.mailsender.getMailSender();
    }

    /**
     * Get User Notification List DTO.
     * @param accesstoken {@link String}
     * @param token {@link String}
     * @return {@link UserNotificationListDTO}
     * @throws Exception Exception
     */
    protected UserNotificationListDTO getNotificationList(final String accesstoken, final String token)
            throws Exception {

        String url = getDefaultHostAndPort() + API_USER_NOTIFICATION_LIST + "?access_token=" + accesstoken;

        if (StringUtils.hasText(token)) {
            url += "&token=" + token;
        }

        ResponseEntity<String> entity = exchangeRest(HttpMethod.GET, url);

        assertEquals(SC_OK, entity.getStatusCode().value());

        UserNotificationListDTO list = this.jsonService.readValue(entity.getBody(), UserNotificationListDTO.class);

        return list;
    }

    /**
     * @return {@link PlatformTransactionManager}
     */
    public PlatformTransactionManager getPlatformTransactionManager() {
        return this.transactionManager;
    }

    /**
     * Get Queue Messages.
     * @param token {@link String}
     * @param userid {@link String}
     * @return {@link QueueListDTO}
     * @throws Exception Exception
     */
    protected QueueListDTO getQueueMessages(final String token, final String userid) throws Exception {

        String url = getDefaultHostAndPort() + API_FOLDER_FILE_MESSAGES + "?access_token=" + token + "&queue="
                + userid;

        ResponseEntity<String> entity = exchangeRest(HttpMethod.GET, url);

        assertEquals(SC_OK, entity.getStatusCode().value());
        QueueListDTO msgs = this.jsonService.readValue(entity.getBody(), QueueListDTO.class);
        return msgs;
    }

    /**
     * @return {@link TestRestTemplate}
     */
    public TestRestTemplate getTemplate() {
        return this.template;
    }

    /**
     * Get UserDTO.
     * @param token {@link String}
     * @param email {@link String}
     * @return {@link UserDTO}
     * @throws IOException IOException
     */
    public UserDTO getUserDTO(final String token, final String email) throws IOException {

        String url = getDefaultHostAndPort() + API_USER_GET + "?access_token=" + token + "&email=" + email;

        ResponseEntity<String> entity = exchangeRest(HttpMethod.GET, url);
        assertEquals(SC_OK, entity.getStatusCode().value());

        UserDTO dto = this.jsonService.readValue(entity.getBody(), UserDTO.class);

        return dto;
    }

    /**
     * Invite User to Folder.
     * @param token {@link String}
     * @param email {@link String}
     * @param folder {@link String}
     * @param permissions {@link List}
     */
    protected void inviteToFolder(final String token, final String email, final String folder,
            final List<FolderPermission> permissions) {

        StringBuilder url = new StringBuilder(getDefaultHostAndPort() + API_FOLDER + folder + "/users" + "?email="
                + email + "&access_token=" + token);

        for (FolderPermission perm : permissions) {
            url.append("&permission=" + perm.name());
        }

        ResponseEntity<String> entity = exchangeRest(HttpMethod.POST, url.toString());

        assertEquals(SC_OK, entity.getStatusCode().value());
    }

    /**
     * login with default user.
     * @return {@link String} response
     */
    protected String login() {
        return login(DEFAULT_EMAIL, DEFAULT_PASS);
    }

    /**
     * login with user.
     * @param email {@link String}
     * @return {@link String} response
     */
    protected String login(final String email) {
        return login(email, DEFAULT_PASS);
    }

    /**
     * login with user/pass on default client.
     * @param email {@link String}
     * @param pass {@link String}
     * @return {@link String}
     */
    protected String login(final String email, final String pass) {
        return login(getClientId(), getClientSecret(), email, pass);
    }

    /**
     * login with client/secret & user/pass.
     * @param clientid {@link String}
     * @param clientsecret {@link String}
     * @param email {@link String}
     * @param pass {@link String}
     * @return {@link String}
     */
    @SuppressWarnings("rawtypes")
    protected String login(final String clientid, final String clientsecret, final String email,
            final String pass) {

        if (!ACCESS_TOKENS.containsKey(email)) {

            ResponseEntity<Map> entity = loginPost(clientid, clientsecret, email, pass);

            // then
            assertEquals(SC_OK, entity.getStatusCode().value());

            assertTrue(entity.getBody().containsKey("access_token"));
            assertTrue(entity.getBody().containsKey("token_type"));
            assertTrue(entity.getBody().containsKey("expires_in"));
            assertTrue(entity.getBody().containsKey("scope"));

            ACCESS_TOKENS.put(email, entity.getBody().get("access_token").toString());
        }

        return ACCESS_TOKENS.get(email);
    }

    /**
     * Post Login Request.
     * @param clientid {@link String}
     * @param clientsecret {@link String}
     * @param email {@link String}
     * @param pass {@link String}
     * @return {@link ResponseEntity}
     */
    @SuppressWarnings("rawtypes")
    protected ResponseEntity<Map> loginPost(final String clientid, final String clientsecret, final String email,
            final String pass) {
        HttpHeaders headers = getBasicAuthorization(clientid, clientsecret);
        HttpEntity<String> request = new HttpEntity<>(headers);

        ResponseEntity<Map> entity = getTemplate().exchange(getDefaultHostAndPort() + OAUTH_TOKEN
                + "?grant_type=password&" + "username=" + email + "&password=" + pass, HttpMethod.POST, request,
                Map.class);
        return entity;
    }

    /**
     * Migrate System Properties from migration scripts.
     * @param em {@link EntityManager}
     */
    private void migrateSystemProperties(final EntityManager em) {

        this.systemDao.save(new SystemProperty("version", "0.0"));
        this.systemDao.save(new SystemProperty("inviteonly", "true"));
        this.systemDao.save(new SystemProperty("assetservice_db", "true"));
        this.systemDao.save(new SystemProperty("assetservice_s3", "false"));

        em.flush();

        try {
            List<String> sqls = getDBSystemPropertiesMigrationScripts();
            for (String sql : sqls) {
                em.createNativeQuery(sql).executeUpdate();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Save Client.
     * @param clientid {@link String}
     * @param clientsecret {@link String}
     * @return {@link String}
     */
    protected String saveClient(final String clientid, final String clientsecret) {

        TransactionTemplate transactionTemplate = new TransactionTemplate(this.getPlatformTransactionManager());
        return (String) transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(final TransactionStatus arg0) {

                List<OAuthGrantTypes> grantTypes = Arrays.asList(OAuthGrantTypes.AUTHORIZATION_CODE,
                        OAuthGrantTypes.PASSWORD, OAuthGrantTypes.REFRESH_TOKEN);

                AbstractIntegrationTest.this.oauthservice.save(clientid, clientid, clientsecret, grantTypes, false);
                return null;
            }
        });
    }

    /**
     * Save Object Event.
     * @param token {@link String}
     * @param folder {@link String}
     * @return {@link String}
     */
    protected String saveObjectEvent(final String token, final String folder) {
        String url = getDefaultHostAndPort() + API_EVENTS_SAVE + "?access_token=" + token + "&object=" + folder
                + "&type=" + EventType.FOLDER_ON_SAVE.name() + "&notification=email";

        // when
        ResponseEntity<String> entity = exchangeRestBasicAuth(HttpMethod.POST, url);

        // then
        assertEquals(SC_OK, entity.getStatusCode().value());
        assertEquals("{\"message\":\"Event Saved\"}", entity.getBody());

        return entity.getHeaders().get("eventid").get(0);
    }

    /**
     * Sets system property.
     * @param token {@link String}
     * @param key {@link String}
     * @param value {@link String}
     */
    protected void setProperty(final String token, final String key, final String value) {
        String url = getDefaultHostAndPort() + API_SYSTEM_PROPERTIES_SAVE + "?access_token=" + token + "&key=" + key
                + "&value=" + value;

        ResponseEntity<String> entity = exchangeRest(HttpMethod.POST, url);

        assertEquals(SC_OK, entity.getStatusCode().value());
    }

    /**
     * Setup System.
     * @return {@link Pair}
     */
    @SuppressWarnings("unchecked")
    private Pair<String, String> setupSystem() {
        TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager);

        Pair<String, String> client = (Pair<String, String>) transactionTemplate.execute(setupSystemTransaction());
        return client;
    }

    /**
     * Setup System Transaction.
     * @return {@link TransactionCallback}
     */
    private TransactionCallback<Object> setupSystemTransaction() {

        final JSONService js = this.jsonService;
        final SetupInterceptor si = this.setupInterceptor;
        final SystemConfigInterceptor sci = this.systemConfigInterceptor;

        return new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(final TransactionStatus ts) {

                try {
                    FormJSON setupForm = js.loadForm(Setup.class);
                    FormJSON systemForm = js.loadForm(SystemConfig.class);

                    Setup setup = new Setup();
                    setup.setClientname("formkiq");
                    setup.setAdminemail(getDefaultEmail());
                    setup.setPassword(getDefaultPass());
                    si.postSave(setupForm, setup);

                    SystemConfig config = new SystemConfig();
                    config.setHostname(getDefaultHostAndPort());
                    sci.postSave(systemForm, config);

                    return Pair.of(setup.getClientname(),
                            findValueByKey(setupForm, "clientsecret").get().getValue());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
    }

    /**
     * Resets Database.
     */
    protected void truncateDatabase() {

        TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager);
        transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(final TransactionStatus arg0) {

                EntityManager em = AbstractIntegrationTest.this.entityManager;
                truncateDatabase(em);
                migrateSystemProperties(em);
                return null;
            }
        });
    }

    /**
     * Resets Database.
     * @param tables {@link String}
     */
    protected void truncateTables(final String... tables) {

        TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager);
        transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(final TransactionStatus arg0) {

                EntityManager em = AbstractIntegrationTest.this.entityManager;
                truncateTables(em, Arrays.asList(tables));
                return null;
            }
        });
    }
}