/*
* Copyright 2014 GoDataDriven B.V.
*
* 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 io.divolte.server;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import io.divolte.server.ServerTestUtils.EventPayload;
import io.divolte.server.ServerTestUtils.TestServer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import static org.junit.Assert.*;
@ParametersAreNonnullByDefault
public class RequestChecksumTest {
private static final String URL_STRING = "http://localhost:%d/csc-event";
private static final String URL_QUERY_CHECKSUM_MISSING = '?'
+ "p=0%3Ai1t84hgy%3A5AF359Zjq5kUy98u4wQjlIZzWGhN~GlG&"
+ "s=0%3Ai1t84hgy%3A95CbiPCYln_1e0a6rFvuRkDkeNnc6KC8&"
+ "v=0%3A1fF6GFGjDOQiEx_OxnTm_tl4BH91eGLF&"
+ "e=0%3A1fF6GFGjDOQiEx_OxnTm_tl4BH91eGLF0&"
+ "c=i1t8q2b6&"
+ "n=f&"
+ "f=f&"
+ "l=http%3A%2F%2Flocalhost%3A8290%2F&"
+ "i=1ak&"
+ "j=sj&"
+ "k=2&"
+ "w=uq&"
+ "h=qd&"
+ "t=pageView";
private static final String URL_QUERY_CHECKSUM_GOOD = URL_QUERY_CHECKSUM_MISSING + "&x=si9804";
private static final String URL_QUERY_CHECKSUM_BAD = URL_QUERY_CHECKSUM_MISSING + "&x=si9805";
private static final String[] URL_QUERY_CHECKSUM_PARTIALS = {
URL_QUERY_CHECKSUM_MISSING + "&x",
URL_QUERY_CHECKSUM_MISSING + "&x=",
};
private static final String URL_QUERY_CHECKSUM_UNICODE = '?'
+ "p=0%3Ai1t84hgy%3Aparty&"
+ "s=0%3Ai1t84hgy%3Asession&"
+ "v=0%3ApageView&"
+ "e=0%3AeventId&"
+ "c=i1t8q2b6&"
+ "n=f&"
+ "f=f&"
+ "l=http%3A%2F%2Flocalhost%3A8290%2F&"
+ "i=1ak&"
+ "j=sj&"
+ "k=2&"
+ "w=uq&"
+ "h=qd&"
+ "t=%E1%BB%A5%C3%B1%E2%9A%95%C2%A9%C2%BA%E1%B8%8C%E2%84%A8&"
+ "x=-ql2p2c";
private static final String URL_QUERY_SENTINEL = '?'
+ "p=0%3Ai1t84hgy%3Aparty&"
+ "s=0%3Ai1t84hgy%3Asession&"
+ "v=0%3ApageView&"
+ "e=0%3AeventId&"
+ "c=i1t8q2b6&"
+ "n=f&"
+ "f=f&"
+ "l=http%3A%2F%2Flocalhost%3A8290%2F&"
+ "i=1ak&"
+ "j=sj&"
+ "k=2&"
+ "w=uq&"
+ "h=qd&"
+ "t=sentinelEvent&"
+ "x=-y99lem";
private boolean discardCorruptEvents;
@Nullable
private TestServer server;
@Nullable
private ImmutableMap<String,Object> serverProperties;
@Test
public void shouldFlagCorrectChecksumAsNotCorrupted() throws IOException, InterruptedException {
request(URL_QUERY_CHECKSUM_GOOD);
Preconditions.checkState(null != server);
final EventPayload payload = server.waitForEvent();
assertFalse(payload.event.corruptEvent);
}
@Test
public void shouldFlagIncorrectChecksumAsCorrupted() throws IOException, InterruptedException {
request(URL_QUERY_CHECKSUM_BAD);
Preconditions.checkState(null != server);
final EventPayload payload = server.waitForEvent();
assertTrue(payload.event.corruptEvent);
}
@Test
public void shouldFlagMissingChecksumAsCorrupted() throws IOException, InterruptedException {
request(URL_QUERY_CHECKSUM_MISSING);
Preconditions.checkState(null != server);
final EventPayload payload = server.waitForEvent();
assertTrue(payload.event.corruptEvent);
}
@Test
public void shouldFlagPartialChecksumAsCorrupted() throws IOException, InterruptedException {
for (final String urlQueryChecksumPartial : URL_QUERY_CHECKSUM_PARTIALS) {
request(urlQueryChecksumPartial);
Preconditions.checkState(null != server);
final EventPayload payload = server.waitForEvent();
assertTrue(payload.event.corruptEvent);
}
}
@Test
public void shouldChecksumCorrectlyWithNonAsciiParameters() throws IOException, InterruptedException {
request(URL_QUERY_CHECKSUM_UNICODE);
Preconditions.checkState(null != server);
final EventPayload payload = server.waitForEvent();
final DivolteEvent eventData = payload.event;
assertFalse(eventData.corruptEvent);
assertEquals("ụñ⚕©ºḌℨ", eventData.eventType.get());
}
@Test
public void shouldDiscardCorruptedEventsIfConfigured() throws InterruptedException, IOException {
discardCorruptEvents = true;
request(URL_QUERY_CHECKSUM_BAD);
request(URL_QUERY_SENTINEL);
Preconditions.checkState(null != server);
final EventPayload payload = server.waitForEvent();
// The first request should be missing, and we should now have the sentinel event.
final String eventType = payload.event.eventType.get();
assertEquals("sentinelEvent", eventType);
}
private void request(final String queryString) throws IOException {
setServerConf(ImmutableMap.of("divolte.mappings.test.discard_corrupted", discardCorruptEvents));
Preconditions.checkState(null != server);
final URL url = new URL(String.format(URL_STRING, server.port) + queryString);
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
assertEquals(200, conn.getResponseCode());
}
private void setServerConf(final Map<String,Object> configurationProperties) {
if (null == server || !configurationProperties.equals(serverProperties)) {
serverProperties = ImmutableMap.copyOf(configurationProperties);
setServer(new TestServer("base-test-server.conf", serverProperties));
}
}
@Before
public void setUp() {
discardCorruptEvents = false;
}
@After
public void tearDown() {
setServer(null);
}
private void setServer(@Nullable final TestServer newServer) {
final TestServer oldServer = this.server;
if (oldServer != newServer) {
if (null != oldServer) {
oldServer.server.shutdown();
}
this.server = newServer;
}
}
}