问题
I am trying to test my Controller - Secure.java. I use play's Fixtures class to setup the database. Unfortunately as the POST call is issued and the control's method is called the database turns out to be empty. However, inside the test-method I can retrieve the data as expected.
The routes
POST /login user.Secure.authenticate
The controller Secure.java:
package controllers.user;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Date;
import java.util.TimeZone;
import models.User;
import play.Logger;
import play.Play;
import play.data.validation.Required;
import play.libs.Crypto;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Util;
import play.utils.Java;
import mashpan.crawl.dropbox.DropboxCrawler;
import mashpan.security.Check;
import mashpan.utilities.*;
import controllers.Application;
/**
* a more or less exact copy of the secure implementation of play.
* - enhanced with a transport guarantee.
* - support for user authentification
*
* @author ra and Philip De Smedt
* @version 0.1
* @date 20/11/2011
*
*/
public class Secure extends TransportUriGuaranteeController {
public static void authenticate(@Required String username, String password, boolean remember) throws Throwable {
Logger.debug("[Secure] authenticate: "
+ "[username=" + (username == null ? "null" : username.toString()) + "]"
+ "[password=" + (password == null ? "null" : password.toString()) + "]"
+ "[remember=" + remember + "]"
);
// Check tokens
Boolean allowed = false;
User user = User.find("byEmail", username).first();
Logger.debug("[Secure.authenticate] "+"[user=" + (user == null ? "null" : user.toString()) + "]");
// try {
// // This is the deprecated method name
// allowed = (Boolean)Security.invoke("authentify", username, password);
// }
// catch (UnsupportedOperationException e )
// {
// // This is the official method name
// allowed = (Boolean)Security.invoke("authenticate", username, password);
// }
allowed = Security.authenticate(username, password);
if(validation.hasErrors() || !allowed) {
Logger.debug("[Secure] Authentication failed"
+ ", validationhasErrors()=" + validation.hasErrors()
+ ", allowed="+allowed
);
if(validation.hasErrors()) {
Logger.debug("[Secure] validation has errors!");
for(play.data.validation.Error e : validation.errors()) {
Logger.debug("[Secure] Error: "+"[e=" + (e == null ? "null" : e.toString()) + "]");
}
}
flash.keep("url");
flash.error("secure.error");
params.flash();
Application.index();
}
// Mark user as connected
session.put("email", username);
// Remember if needed
if (remember)
{
response.setCookie("rememberme", Crypto.sign(username) + "-" + username, "30d");
}
// Save last login time and redirect to the original URL (or /)
User u = User.find("byEmail", username).first();
u.lastLogin = new Date();
u.save();
Logger.debug("[Secure] Successfully authenticated user. Redirecting...");
redirectToOriginalURL();
}
public static class Security extends Controller {
/**
* Extend Play!s security mechanism to authenticate against
* the User object.
*/
public static boolean authenticate(String email, String password) {
Logger.debug("[Secure.Security.authenticate] "
+ "[email=" + (email == null ? "null" : email.toString()) + "]"
+ "[password=" + (password == null ? "null" : password.toString()) + "]");
User user = User.find("byEmail", email).first();
List<User> users = User.<User>findAll();
Logger.debug("[Secure.Security] # of users found="+users.size());
for(User u : users) {
Logger.debug("[Secure.Security] "+"[u=" + (u == null ? "null" : u.toString()) + "]");
}
if (user == null) {
Logger.debug("[Secure.Security] Could not find user, authentication failed!");
return false;
}
if (user.confirmationCode.length() != 0) { //user not confirmed yet
Logger.debug("[Secure.Security] User not confirmed yet, authentication failed!");
return false;
}
return user.isThisCorrectUserPassword(password);
}
public static boolean check(String check) {
if ("isConnected".equals(check)) {
return Security.isConnected();
}
return false;
}
/**
* This method returns the current connected username
* @return
*/
public static String connected() {
return session.get("email");
}
/**
* Indicate if a user is currently connected
* @return true if the user is connected
*/
public static boolean isConnected() {
return session.contains("email");
}
/**
* This method is called after a successful authentication.
* You need to override this method if you with to perform specific actions (eg. Record the time the user signed in)
*/
static void onAuthenticated() { }
/**
* This method is called before a user tries to sign off.
* You need to override this method if you wish to perform specific actions (eg. Record the name of the user who signed off)
*/
static void onDisconnect() { }
/**
* This method is called after a successful sign off.
* You need to override this method if you wish to perform specific actions (eg. Record the time the user signed off)
*/
static void onDisconnected() { }
/**
* This method is called if a check does not succeed. By default it shows the not allowed page (the controller forbidden method).
* @param profile
*/
static void onCheckFailed(String profile) {
forbidden();
}
}
}
the test class SecureTest.java
package controller.user;
import java.util.*;
import mashpan.utilities.*;
import models.*;
import org.junit.*;
import play.*;
import play.cache.*;
import play.db.jpa.GenericModel.JPAQuery;
import play.mvc.Http.Response;
import play.test.*;
public class FunctionalSecureTests extends FunctionalTest {
@Before
public void setUp() {
Fixtures.deleteDatabase();
Fixtures.loadModels("testusers.yaml");
Cache.clear();
}
@Test
public void postLogin_shouldHaveStatus200() {
User user = User.find("byEmail", UserUtility.EMAIL).first();
Logger.debug("[FunctionalSecureTests] "+"[user=" + (user == null ? "null" : user.toString()) + "]"); //prints out
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("username", UserUtility.EMAIL);
parameters.put("password", UserUtility.PASSWORD);
Response response = POST("/login", parameters);
assertIsOk(response);
assertStatus(200, response);
}
}
conf/testusers.yaml
User(mashpan):
first_name: "Mash"
last_name: "Pan"
email: "tester@gmail.com"
signupDate: 2012-03-08
passwordHash: "NOTFORYOU"
isAdmin: No
confirmationCode: ""
activationSent: Yes
recoverPasswordCode: !!null
lastLogin: !!null
referralCode: !!null
stacktrace
DEBUG 232 :play#debug - [FunctionalSecureTests] [user=User [first_name=Mash, last_name=Pan, email=mashpantester@gmail.com, signupDate=2012-03-08 01:00:00.0, passwordHash=$2a$10$L6IdeDhMGe1T7IbtSDd.6uLOvhHk7IoAzRzGzNlk8Cm4WWyWCbIp., isAdmin=false, confirmationCode=, activationSent=true, recoverPasswordCode=null, lastLogin=null, referralCode=null, [id=1]]]
DEBUG 232 :play#debug - [Secure] authenticate: [username=mashpantester@gmail.com][password=chickenrunfasteriffedup][remember=false]
DEBUG 232 :play#debug - [Secure.authenticate] [user=null]
DEBUG 232 :play#debug - [Secure.Security.authenticate] [email=mashpantester@gmail.com][password=chickenrunfasteriffedup]
DEBUG 232 :play#debug - [Secure.Security] # of users found=0
DEBUG 232 :play#debug - [Secure.Security] Could not find user, authentication failed!
DEBUG 232 :play#debug - [Secure] Authentication failed, validationhasErrors()=false, allowed=false
回答1:
Your functional test run in a transaction that will end at the end of the test. So everything you do in this transaction won't be commited to the database until the test is finished. So in this case you can use a job to create a new transaction only for the setup
@Before
public void setUp() throws Exception {
new Job() {
@Override
public void doJob() throws Exception {
Fixtures.deleteDatabase();
Fixtures.loadModels("testusers.yaml");
Cache.clear();
}
}.now().get();
}
回答2:
Just add :
JPA.em().getTransaction().commit();
After Fixtures.loadModels
.
来源:https://stackoverflow.com/questions/9708356/how-to-setup-database-fixture-for-functional-tests-in-playframework