package com.wesabe.grendel.entities.tests;
import static org.fest.assertions.Assertions.*;
import static org.mockito.Mockito.*;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.security.SecureRandom;
import javax.ws.rs.core.MediaType;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeZone;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import com.google.common.collect.ImmutableList;
import com.wesabe.grendel.entities.Document;
import com.wesabe.grendel.entities.User;
import com.wesabe.grendel.openpgp.KeySet;
import com.wesabe.grendel.openpgp.MessageReader;
import com.wesabe.grendel.openpgp.MessageWriter;
@RunWith(Enclosed.class)
public class DocumentTest {
public static class A_Fresh_Document {
private User owner;
private String name;
private DateTime now;
@Before
public void setup() throws Exception {
this.now = new DateTime(2009, 12, 27, 10, 0, 43, 0, DateTimeZone.UTC);
DateTimeUtils.setCurrentMillisFixed(now.getMillis());
this.owner = mock(User.class);
this.name = "document1.txt";
}
@After
public void teardown() {
DateTimeUtils.setCurrentMillisSystem();
}
@Test
public void itHasAnOwner() throws Exception {
final Document doc = new Document(owner, name, MediaType.APPLICATION_OCTET_STREAM_TYPE);
assertThat(doc.getOwner()).isEqualTo(owner);
}
@Test
public void itHasAName() throws Exception {
final Document doc = new Document(owner, name, MediaType.APPLICATION_OCTET_STREAM_TYPE);
assertThat(doc.getName()).isEqualTo(name);
}
@Test
public void itHasAModificationTimestamp() throws Exception {
final Document doc = new Document(owner, name, MediaType.APPLICATION_OCTET_STREAM_TYPE);
assertThat(doc.getModifiedAt()).isEqualTo(now);
}
@Test
public void itHasACreationTimestamp() throws Exception {
final Document doc = new Document(owner, name, MediaType.APPLICATION_OCTET_STREAM_TYPE);
assertThat(doc.getCreatedAt()).isEqualTo(now);
}
@Test
public void itHasAContentType() throws Exception {
final Document doc = new Document(owner, name, MediaType.APPLICATION_OCTET_STREAM_TYPE);
assertThat(doc.getContentType()).isEqualTo(MediaType.APPLICATION_OCTET_STREAM_TYPE);
}
@Test
public void itIsLinkable() throws Exception {
final Document doc = new Document(owner, name, MediaType.APPLICATION_OCTET_STREAM_TYPE);
assertThat(doc.toString()).isEqualTo(name);
}
@Test
public void itHasAnETag() throws Exception {
final Document doc = new Document(owner, name, MediaType.APPLICATION_OCTET_STREAM_TYPE);
assertThat(doc.getEtag()).isEqualTo("doc-document1.txt-0");
}
}
public static class Encrypting_A_Document_Body {
private KeySet ownerKeySet, recipientKeySet;
private User owner, reader;
private Document doc;
@Before
public void setup() throws Exception {
final FileInputStream ownerKeyring = new FileInputStream("src/test/resources/secret-keyring.gpg");
this.ownerKeySet = KeySet.load(ownerKeyring);
ownerKeyring.close();
final FileInputStream recipientKeyring = new FileInputStream("src/test/resources/another-secret-keyring.gpg");
this.recipientKeySet = KeySet.load(recipientKeyring);
recipientKeyring.close();
this.owner = new User(ownerKeySet);
this.reader = new User(recipientKeySet);
this.doc = new Document(owner, "test", MediaType.APPLICATION_OCTET_STREAM_TYPE);
}
@Test
public void itStoresItAsAnEncryptedOpenPGPMessage() throws Exception {
final byte[] originalBody = "I am a secret document".getBytes();
doc.linkUser(reader);
doc.encryptAndSetBody(ownerKeySet.unlock("test".toCharArray()), new SecureRandom(), originalBody);
final Field bodyField = doc.getClass().getDeclaredField("body");
bodyField.setAccessible(true);
final byte[] encryptedBody = (byte[]) bodyField.get(doc);
final MessageReader reader = new MessageReader(ownerKeySet, recipientKeySet.unlock("test2".toCharArray()));
final byte[] decryptedBody = reader.read(encryptedBody);
assertThat(decryptedBody).isEqualTo(originalBody);
}
}
public static class Decrypting_A_Document_Body {
private KeySet ownerKeySet, recipientKeySet;
private User owner;
private Document doc;
@Before
public void setup() throws Exception {
final FileInputStream ownerKeyring = new FileInputStream("src/test/resources/secret-keyring.gpg");
this.ownerKeySet = KeySet.load(ownerKeyring);
ownerKeyring.close();
final FileInputStream recipientKeyring = new FileInputStream("src/test/resources/another-secret-keyring.gpg");
this.recipientKeySet = KeySet.load(recipientKeyring);
recipientKeyring.close();
this.owner = new User(ownerKeySet);
this.doc = new Document(owner, "test", MediaType.APPLICATION_OCTET_STREAM_TYPE);
}
@Test
public void itCanDecryptIt() throws Exception {
final byte[] originalBody = "I am a secret document".getBytes();
final MessageWriter writer = new MessageWriter(ownerKeySet.unlock("test".toCharArray()), ImmutableList.of(recipientKeySet), new SecureRandom());
final byte[] encryptedBody = writer.write(originalBody);
final Field bodyField = doc.getClass().getDeclaredField("body");
bodyField.setAccessible(true);
bodyField.set(doc, encryptedBody);
final byte[] decryptedBody = doc.decryptBody(recipientKeySet.unlock("test2".toCharArray()));
assertThat(decryptedBody).isEqualTo(originalBody);
}
}
public static class Linking_A_User {
private User user;
private Document document;
@SuppressWarnings("deprecation")
@Before
public void setup() throws Exception {
this.user = new User();
this.document = new Document();
document.linkUser(user);
}
@Test
public void itAddsTheDocumentToTheUsersLinkedDocuments() throws Exception {
assertThat(user.getLinkedDocuments()).contains(document);
}
@Test
public void itAddsTheUserToTheDocumentsLinkedUsers() throws Exception {
assertThat(document.getLinkedUsers()).contains(user);
}
@Test
public void itIsLinkedToTheUser() throws Exception {
assertThat(document.isLinked(user)).isTrue();
}
}
public static class Unlinking_A_User {
private User user;
private Document document;
@SuppressWarnings("deprecation")
@Before
public void setup() throws Exception {
this.user = new User();
this.document = new Document();
document.linkUser(user);
document.unlinkUser(user);
}
@Test
public void itAddsTheDocumentToTheUsersLinkedDocuments() throws Exception {
assertThat(user.getLinkedDocuments()).excludes(document);
}
@Test
public void itAddsTheUserToTheDocumentsLinkedUsers() throws Exception {
assertThat(document.getLinkedUsers()).excludes(user);
}
@Test
public void itIsNotLinkedToTheUser() throws Exception {
assertThat(document.isLinked(user)).isFalse();
}
}
}