google-nomulus/javatests/google/registry/ui/server/registrar/ConsoleUiActionTest.java
guyben 97aa98eb35 Add metrics for registrar console requests
Cardinality of this metric:

clientId: there are currently 650 (on sandbox, because of OTE), and 200 on production.
explicitClientId: 2
roles: 2 now, might be 3 soon if we add vendors
status: 2

So we're talking about a cardinality of 2,000-8,000. Less when you consider that registrars only seldom actually need to access the console (certainly not daily or even weekly).

Compare with, e.g., the /epp/processing_time from the above EppMetrics.java which has:
Epp commands: 26 (manual counting)
client IDs: 200 on prod
status: the actual status CODE of the command. Can have many values, but looking at the past few weeks' metrics I counted 20
Note that not every command results in every status. Looking a few weeks back we can see around 80-100 (commands+status) combination.
buckets: 16

so that's over 250,000-1,000,000 cardinality, on a very high-volume metric.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=218699280
2018-10-25 14:51:58 -04:00

205 lines
8.5 KiB
Java

// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.ui.server.registrar;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.truth.Truth.assertThat;
import static com.google.monitoring.metrics.contrib.LongMetricSubject.assertThat;
import static google.registry.testing.DatastoreHelper.loadRegistrar;
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.Role.ADMIN;
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.Role.OWNER;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.net.MediaType;
import google.registry.request.HttpException.ForbiddenException;
import google.registry.request.auth.AuthLevel;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.UserAuthInfo;
import google.registry.security.XsrfTokenManager;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.UserInfo;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link ConsoleUiAction}. */
@RunWith(JUnit4.class)
public class ConsoleUiActionTest {
@Rule
public final AppEngineRule appEngineRule = AppEngineRule.builder()
.withDatastore()
.withUserService(UserInfo.create("marla.singer@example.com", "12345"))
.build();
private final AuthenticatedRegistrarAccessor registrarAccessor =
mock(AuthenticatedRegistrarAccessor.class);
private final HttpServletRequest request = mock(HttpServletRequest.class);
private final FakeResponse response = new FakeResponse();
private final ConsoleUiAction action = new ConsoleUiAction();
private final User user = new User("marla.singer@example.com", "gmail.com", "12345");
@Before
public void setUp() {
action.enabled = true;
action.logoFilename = "logo.png";
action.productName = "Nomulus";
action.integrationEmail = "integration@example.com";
action.supportEmail = "support@example.com";
action.announcementsEmail = "announcements@example.com";
action.supportPhoneNumber = "1 (888) 555 0123";
action.technicalDocsUrl = "http://example.com/technical-docs";
action.req = request;
action.response = response;
action.registrarConsoleMetrics = new RegistrarConsoleMetrics();
action.registrarAccessor = registrarAccessor;
action.userService = UserServiceFactory.getUserService();
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
action.paramClientId = Optional.empty();
AuthResult authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
action.authResult = authResult;
when(registrarAccessor.getRegistrar("TheRegistrar"))
.thenReturn(loadRegistrar("TheRegistrar"));
when(registrarAccessor.getAllClientIdWithRoles())
.thenReturn(
ImmutableSetMultimap.of(
"TheRegistrar", OWNER,
"OtherRegistrar", OWNER,
"OtherRegistrar", ADMIN,
"AdminRegistrar", ADMIN));
when(registrarAccessor.guessClientId()).thenCallRealMethod();
// Used for error message in guessClientId
registrarAccessor.authResult = authResult;
RegistrarConsoleMetrics.consoleRequestMetric.reset();
}
@After
public void tearDown() throws Exception {
assertThat(RegistrarConsoleMetrics.consoleRequestMetric).hasNoOtherValues();
}
public void assertMetric(String clientId, String explicitClientId, String roles, String status) {
assertThat(RegistrarConsoleMetrics.consoleRequestMetric)
.hasValueForLabels(1, clientId, explicitClientId, roles, status);
RegistrarConsoleMetrics.consoleRequestMetric.reset(clientId, explicitClientId, roles, status);
}
@Test
public void testWebPage_disallowsIframe() {
action.run();
assertThat(response.getHeaders()).containsEntry("X-Frame-Options", "SAMEORIGIN");
assertMetric("TheRegistrar", "false", "[OWNER]", "SUCCESS");
}
@Test
public void testWebPage_setsHtmlUtf8ContentType() {
action.run();
assertThat(response.getContentType()).isEqualTo(MediaType.HTML_UTF_8);
assertMetric("TheRegistrar", "false", "[OWNER]", "SUCCESS");
}
@Test
public void testWebPage_containsUserNickname() {
action.run();
assertThat(response.getPayload()).contains("marla.singer");
assertMetric("TheRegistrar", "false", "[OWNER]", "SUCCESS");
}
@Test
public void testUserHasAccessAsTheRegistrar_showsRegistrarConsole() {
action.run();
assertThat(response.getPayload()).contains("Registrar Console");
assertThat(response.getPayload()).contains("reg-content-and-footer");
assertMetric("TheRegistrar", "false", "[OWNER]", "SUCCESS");
}
@Test
public void testConsoleDisabled_showsDisabledPage() {
action.enabled = false;
action.run();
assertThat(response.getPayload()).contains("<h1>Console is disabled</h1>");
}
@Test
public void testUserDoesntHaveAccessToAnyRegistrar_showsWhoAreYouPage() {
when(registrarAccessor.getAllClientIdWithRoles()).thenReturn(ImmutableSetMultimap.of());
action.run();
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
assertThat(response.getPayload()).contains("not associated with Nomulus.");
assertMetric("<null>", "false", "[]", "FORBIDDEN");
}
@Test
public void testNoUser_redirect() {
when(request.getRequestURI()).thenReturn("/test");
action.authResult = AuthResult.NOT_AUTHENTICATED;
action.run();
assertThat(response.getStatus()).isEqualTo(SC_MOVED_TEMPORARILY);
assertThat(response.getHeaders().get(LOCATION)).isEqualTo("/_ah/login?continue=%2Ftest");
}
@Test
public void testNoUserInformationAtAll_redirectToRoot() {
when(request.getRequestURI()).thenThrow(new IllegalArgumentException());
action.authResult = AuthResult.NOT_AUTHENTICATED;
action.run();
assertThat(response.getStatus()).isEqualTo(SC_MOVED_TEMPORARILY);
assertThat(response.getHeaders().get(LOCATION)).isEqualTo("/");
}
@Test
public void testSettingClientId_notAllowed_showsNeedPermissionPage() {
// Behaves the same way if fakeRegistrar exists, but we don't have access to it
action.paramClientId = Optional.of("fakeRegistrar");
when(registrarAccessor.getRegistrar("fakeRegistrar"))
.thenThrow(new ForbiddenException("forbidden"));
action.run();
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
assertThat(response.getPayload()).contains("not associated with the registrar fakeRegistrar.");
assertMetric("fakeRegistrar", "true", "[]", "FORBIDDEN");
}
@Test
public void testSettingClientId_allowed_showsRegistrarConsole() {
action.paramClientId = Optional.of("OtherRegistrar");
when(registrarAccessor.getRegistrar("OtherRegistrar"))
.thenReturn(loadRegistrar("TheRegistrar"));
action.run();
assertThat(response.getPayload()).contains("Registrar Console");
assertThat(response.getPayload()).contains("reg-content-and-footer");
assertMetric("OtherRegistrar", "true", "[OWNER, ADMIN]", "SUCCESS");
}
@Test
public void testUserHasAccessAsTheRegistrar_showsClientIdChooser() {
action.run();
assertThat(response.getPayload()).contains("<option value=\"TheRegistrar\" selected>");
assertThat(response.getPayload()).contains("<option value=\"OtherRegistrar\">");
assertThat(response.getPayload()).contains("<option value=\"AdminRegistrar\">");
assertMetric("TheRegistrar", "false", "[OWNER]", "SUCCESS");
}
}