package org.odroid.server.controllers;
import static java.util.Arrays.asList;
import static org.apache.commons.io.FileUtils.deleteDirectory;
import static org.apache.commons.io.FileUtils.readFileToByteArray;
import static org.junit.Assert.assertArrayEquals;
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.odroid.server.entities.ApplicationDataType.MAP_PRICE;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.odroid.server.entities.Application;
import org.odroid.server.exception.ApplicationNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.multipart.MultipartFile;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/root-context-test.xml", "/servlet-context-test.xml" })
public class ApplicationControllerTest {
private Logger l = LoggerFactory.getLogger(getClass());
@Autowired
private SessionFactory sf;
@Autowired
private ApplicationController ac;
@Value("${os.filestore}")
private String APP_FILESTORE;
public static final String HASH_PATTERN = "[0-9a-z]+";
public static final String INVALID_HASH = "invalid hash ~!#$@";
@Rule
public ExpectedException exception = ExpectedException.none();
@Before
public void before() {
clearDB();
}
private void clearDB() {
Session s = null;
try {
s = sf.openSession();
Transaction t = s.beginTransaction();
Query q = s.createQuery("delete from Application");
int itemsDeleted = q.executeUpdate();
l.info("Deleted applications: {}", itemsDeleted);
t.commit();
} finally {
if (s != null) {
s.close();
}
}
}
@Test
public void testCreateApplication() {
Application a = application();
l.debug("Application before create: {}", a);
a = ac.create(a);
l.debug("Application after create: {}", a);
assertNotNull(a);
assertNotNull(a.getHash());
assertTrue(a.getHash().matches(HASH_PATTERN));
assertNotNull(a.getId());
assertTrue(a.getActive());
}
@Test
public void testGetApplicationForHash() {
Application newApp = application();
newApp = ac.create(newApp);
String hash = newApp.getHash();
assertNotNull(hash);
assertTrue(hash.matches(HASH_PATTERN));
Application appForHash = ac.applicationForHash(hash);
assertEquals(newApp, appForHash);
l.debug("All applications: {}", ac.applications());
}
@Test
public void testGetApplications() {
Application a1 = application();
Application a2 = application();
a1 = ac.create(a1);
a2 = ac.create(a2);
List<Application> apps = ac.applications();
l.debug("All applications: {}", apps);
assertFalse(apps.isEmpty());
assertEquals(2, apps.size());
assertTrue(apps.containsAll(asList(a1, a2)));
}
@Test
public void testLockAndUnlockApplication() {
Application a = application();
a = ac.create(a);
assertTrue(a.getActive());
a = ac.lock(a.getHash());
assertFalse(a.getActive());
a = ac.unlock(a.getHash());
assertTrue(a.getActive());
}
@Test
public void testAddData() throws IOException {
Application a = application();
a = ac.create(a);
String response = ac.addData(a.getHash(), MAP_PRICE, mockMapPriceFile(MAP_PRICE.name().toLowerCase(), mockMapPriceContent()));
assertArrayEquals(mockMapPriceContent(), response.getBytes());
File appDir = new File(APP_FILESTORE, a.getHash());
assertTrue(appDir.exists());
assertTrue(appDir.isDirectory());
assertTrue(appDir.list().length > 0);
File mapPriceFile = new File(appDir, MAP_PRICE.name().toLowerCase());
assertTrue(mapPriceFile.exists());
assertTrue(mapPriceFile.isFile());
assertArrayEquals(mockMapPriceContent(), readFileToByteArray(mapPriceFile));
response = ac.addData(a.getHash(), MAP_PRICE, mockMapPriceFile(MAP_PRICE.name().toLowerCase(), mockMapPriceContent2()));
assertArrayEquals(mockMapPriceContent2(), response.getBytes());
assertTrue(appDir.exists());
assertTrue(appDir.isDirectory());
assertTrue(appDir.list().length > 0);
mapPriceFile = new File(appDir, MAP_PRICE.name().toLowerCase());
assertTrue(mapPriceFile.exists());
assertTrue(mapPriceFile.isFile());
assertArrayEquals(mockMapPriceContent2(), readFileToByteArray(mapPriceFile));
deleteDirectory(appDir);
assertFalse(appDir.exists());
}
private MultipartFile mockMapPriceFile(String name, byte[] content) {
return new MockMultipartFile(name, content);
}
private byte[] mockMapPriceContent() {
StringBuilder sb = new StringBuilder();
sb.append("123456788=2.45\n");
sb.append("123456789=1.47\n");
return sb.toString().getBytes();
}
private byte[] mockMapPriceContent2() {
StringBuilder sb = new StringBuilder();
sb.append("123456786=0.45\n");
sb.append("123456787=11.475\n");
return sb.toString().getBytes();
}
@Test
public void testCreateApplicationEmptyName() {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("Name must be set");
Application a = new Application();
a = ac.create(a);
}
@Test
public void testCreateApplicationHashNoEmpty() {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("Hash mustn't be set");
Application a = new Application();
a.setName("app name");
a.setHash("app hash");
a = ac.create(a);
}
@Test
public void testGetApplicationForInvalidHash() {
exception.expect(ApplicationNotFoundException.class);
exception.expectMessage("No application found for hash: " + INVALID_HASH);
Application a = ac.applicationForHash(INVALID_HASH);
assertNull(a);
}
@Test
public void testLockApplicationForInvalidHash() {
exception.expect(ApplicationNotFoundException.class);
exception.expectMessage("No application found for hash: " + INVALID_HASH);
ac.lock(INVALID_HASH);
}
@Test
public void testUnlockApplicationForInvalidHash() {
exception.expect(ApplicationNotFoundException.class);
exception.expectMessage("No application found for hash: " + INVALID_HASH);
ac.unlock(INVALID_HASH);
}
@Test
public void testAddDataInvalidHash() throws IOException {
exception.expect(ApplicationNotFoundException.class);
exception.expectMessage("No application found for hash: " + INVALID_HASH);
ac.addData(INVALID_HASH, MAP_PRICE, new MockMultipartFile("name", "".getBytes()));
}
private Application application() {
Application a = new Application();
a.setName("App Name " + System.currentTimeMillis());
a.setActive(true);
return a;
}
}