天道酬勤,学无止境

how to setup database/fixture for functional tests in playframework

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

评论

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();
}

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐