package base;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import controllers.Component;
import models.Account;
import models.Friendship;
import models.Group;
import models.GroupAccount;
import models.enums.AccountRole;
import models.enums.GroupType;
import models.enums.LinkType;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import play.db.jpa.JPA;
import play.libs.F;
import play.mvc.Http;
import play.test.FakeApplication;
import play.test.Helpers;
import javax.inject.Inject;
import java.util.Collections;
import java.util.Map;
import static org.mockito.Mockito.*;
/**
* You can extend your test classes from this class to provide a complete fake environment.
*/
public abstract class FakeApplicationTest {
@Inject
GroupAccount groupAccount;
/**
* Mocks a HTTP request instance.
*/
private final Http.Request request = mock(Http.Request.class);
/**
* Hols the FakeApplication instance.
*/
public static FakeApplication app;
/**
* The default password for test accounts.
*/
public static final String TEST_ACCOUNT_PASSWORD = "123456";
/**
* Holds the singleton Config instance for the current context.
*/
private static Config configuration = null;
/**
* Returns the configuration value for a configuration key.
*
* @param configurationKey Configuration key
* @return Configuration value
*/
protected static String getConfiguration(String configurationKey) {
if (FakeApplicationTest.configuration == null) {
FakeApplicationTest.configuration = ConfigFactory.load();
}
return FakeApplicationTest.configuration.getString(configurationKey);
}
@BeforeClass
public static void startApp() {
app = Helpers.fakeApplication();
Helpers.start(app);
}
@Before
public void setUp() throws Exception {
Map<String, String> flashData = Collections.emptyMap();
Map<String, Object> argData = Collections.emptyMap();
Long id = 2L;
play.api.mvc.RequestHeader header = mock(play.api.mvc.RequestHeader.class);
Http.Context context = new Http.Context(id, header, this.request, flashData, flashData, argData);
Http.Context.current.set(context);
}
@AfterClass
public static void stopApp() {
Helpers.stop(app);
}
/**
* Returns an account by email.
*
* @param email E-Mail address of account to fetch
* @return Account instance
*/
public Account getAccountByEmail(final String email) {
try {
return JPA.withTransaction(new F.Function0<Account>() {
@Override
public Account apply() throws Throwable {
return Account.findByEmail(email);
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
/**
* Returns a test account, creates one before if not exists.
*
* @param number Number of test account
* @return Account instance
*/
public Account getTestAccount(final int number) {
final String testAccountEmail = "test" + String.valueOf(number) + "@htwplus.de";
Account storedTestAccount = this.getAccountByEmail(testAccountEmail);
// if there is this test account, return
if (storedTestAccount != null) {
return storedTestAccount;
}
// there is no test account with that number right now, create a persistent one
try {
return JPA.withTransaction(new F.Function0<Account>() {
@Override
public Account apply() throws Throwable {
Account testAccount = new Account();
testAccount.firstname = "Test";
testAccount.lastname = "User " + String.valueOf(number);
testAccount.email = testAccountEmail;
testAccount.avatar = "a1";
testAccount.role = AccountRole.STUDENT;
testAccount.password = Component.md5(FakeApplicationTest.TEST_ACCOUNT_PASSWORD);
testAccount.create();
return testAccount;
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
/**
* Returns the default admin account.
*
* @return Account instance
*/
public Account getAdminAccount() {
String adminEmailAddress = FakeApplicationTest.getConfiguration("htwplus.admin.mail");
return this.getAccountByEmail(adminEmailAddress);
}
/**
* Establishes a friendship between test accounts.
*
* @param testAccountA First test account
* @param testAccountB Second test account
*/
public void establishFriendshipTestAccounts(final Account testAccountA, final Account testAccountB) {
JPA.withTransaction(new F.Callback0() {
@Override
public void invoke() throws Throwable {
if (!Friendship.alreadyFriendly(testAccountA, testAccountB)) {
Friendship testFriendship = new Friendship(testAccountA, testAccountB, LinkType.establish);
testFriendship.create();
}
if (!Friendship.alreadyFriendly(testAccountB, testAccountA)) {
Friendship testFriendship = new Friendship(testAccountB, testAccountA, LinkType.establish);
testFriendship.create();
}
}
});
}
/**
* Removes a friendship between test accounts.
*
* @param testAccountA First test account
* @param testAccountB Second test account
*/
public void removeFriendshipTestAccounts(final Account testAccountA, final Account testAccountB) {
JPA.withTransaction(new F.Callback0() {
@Override
public void invoke() throws Throwable {
if (Friendship.alreadyFriendly(testAccountA, testAccountB)) {
Friendship.findFriendLink(testAccountA, testAccountB).delete();
}
if (Friendship.alreadyFriendly(testAccountB, testAccountA)) {
Friendship.findFriendLink(testAccountB, testAccountA).delete();
}
}
});
}
/**
* Returns a group by title.
*
* @param title Title of group to fetch
* @return Group instance
*/
public Group getGroupByTitle(final String title) {
try {
return JPA.withTransaction(new F.Function0<Group>() {
@Override
public Group apply() throws Throwable {
return Group.findByTitle(title);
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
/**
* Returns a test group, creates one before if not exists.
*
* @param number Number of test group
* @param groupOwner the optional group owner
* @return Group instance
*/
public Group getTestGroup(final int number, final Account groupOwner) {
final String testGroupTitle = "Test Group " + String.valueOf(number);
Group storedTestGroup = this.getGroupByTitle(testGroupTitle);
// if there is this test group, return
if (storedTestGroup != null) {
return storedTestGroup;
}
// there is no test account with that number right now, create a persistent one
try {
return JPA.withTransaction(new F.Function0<Group>() {
@Override
public Group apply() throws Throwable {
Group testGroup = new Group();
testGroup.groupType = GroupType.close;
testGroup.setTitle(testGroupTitle);
if (groupOwner != null) {
testGroup.createWithGroupAccount(groupOwner);
} else {
testGroup.create();
}
return testGroup;
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
/**
* Returns a group account for an account to a group.
*
* @param account Account
* @param group Group
* @return GroupAccount instance if found, otherwise null
*/
public GroupAccount getGroupAccount(final Account account, final Group group) {
try {
return JPA.withTransaction(new F.Function0<GroupAccount>() {
@Override
public GroupAccount apply() throws Throwable {
return GroupAccount.find(account, group);
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
/**
* Establishes a group membership of an account to a group.
*
* @param account Account
* @param group Group
*/
public void establishGroupMembership(final Account account, final Group group) {
JPA.withTransaction(new F.Callback0() {
@Override
public void invoke() throws Throwable {
if (!Group.isMember(group, account)) {
groupAccount.account = account;
groupAccount.group = group;
groupAccount.linkType = LinkType.establish;
testGroupAccount.create();
group.update();
}
}
});
}
/**
* Removes a membership of an account to a group.
*
* @param account Account
* @param group Group
*/
public void removeGroupMembership(final Account account, final Group group) {
JPA.withTransaction(new F.Callback0() {
@Override
public void invoke() throws Throwable {
if (Group.isMember(group, account)) {
GroupAccount groupAccount = GroupAccount.find(account, group);
groupAccount.delete();
}
}
});
}
/**
* Logs in an account into the test HTTP context.
*
* @param account Account to login
*/
public void loginAccount(Account account) {
Http.Context.current().session().put("id", account.id.toString());
Http.Context.current().args.put("account", account);
}
/**
* Logs in a test account.
*
* @param testAccountNumber Test account number
*/
public void loginTestAccount(int testAccountNumber) {
Account testAccount = this.getTestAccount(testAccountNumber);
this.loginAccount(testAccount);
}
/**
* Logs in the default admin account.
*/
public void loginAdminAccount() {
Account adminAccount = this.getAdminAccount();
this.loginAccount(adminAccount);
}
/**
* Logs out a test account.
*/
public void logoutTestAccount() {
Http.Context.current().session().remove("id");
}
/**
* Force a thread sleep.
*
* @param seconds Seconds how long to sleep
*/
protected void sleep(int seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* Returns the current HTTP context.
*
* @return Context instance
*/
protected Http.Context getContext() {
return Http.Context.current();
}
}