de.siegmar.securetransfer.controller.MvcTest.java Source code

Java tutorial

Introduction

Here is the source code for de.siegmar.securetransfer.controller.MvcTest.java

Source

/*
 * Copyright 2017 Oliver Siegmar
 *
 * 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 de.siegmar.securetransfer.controller;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.flash;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import java.nio.charset.StandardCharsets;
import java.util.UUID;

import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import com.google.common.hash.HashCode;
import com.google.common.io.ByteStreams;

import de.siegmar.securetransfer.controller.dto.EncryptMessageCommand;
import de.siegmar.securetransfer.domain.DecryptedFile;
import de.siegmar.securetransfer.domain.DecryptedMessage;
import de.siegmar.securetransfer.domain.SenderMessage;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@ActiveProfiles("test")
@AutoConfigureMockMvc
@SuppressWarnings("checkstyle:executablestatementcount")
public class MvcTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void getForm() throws Exception {
        mockMvc.perform(get("/send")).andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("send/send_form")).andExpect(model().attributeExists("command"))
                .andExpect(model().attribute("message_max_length", EncryptMessageCommand.MESSAGE_MAX_LENGTH))
                .andExpect(model().attribute("password_max_length", EncryptMessageCommand.PASSWORD_MAX_LENGTH));
    }

    @Test
    public void invalidFormSubmit() throws Exception {
        // message missing
        final String boundary = "------TestBoundary" + UUID.randomUUID();
        final MultipartEntityBuilder builder = MultipartEntityBuilder.create().setBoundary(boundary);

        mockMvc.perform(post("/send").content(ByteStreams.toByteArray(builder.build().getContent()))
                .contentType(MediaType.MULTIPART_FORM_DATA_VALUE + "; boundary=" + boundary))
                .andExpect(status().isOk()).andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(model().hasErrors());
    }

    @Test
    public void messageWithoutFileWithoutPassword() throws Exception {
        final String messageToSend = "my secret message";

        final String boundary = "------TestBoundary" + UUID.randomUUID();
        final MultipartEntityBuilder builder = MultipartEntityBuilder.create().setBoundary(boundary)
                .addTextBody("expirationDays", "1").addTextBody("message", messageToSend);

        // Create new message and expect redirect with flash message after store
        final MvcResult createMessageResult = mockMvc
                .perform(post("/send").content(ByteStreams.toByteArray(builder.build().getContent()))
                        .contentType(MediaType.MULTIPART_FORM_DATA_VALUE + "; boundary=" + boundary))
                .andExpect(status().isFound()).andExpect(redirectedUrlPattern("/send/**"))
                .andExpect(flash().attribute("message", messageToSend)).andReturn();

        // receive data after redirect
        final String messageStatusUrl = createMessageResult.getResponse().getRedirectedUrl();

        final MvcResult messageStatusResult = mockMvc.perform(get(messageStatusUrl)).andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("send/message_status")).andReturn();

        final SenderMessage senderMessage = (SenderMessage) messageStatusResult.getModelAndView().getModel()
                .get("senderMessage");

        assertNotNull(senderMessage);
        assertNotNull(senderMessage.getId());
        assertNotNull(senderMessage.getReceiverId());
        assertNotNull(senderMessage.getExpiration());
        assertNull(senderMessage.getReceived());
        assertFalse(senderMessage.isPasswordEncrypted());

        final String receiveUrl = (String) messageStatusResult.getModelAndView().getModel().get("receiveUrl");

        assertNotNull(receiveUrl);

        final String linkSecret = messageStatusUrl.replaceFirst(".*linkSecret=", "");
        HashCode.fromString(linkSecret);

        // call receiver URL
        final MvcResult confirmPage = mockMvc.perform(get(receiveUrl)).andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("receive/message_confirm")).andReturn();

        final Document confirmPageDoc = Jsoup.parse(confirmPage.getResponse().getContentAsString());
        final String confirmUrl = confirmPageDoc.getElementsByTag("form").attr("action");

        // Receive message
        final MvcResult messageResult = mockMvc.perform(get(confirmUrl).param("linkSecret", linkSecret))
                .andExpect(status().isOk()).andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("receive/message")).andReturn();

        final DecryptedMessage decryptedMessage = (DecryptedMessage) messageResult.getModelAndView().getModel()
                .get("decryptedMessage");

        assertEquals(messageToSend, decryptedMessage.getMessage());
        assertEquals(0, decryptedMessage.getFiles().size());

        // Check message is burned
        mockMvc.perform(get(receiveUrl)).andExpect(status().isNotFound())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("message_not_found"));

        // Check sender status page
        final MvcResult messageStatusResult2 = mockMvc.perform(get(messageStatusUrl)).andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("send/message_status")).andReturn();

        final SenderMessage senderMessage2 = (SenderMessage) messageStatusResult2.getModelAndView().getModel()
                .get("senderMessage");

        assertNotNull(senderMessage2);
        assertNotNull(senderMessage2.getId());
        assertNotNull(senderMessage2.getReceiverId());
        assertNotNull(senderMessage2.getExpiration());
        assertNotNull(senderMessage2.getReceived());
        assertFalse(senderMessage.isPasswordEncrypted());
    }

    @Test
    public void messageWithFileWithPassword() throws Exception {
        final String messageToSend = "my secret message";
        final String password = "top secret password";
        final String fileContent = "test file content";

        final String boundary = "------TestBoundary" + UUID.randomUUID();
        final MultipartEntityBuilder builder = MultipartEntityBuilder.create().setBoundary(boundary)
                .addTextBody("expirationDays", "1").addTextBody("message", messageToSend)
                .addTextBody("password", password).addBinaryBody("files",
                        fileContent.getBytes(StandardCharsets.UTF_8), ContentType.APPLICATION_OCTET_STREAM,
                        "test.txt");

        // Create new message and expect redirect with flash message after store
        final MvcResult createMessageResult = mockMvc
                .perform(post("/send").content(ByteStreams.toByteArray(builder.build().getContent()))
                        .contentType(MediaType.MULTIPART_FORM_DATA_VALUE + "; boundary=" + boundary))
                .andExpect(status().isFound()).andExpect(redirectedUrlPattern("/send/**"))
                .andExpect(flash().attribute("message", messageToSend)).andReturn();

        // receive data after redirect
        final String messageStatusUrl = createMessageResult.getResponse().getRedirectedUrl();

        final String linkSecret = messageStatusUrl.replaceFirst(".*linkSecret=", "");
        HashCode.fromString(linkSecret);

        final MvcResult messageStatusResult = mockMvc.perform(get(messageStatusUrl)).andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("send/message_status")).andReturn();

        final SenderMessage senderMessage = (SenderMessage) messageStatusResult.getModelAndView().getModel()
                .get("senderMessage");

        assertNotNull(senderMessage);
        assertNotNull(senderMessage.getId());
        assertNotNull(senderMessage.getReceiverId());
        assertNotNull(senderMessage.getExpiration());
        assertNull(senderMessage.getReceived());
        assertTrue(senderMessage.isPasswordEncrypted());

        final String receiveUrl = (String) messageStatusResult.getModelAndView().getModel().get("receiveUrl");

        assertNotNull(receiveUrl);

        // call receiver URL
        final MvcResult confirmPage = mockMvc.perform(get(receiveUrl)).andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("receive/message_ask_password")).andReturn();

        final Document confirmPageDoc = Jsoup.parse(confirmPage.getResponse().getContentAsString());
        final String passwordUrl = confirmPageDoc.getElementsByTag("form").attr("action");

        // Receive message
        final MvcResult messageResult = mockMvc
                .perform(post(passwordUrl).param("linkSecret", linkSecret).param("password", password))
                .andExpect(status().isOk()).andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("receive/message")).andReturn();

        final DecryptedMessage decryptedMessage = (DecryptedMessage) messageResult.getModelAndView().getModel()
                .get("decryptedMessage");

        assertEquals(messageToSend, decryptedMessage.getMessage());
        assertEquals(1, decryptedMessage.getFiles().size());

        final DecryptedFile file = decryptedMessage.getFiles().get(0);
        final String fileId = file.getId();
        final String fileKey = file.getKeyHex();

        // Download file
        final MvcResult downloadResult = mockMvc
                .perform(get("/receive/file/{id}/{key}", fileId, fileKey).sessionAttr("iv_file_" + fileId,
                        file.getKeyIv().getIv()))
                .andExpect(request().asyncStarted())
                //.andExpect(request().asyncResult("Deferred result"))
                .andExpect(status().isOk()).andExpect(content().contentType("application/octet-stream"))
                .andReturn();

        downloadResult.getAsyncResult();
        assertEquals(fileContent, downloadResult.getResponse().getContentAsString());

        // Check message is burned
        mockMvc.perform(get(receiveUrl)).andExpect(status().isNotFound())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("message_not_found"));

        // Check file is burned
        mockMvc.perform(get("/receive/file/{id}/{key}", fileId, fileKey).sessionAttr("iv_file_" + fileId,
                file.getKeyIv().getIv())).andExpect(status().isNotFound())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("message_not_found"));

        // Check sender status page
        final MvcResult messageStatusResult2 = mockMvc.perform(get(messageStatusUrl)).andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"))
                .andExpect(view().name("send/message_status")).andReturn();

        final SenderMessage senderMessage2 = (SenderMessage) messageStatusResult2.getModelAndView().getModel()
                .get("senderMessage");

        assertNotNull(senderMessage2);
        assertNotNull(senderMessage2.getId());
        assertNotNull(senderMessage2.getReceiverId());
        assertNotNull(senderMessage2.getExpiration());
        assertNotNull(senderMessage2.getReceived());
        assertTrue(senderMessage.isPasswordEncrypted());
    }

}