Подтвердить что ты не робот

Playframework Защищенный модуль: как вы "входите", чтобы протестировать защищенный контроллер в FunctionalTest?

EDIT: я использую Play! версия 1.2 (выпуск продукции)

Я хочу проверить действия контроллера, защищенные модулем Secure класс, поэтому мне нужно войти в систему до тестирования моего контроллера (иначе я буду перенаправлен на страницу входа).

Я попытался войти в систему до вызова защищенного действия. Вот как выглядит мой FunctionalTest:

@Test
public void someTestOfASecuredAction() {
    Map<String, String> loginUserParams = new HashMap<String, String>(); 
    loginUserParams.put("username", "admin"); 
    loginUserParams.put("password", "admin");

    // Login here so the following request will be authenticated:
    Response response = POST("/login", loginUserParams);

    // The following is an action that requires an authenticated user:
    Map<String, String> params;
    params.put("someparam", "somevalue");
    response = POST("/some/secured/action", params);

    assertIsOk(response); // this always fails because it is a 302 redirecting to /login
}

Пройдя через код, я подтвердил, что почта входа работает - это вызывает ответ перенаправления с местоположением, установленным на домашней странице (что указывает на успешный вход в систему).

Но затем в следующем вызове защищенного действия я всегда перенаправляюсь на "/login" - это означает, что мой предыдущий логин не был прикреплен ко второму запросу POST.

Взглянув в исходный код FunctionalTest, я увидел, что был перехватчик @Before, который очищает все файлы cookie. Я попытался переопределить этот intercepter в моем собственном промежуточном суперклассе (чтобы сохранить файлы cookie), но это тоже не сработало.

РЕДАКТИРОВАТЬ: я сбивал с толку play.mvc.Before перед перехватчиком с org.junit. Прежде - первый для использования с Play! контроллеров, последний для тестов JUnit. @Before в FuncitonTest является перехватчиком JUnit, поэтому он должен иметь какое-либо влияние на файлы cookie (поскольку он запускается один раз до запуска теста).

Я не хочу писать тест Selenium для каждого защищенного действия - так как почти все будут защищены. Есть ли способ "обмануть" модуль Secure, полагая, что вы прошли проверку подлинности? Или, может быть, какой-то другой очень очевидный способ справиться с этим (казалось бы, общим) сценарием в FunctionalTest?

Спасибо заранее,

Марк

EDIT: рабочий код, ответ Codemwnci помечен как правильный

Ответ Codemwnci правильный. Вот мой способ обхода файлов cookie с одного запроса на следующий:

@Test
public void someTestOfASecuredAction() {
    Map<String, String> loginUserParams = new HashMap<String, String>();
    loginUserParams.put("username", "admin");
    loginUserParams.put("password", "admin");
    Response loginResponse = POST("/login", loginUserParams);

    Request request = newRequest();
    request.cookies = loginResponse.cookies; // this makes the request authenticated
    request.url = "/some/secured/action";
    request.method = "POST";
    request.params.put("someparam", "somevalue");
    Response response = makeRequest(request);
    assertIsOk(response); // Passes!
}
4b9b3361

Ответ 1

Я думаю, что должно быть непонимание того, что делает перехватчик @Before. Он выполняется до выполнения вашего теста. Если ваш тест затем регистрирует вас, то это событие происходит ПОСЛЕ того, как код @Before был выполнен, а результаты защищенного модуля должны быть сохранены в Cookie.

Поэтому я могу только предположить, что Cookie не отправляется со следующим запросом, поэтому я бы предложил попробовать следующее...

получить cookie, используемый безопасным файлом cookie, из объекта Response сразу после вашего входа. Создайте объект Request и установите Cookie в объект запроса, затем вызовите свой метод POST, передав объект запроса.

Я не тестировал этот код, поэтому не уверен, как он будет реагировать на смешение предварительно созданного объекта запроса и передачу URL-адреса, но не уверен, что еще предложить.

Ответ 2

У меня была та же проблема, но в тестах с Play 2.0.4.

Я решил проблему, выполнив следующие Seb и Codemwnci, и я построил, проверив API, следующее решение:

@Test
public void listSomething() {
    running(fakeApplication(inMemoryDatabase()), new Runnable() {
        @Override
        public void run() {
            // LOGIN
            final Map<String, String> data = new HashMap<String, String>();
            data.put("email", "[email protected]");
            data.put("password", "userpassword");

            Result result = callAction(
            controllers.routes.ref.Application.authenticate(),
            fakeRequest().withFormUrlEncodedBody(data));

            // RECOVER COOKIE FROM LOGIN RESULT
            final Cookie playSession = play.test.Helpers.cookie("PLAY_SESSION",
                                                                result);

            // LIST SOMETHING (using cookie of the login result)
            result = callAction(controllers.routes.ref.Application.list(), 
                                fakeRequest().withCookies(playSession));

            /* 
             * WAS RECEIVING 'SEE_OTHER' (303) 
             * BEFORE RECOVERING PLAY_SESSION COOKIE (BECAUSE NOT LOGGED IN).
             *
             * NOW, EXPECTED 'OK'
             */ 
            assertThat(status(result)).isEqualTo(OK); 
            assertThat(contentAsString(result)).contains(
                    "Something found");
        }
    });
}

Application.list() выглядит примерно так:

@Security.Authenticated(Secured.class)
public static Result list() {
   return ok(list.render(...));
}

Ответ 3

Возможно, вы видите https://bugs.launchpad.net/play/+bug/497408

Я думаю, что он должен работать.

Обновление: я немного отлаживал. Я думаю, что есть две ошибки.

  • В FunctionalTest файлы cookie просто отбрасываются, если у них нет maxAge.
  • В Scope.java в сеансе поле "TS" устанавливается только в том случае, если ранее существовал файл cookie. Поэтому при первом запуске cookie сеанса он игнорируется при отправке обратно на сервер. Если вы делаете 3 запроса, кажется, что они работают нормально между запросами 2 и 3, но не между запросами 1 и 2, потому что по запросу 2 отправленный cookie не имеет метки времени.

Итак, ошибка 1 разбивает его, если вы не устанавливаете maxAge, а ошибка 2 прерывает его, если вы устанавливаете maxAge.

Обновление 2: я сделал несколько исправлений, которые исправили это для меня: http://play.lighthouseapp.com/projects/57987-play-framework/tickets/775

Ответ 4

Хотите указать, что в окончательном решении Mark S есть ошибка.

Это неверно: request.url = "/some/secured/action";

Это правильно: request.path = "/some/secured/action";

"url" должен быть полным URL-адресом.