package com.wesabe.grendel.resources.tests;
import static org.fest.assertions.Assertions.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import com.wesabe.grendel.auth.Credentials;
import com.wesabe.grendel.auth.Session;
import com.wesabe.grendel.entities.Document;
import com.wesabe.grendel.entities.User;
import com.wesabe.grendel.entities.dao.DocumentDAO;
import com.wesabe.grendel.entities.dao.UserDAO;
import com.wesabe.grendel.openpgp.UnlockedKeySet;
import com.wesabe.grendel.resources.LinkedDocumentResource;
@RunWith(Enclosed.class)
public class LinkedDocumentResourceTest {
private static abstract class Context {
protected UserDAO userDAO;
protected DocumentDAO documentDAO;
protected Credentials credentials;
protected User owner, user;
protected UnlockedKeySet keySet;
protected Session session;
protected Document document;
protected LinkedDocumentResource resource;
public void setup() throws Exception {
this.owner = mock(User.class);
this.user = mock(User.class);
this.userDAO = mock(UserDAO.class);
when(userDAO.findById("frank")).thenReturn(owner);
this.keySet = mock(UnlockedKeySet.class);
this.document = mock(Document.class);
when(document.getName()).thenReturn("document1.txt");
when(document.getContentType()).thenReturn(MediaType.TEXT_PLAIN_TYPE);
when(document.getModifiedAt()).thenReturn(new DateTime(2009, 12, 29, 8, 42, 32, 00, DateTimeZone.UTC));
when(document.decryptBody(keySet)).thenReturn("yay for everyone".getBytes());
when(document.isLinked(user)).thenReturn(true);
this.documentDAO = mock(DocumentDAO.class);
when(documentDAO.findByOwnerAndName(owner, "document1.txt")).thenReturn(document);
this.session = new Session(user, keySet);
this.credentials = mock(Credentials.class);
when(credentials.buildSession(userDAO, "bob")).thenReturn(session);
this.resource = new LinkedDocumentResource(userDAO, documentDAO);
}
}
public static class Showing_A_Linked_Document extends Context {
@Before
@Override
public void setup() throws Exception {
super.setup();
}
@Test
public void itThrowsA404IfTheOwnerDoesNotExist() throws Exception {
when(userDAO.findById("frank")).thenReturn(null);
try {
resource.show(credentials, "bob", "frank", "document1.txt");
fail("should have returned a 404 but didn't");
} catch (WebApplicationException e) {
assertThat(e.getResponse().getStatus()).isEqualTo(Status.NOT_FOUND.getStatusCode());
}
}
@Test
public void itThrowsA404IfTheDocumentDoesNotExist() throws Exception {
when(documentDAO.findByOwnerAndName(owner, "document1.txt")).thenReturn(null);
try {
resource.show(credentials, "bob", "frank", "document1.txt");
fail("should have returned a 404 but didn't");
} catch (WebApplicationException e) {
assertThat(e.getResponse().getStatus()).isEqualTo(Status.NOT_FOUND.getStatusCode());
}
}
@Test
public void itThrowsA404IfTheDocumentIsNotLinkedToTheUser() throws Exception {
when(document.isLinked(user)).thenReturn(false);
try {
resource.show(credentials, "bob", "frank", "document1.txt");
fail("should have returned a 404 but didn't");
} catch (WebApplicationException e) {
assertThat(e.getResponse().getStatus()).isEqualTo(Status.NOT_FOUND.getStatusCode());
}
}
@Test
public void itReturnsTheDecryptedDocument() throws Exception {
final Response r = resource.show(credentials, "bob", "frank", "document1.txt");
SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getDateTimeInstance();
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
formatter.applyPattern("EEE MMM dd HH:mm:ss z yyyy");
assertThat(r.getStatus()).isEqualTo(Status.OK.getStatusCode());
assertThat(r.getMetadata().getFirst("Content-Type")).isEqualTo(MediaType.valueOf("text/plain"));
assertThat(r.getMetadata().getFirst("Cache-Control").toString()).isEqualTo("private, no-cache, no-store, no-transform");
assertThat(formatter.format(r.getMetadata().getFirst("Last-Modified"))).isEqualTo("Tue Dec 29 08:42:32 UTC 2009");
assertThat((byte[]) r.getEntity()).isEqualTo("yay for everyone".getBytes());
}
}
public static class Deleting_A_Linked_Document extends Context {
@Before
@Override
public void setup() throws Exception {
super.setup();
}
@Test
public void itThrowsA404IfTheOwnerDoesNotExist() throws Exception {
when(userDAO.findById("frank")).thenReturn(null);
try {
resource.delete(credentials, "bob", "frank", "document1.txt");
fail("should have returned a 404 but didn't");
} catch (WebApplicationException e) {
assertThat(e.getResponse().getStatus()).isEqualTo(Status.NOT_FOUND.getStatusCode());
}
}
@Test
public void itThrowsA404IfTheDocumentDoesNotExist() throws Exception {
when(documentDAO.findByOwnerAndName(owner, "document1.txt")).thenReturn(null);
try {
resource.delete(credentials, "bob", "frank", "document1.txt");
fail("should have returned a 404 but didn't");
} catch (WebApplicationException e) {
assertThat(e.getResponse().getStatus()).isEqualTo(Status.NOT_FOUND.getStatusCode());
}
}
@Test
public void itThrowsA404IfTheDocumentIsNotLinkedToTheUser() throws Exception {
when(document.isLinked(user)).thenReturn(false);
try {
resource.delete(credentials, "bob", "frank", "document1.txt");
fail("should have returned a 404 but didn't");
} catch (WebApplicationException e) {
assertThat(e.getResponse().getStatus()).isEqualTo(Status.NOT_FOUND.getStatusCode());
}
}
@Test
public void itUnlinksTheUserFromTheDocument() throws Exception {
resource.delete(credentials, "bob", "frank", "document1.txt");
final InOrder inOrder = inOrder(document, documentDAO);
inOrder.verify(document).unlinkUser(user);
inOrder.verify(documentDAO).saveOrUpdate(document);
}
@Test
public void itReturnsNoContent() throws Exception {
final Response r = resource.delete(credentials, "bob", "frank", "document1.txt");
assertThat(r.getStatus()).isEqualTo(Status.NO_CONTENT.getStatusCode());
}
}
}