diff options
Diffstat (limited to 'vespaclient-container-plugin/src/test/java')
13 files changed, 843 insertions, 0 deletions
diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/CollectingMetric.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/CollectingMetric.java new file mode 100644 index 00000000000..1b9a5eb6381 --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/CollectingMetric.java @@ -0,0 +1,38 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.yahoo.jdisc.Metric; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author ollivir + */ +public final class CollectingMetric implements Metric { + private final Context DUMMY_CONTEXT = new Context() {}; + private final Map<String, AtomicLong> values = new ConcurrentHashMap<>(); + + public CollectingMetric() {} + + @Override + public void set(String key, Number val, Context ctx) { + values.computeIfAbsent(key, ignored -> new AtomicLong(0)).set(val.longValue()); + } + + @Override + public void add(String key, Number val, Context ctx) { + values.computeIfAbsent(key, ignored -> new AtomicLong(0)).addAndGet(val.longValue()); + } + + public long get(String key) { + return Optional.ofNullable(values.get(key)).map(AtomicLong::get).orElse(0L); + } + + @Override + public Context createContext(Map<String, ?> properties) { + return DUMMY_CONTEXT; + } +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/DummyMetric.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/DummyMetric.java new file mode 100644 index 00000000000..1cdac87f3df --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/DummyMetric.java @@ -0,0 +1,31 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.yahoo.jdisc.Metric; + +import java.util.Map; + +/** + * @author Einar M R Rosenvinge + * @since 5.1.20 + */ +class DummyMetric implements Metric { + + @Override + public void set(String key, Number val, Context ctx) { + } + + @Override + public void add(String key, Number val, Context ctx) { + } + + @Override + public Context createContext(Map<String, ?> properties) { + return DummyContext.INSTANCE; + } + + private static class DummyContext implements Context { + private static final DummyContext INSTANCE = new DummyContext(); + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerCompressionTest.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerCompressionTest.java new file mode 100644 index 00000000000..6f1b5eebcc4 --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerCompressionTest.java @@ -0,0 +1,69 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.yahoo.container.jdisc.HttpRequest; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPOutputStream; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FeedHandlerCompressionTest { + + public static byte[] compress(final String dataToBrCompressed) throws IOException { + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(dataToBrCompressed.length()); + final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream); + gzipOutputStream.write(dataToBrCompressed.getBytes()); + gzipOutputStream.close(); + byte[] compressedBytes = byteArrayOutputStream.toByteArray(); + byteArrayOutputStream.close(); + return compressedBytes; + } + + @Test + public void testUnzipStreamIfNeeded() throws Exception { + final String testData = "foo bar"; + InputStream inputStream = new ByteArrayInputStream(compress(testData)); + HttpRequest httpRequest = mock(HttpRequest.class); + when(httpRequest.getHeader("content-encoding")).thenReturn("gzip"); + InputStream decompressedStream = FeedHandler.unzipStreamIfNeeded(inputStream, httpRequest); + final StringBuilder processedInput = new StringBuilder(); + while (true) { + int readValue = decompressedStream.read(); + if (readValue < 0) { + break; + } + processedInput.append((char)readValue); + } + assertEquals(processedInput.toString(), testData); + } + + /** + * Test by setting encoding, but not compressing data. + * @throws Exception + */ + @Test + public void testUnzipFails() throws Exception { + final String testData = "foo bar"; + InputStream inputStream = new ByteArrayInputStream(testData.getBytes()); + HttpRequest httpRequest = mock(HttpRequest.class); + when(httpRequest.getHeader("Content-Encoding")).thenReturn("gzip"); + InputStream decompressedStream = FeedHandler.unzipStreamIfNeeded(inputStream, httpRequest); + final StringBuilder processedInput = new StringBuilder(); + while (true) { + int readValue = decompressedStream.read(); + if (readValue < 0) { + break; + } + processedInput.append((char)readValue); + } + assertEquals(processedInput.toString(), testData); + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerTest.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerTest.java new file mode 100644 index 00000000000..f3ea8fb5a80 --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerTest.java @@ -0,0 +1,45 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; +import com.yahoo.container.handler.threadpool.ContainerThreadPool; +import com.yahoo.container.jdisc.RequestHandlerTestDriver; +import com.yahoo.document.DocumentTypeManager; +import com.yahoo.document.config.DocumentmanagerConfig; +import com.yahoo.jdisc.handler.OverloadException; +import com.yahoo.metrics.simple.MetricReceiver; +import org.junit.Test; + +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +import static com.yahoo.vespa.http.server.FeedHandlerV3Test.createRequest; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author bjorncs + */ +public class FeedHandlerTest { + + @Test + public void response_has_status_code_429_when_throttling() { + FeedHandler handler = new FeedHandler( + new RejectingContainerThreadpool(), + new CollectingMetric(), + new DocumentTypeManager(new DocumentmanagerConfig.Builder().enablecompression(true).build()), + null /* session cache */, + MetricReceiver.nullImplementation); + var responseHandler = new RequestHandlerTestDriver.MockResponseHandler(); + try { + handler.handleRequest(createRequest(100).getJDiscRequest(), responseHandler); + fail(); + } catch (OverloadException e) {} + assertEquals(429, responseHandler.getStatus()); + } + + private static class RejectingContainerThreadpool implements ContainerThreadPool { + private final Executor executor = ignored -> { throw new RejectedExecutionException(); }; + + @Override public Executor executor() { return executor; } + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerV3Test.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerV3Test.java new file mode 100644 index 00000000000..a5a8f4cb5bd --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedHandlerV3Test.java @@ -0,0 +1,152 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.google.common.base.Splitter; +import com.yahoo.container.jdisc.HttpRequest; +import com.yahoo.container.jdisc.HttpResponse; +import com.yahoo.container.jdisc.messagebus.SessionCache; +import com.yahoo.document.DataType; +import com.yahoo.document.DocumentType; +import com.yahoo.document.DocumentTypeManager; +import com.yahoo.document.config.DocumentmanagerConfig; +import com.yahoo.documentapi.messagebus.protocol.PutDocumentMessage; +import com.yahoo.documentapi.metrics.DocumentApiMetrics; +import com.yahoo.jdisc.ReferencedResource; +import com.yahoo.messagebus.Result; +import com.yahoo.messagebus.SourceSessionParams; +import com.yahoo.messagebus.shared.SharedSourceSession; +import com.yahoo.metrics.simple.MetricReceiver; +import com.yahoo.text.Utf8; +import com.yahoo.vespa.http.client.config.FeedParams; +import com.yahoo.vespa.http.client.core.ErrorCode; +import com.yahoo.vespa.http.client.core.Headers; +import com.yahoo.vespa.http.client.core.OperationStatus; +import org.junit.Test; +import org.mockito.stubbing.Answer; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FeedHandlerV3Test { + final CollectingMetric metric = new CollectingMetric(); + private final Executor simpleThreadpool = Executors.newCachedThreadPool(); + + @Test + public void feedOneDocument() throws Exception { + final FeedHandlerV3 feedHandlerV3 = setupFeederHandler(simpleThreadpool); + HttpResponse httpResponse = feedHandlerV3.handle(createRequest(1)); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + httpResponse.render(outStream); + assertEquals(httpResponse.getContentType(), "text/plain"); + assertEquals(Utf8.toString(outStream.toByteArray()), "1230 OK message trace\n"); + } + + @Test + public void feedOneBrokenDocument() throws Exception { + final FeedHandlerV3 feedHandlerV3 = setupFeederHandler(simpleThreadpool); + HttpResponse httpResponse = feedHandlerV3.handle(createBrokenRequest()); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + httpResponse.render(outStream); + assertEquals(httpResponse.getContentType(), "text/plain"); + assertTrue(Utf8.toString(outStream.toByteArray()).startsWith("1230 ERROR ")); + assertEquals(1L, metric.get(MetricNames.PARSE_ERROR)); + } + + @Test + public void feedManyDocument() throws Exception { + final FeedHandlerV3 feedHandlerV3 = setupFeederHandler(simpleThreadpool); + HttpResponse httpResponse = feedHandlerV3.handle(createRequest(100)); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + httpResponse.render(outStream); + assertEquals(httpResponse.getContentType(), "text/plain"); + String result = Utf8.toString(outStream.toByteArray()); + assertEquals(101, Splitter.on("\n").splitToList(result).size()); + } + + private static DocumentTypeManager createDoctypeManager() { + DocumentTypeManager docTypeManager = new DocumentTypeManager(); + DocumentType documentType = new DocumentType("testdocument"); + documentType.addField("title", DataType.STRING); + documentType.addField("body", DataType.STRING); + docTypeManager.registerDocumentType(documentType); + return docTypeManager; + } + + static HttpRequest createRequest(int numberOfDocs) { + StringBuilder wireData = new StringBuilder(); + for (int x = 0; x < numberOfDocs; x++) { + String docData = "[{\"put\": \"id:testdocument:testdocument::c\", \"fields\": { \"title\": \"fooKey\", \"body\": \"value\"}}]"; + String operationId = "123" + x; + wireData.append(operationId + " " + Integer.toHexString(docData.length()) + "\n" + docData); + } + return createRequestWithPayload(wireData.toString()); + } + + private static HttpRequest createBrokenRequest() { + String docData = "[{\"put oops I broke it]"; + String wireData = "1230 " + Integer.toHexString(docData.length()) + "\n" + docData; + return createRequestWithPayload(wireData); + } + + static HttpRequest createRequestWithPayload(String payload) { + InputStream inputStream = new ByteArrayInputStream(payload.getBytes()); + HttpRequest request = HttpRequest.createTestRequest("http://dummyhostname:19020/reserved-for-internal-use/feedapi", + com.yahoo.jdisc.http.HttpRequest.Method.POST, inputStream); + request.getJDiscRequest().headers().add(Headers.VERSION, "3"); + request.getJDiscRequest().headers().add(Headers.DATA_FORMAT, FeedParams.DataFormat.JSON_UTF8.name()); + request.getJDiscRequest().headers().add(Headers.TIMEOUT, "1000000000"); + request.getJDiscRequest().headers().add(Headers.CLIENT_ID, "client123"); + request.getJDiscRequest().headers().add(Headers.PRIORITY, "LOWEST"); + request.getJDiscRequest().headers().add(Headers.TRACE_LEVEL, "4"); + request.getJDiscRequest().headers().add(Headers.DRAIN, "true"); + return request; + } + + private FeedHandlerV3 setupFeederHandler(Executor threadPool) { + DocumentTypeManager docMan = new DocumentTypeManager(new DocumentmanagerConfig.Builder().enablecompression(true).build()); + FeedHandlerV3 feedHandlerV3 = new FeedHandlerV3( + threadPool, + metric, + docMan, + null /* session cache */, + new DocumentApiMetrics(MetricReceiver.nullImplementation, "test")) { + @Override + protected ReferencedResource<SharedSourceSession> retainSource( + SessionCache sessionCache, SourceSessionParams sessionParams) { + SharedSourceSession sharedSourceSession = mock(SharedSourceSession.class); + + try { + when(sharedSourceSession.sendMessageBlocking(any())).thenAnswer((Answer<?>) invocation -> { + Object[] args = invocation.getArguments(); + PutDocumentMessage putDocumentMessage = (PutDocumentMessage) args[0]; + ReplyContext replyContext = (ReplyContext) putDocumentMessage.getContext(); + replyContext.feedReplies.add(new OperationStatus("message", replyContext.docId, ErrorCode.OK, false, "trace")); + Result result = mock(Result.class); + when(result.isAccepted()).thenReturn(true); + return result; + }); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + Result result = mock(Result.class); + when(result.isAccepted()).thenReturn(true); + ReferencedResource<SharedSourceSession> refSharedSessopn = + new ReferencedResource<>(sharedSourceSession, () -> {}); + return refSharedSessopn; + } + }; + feedHandlerV3.injectDocumentManangerForTests(createDoctypeManager()); + return feedHandlerV3; + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedReaderFactoryTestCase.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedReaderFactoryTestCase.java new file mode 100644 index 00000000000..6b0bd1c9518 --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/FeedReaderFactoryTestCase.java @@ -0,0 +1,40 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.yahoo.document.DocumentTypeManager; +import com.yahoo.text.Utf8; +import com.yahoo.vespa.http.client.config.FeedParams; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class FeedReaderFactoryTestCase { + DocumentTypeManager manager = new DocumentTypeManager(); + + private InputStream createStream(String s) { + return new ByteArrayInputStream(Utf8.toBytes(s)); + } + + @Test + public void testXmlExceptionWithDebug() { + try { + new FeedReaderFactory(true).createReader(createStream("Some malformed xml"), manager, FeedParams.DataFormat.XML_UTF8); + fail(); + } catch (RuntimeException e) { + assertEquals("Could not create VespaXMLFeedReader. First characters are: 'Some malformed xml'", e.getMessage()); + } + } + @Test + public void testXmlException() { + try { + new FeedReaderFactory(false).createReader(createStream("Some malformed xml"), manager, FeedParams.DataFormat.XML_UTF8); + fail(); + } catch (RuntimeException e) { + assertEquals("Could not create VespaXMLFeedReader.", e.getMessage()); + } + } +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MetaStream.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MetaStream.java new file mode 100644 index 00000000000..4dce8cb4e7d --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MetaStream.java @@ -0,0 +1,39 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.yahoo.text.Utf8; + +import java.io.ByteArrayInputStream; + +/** + * Stream with extra data outside the actual input stream. + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public final class MetaStream extends ByteArrayInputStream { + + private byte[] operations; + int i; + + public MetaStream(byte[] buf) { + super(createPayload(buf)); + this.operations = buf; + i = 0; + } + + private static final byte[] createPayload(byte[] buf) { + StringBuilder bu = new StringBuilder(); + for (int i = 0; i < buf.length; i++) { + bu.append("id:banana:banana::doc1 0\n"); + } + return Utf8.toBytes(bu.toString()); + } + + public byte getNextOperation() { + if (i >= operations.length) { + return 0; + } + return operations[i++]; + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MockNetwork.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MockNetwork.java new file mode 100644 index 00000000000..7d3c0bb74ca --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MockNetwork.java @@ -0,0 +1,69 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import java.util.List; + +import com.yahoo.jrt.slobrok.api.IMirror; +import com.yahoo.messagebus.Message; +import com.yahoo.messagebus.network.Network; +import com.yahoo.messagebus.network.NetworkOwner; +import com.yahoo.messagebus.routing.RoutingNode; + +/** + * NOP-network. + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +class MockNetwork implements Network { + + @Override + public boolean waitUntilReady(double seconds) { + return true; + } + + @Override + public void attach(NetworkOwner owner) { + } + + @Override + public void registerSession(String session) { + } + + @Override + public void unregisterSession(String session) { + + } + + @Override + public boolean allocServiceAddress(RoutingNode recipient) { + return true; + } + + @Override + public void freeServiceAddress(RoutingNode recipient) { + + } + + @Override + public void send(Message msg, List<RoutingNode> recipients) { + } + + @Override + public void sync() { + } + + @Override + public void shutdown() { + } + + @Override + public String getConnectionSpec() { + return null; + } + + @Override + public IMirror getMirror() { + return null; + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MockReply.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MockReply.java new file mode 100644 index 00000000000..1cb00160bbd --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/MockReply.java @@ -0,0 +1,35 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.yahoo.messagebus.Reply; +import com.yahoo.text.Utf8String; + +/** + * Minimal reply simulator. + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +class MockReply extends Reply { + + Object context; + + public MockReply(Object context) { + this.context = context; + } + + @Override + public Utf8String getProtocol() { + return null; + } + + @Override + public int getType() { + return 0; + } + + @Override + public Object getContext() { + return context; + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/VersionsTestCase.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/VersionsTestCase.java new file mode 100644 index 00000000000..6858c4bede3 --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/VersionsTestCase.java @@ -0,0 +1,118 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server; + +import com.yahoo.collections.Tuple2; +import com.yahoo.container.jdisc.HttpResponse; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> + * @since 5.7.0 + */ +public class VersionsTestCase { + + private static final List<String> EMPTY = Collections.emptyList(); + private static final List<String> ONE_TWO = Arrays.asList("1", "2"); + private static final List<String> ONE_THREE = Arrays.asList("1", "3"); + private static final List<String> TWO_THREE = Arrays.asList("3", "2"); + private static final List<String> ONE_NULL_THREE = Arrays.asList("1", null, "3"); + private static final List<String> ONE_COMMA_THREE = Collections.singletonList("1, 3"); + private static final List<String> ONE_EMPTY_THREE = Arrays.asList("1", "", "3"); + private static final List<String> TOO_LARGE_NUMBER = Collections.singletonList("1000000000"); + private static final List<String> THREE_TOO_LARGE_NUMBER = Arrays.asList("3", "1000000000"); + private static final List<String> THREE_COMMA_TOO_LARGE_NUMBER = Arrays.asList("3,1000000000"); + private static final List<String> GARBAGE = Collections.singletonList("garbage"); + + @Test + public void testEmpty() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(EMPTY); + assertTrue(v.first instanceof ErrorHttpResponse); + assertEquals(Integer.valueOf(-1), v.second); + } + + @Test + public void testOneTwo() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(ONE_TWO); + assertTrue(v.first instanceof ErrorHttpResponse); + assertEquals(Integer.valueOf(-1), v.second); + } + + @Test + public void testOneThree() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(ONE_THREE); + assertNull(v.first); + assertEquals(Integer.valueOf(3), v.second); + } + + @Test + public void testTwoThree() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(TWO_THREE); + assertNull(v.first); + assertEquals(Integer.valueOf(3), v.second); + } + + @Test + public void testOneNullThree() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(ONE_NULL_THREE); + assertNull(v.first); + assertEquals(Integer.valueOf(3), v.second); + } + + @Test + public void testOneCommaThree() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(ONE_COMMA_THREE); + assertNull(v.first); + assertEquals(Integer.valueOf(3), v.second); + } + + @Test + public void testOneEmptyThree() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(ONE_EMPTY_THREE); + assertNull(v.first); + assertEquals(Integer.valueOf(3), v.second); + } + + @Test + public void testTooLarge() throws Exception { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(TOO_LARGE_NUMBER); + assertTrue(v.first instanceof ErrorHttpResponse); + ByteArrayOutputStream errorMsg = new ByteArrayOutputStream(); + ErrorHttpResponse errorResponse = (ErrorHttpResponse) v.first; + errorResponse.render(errorMsg); + assertEquals(errorMsg.toString(), + "Could not parse X-Yahoo-Feed-Protocol-Versionheader of request (values: [1000000000]). " + + "Server supports protocol versions [3]"); + assertEquals(Integer.valueOf(-1), v.second); + } + + @Test + public void testThreeTooLarge() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(THREE_TOO_LARGE_NUMBER); + assertNull(v.first); + assertEquals(Integer.valueOf(3), v.second); + } + + @Test + public void testTwoCommaTooLarge() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(THREE_COMMA_TOO_LARGE_NUMBER); + assertNull(v.first); + assertEquals(Integer.valueOf(3), v.second); + } + + @Test + public void testGarbage() { + Tuple2<HttpResponse, Integer> v = FeedHandler.doCheckProtocolVersion(GARBAGE); + assertTrue(v.first instanceof ErrorHttpResponse); + assertEquals(Integer.valueOf(-1), v.second); + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/util/ByteLimitedInputStreamTestCase.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/util/ByteLimitedInputStreamTestCase.java new file mode 100644 index 00000000000..ed571c6baff --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespa/http/server/util/ByteLimitedInputStreamTestCase.java @@ -0,0 +1,106 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.http.server.util; + +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> + * @since 5.1.23 + */ +public class ByteLimitedInputStreamTestCase { + + private static ByteLimitedInputStream create(byte[] source, int limit) { + if (limit > source.length) { + throw new IllegalArgumentException("Limit is greater than length of source buffer."); + } + InputStream wrappedStream = new ByteArrayInputStream(source); + return new ByteLimitedInputStream(wrappedStream, limit); + } + + @Test + public void requireThatBasicsWork() throws IOException { + ByteLimitedInputStream stream = create("abcdefghijklmnopqr".getBytes(StandardCharsets.US_ASCII), 9); + + assertEquals(9, stream.available()); + assertEquals(97, stream.read()); + assertEquals(8, stream.available()); + assertEquals(98, stream.read()); + assertEquals(7, stream.available()); + assertEquals(99, stream.read()); + assertEquals(6, stream.available()); + assertEquals(100, stream.read()); + assertEquals(5, stream.available()); + assertEquals(101, stream.read()); + assertEquals(4, stream.available()); + assertEquals(102, stream.read()); + assertEquals(3, stream.available()); + assertEquals(103, stream.read()); + assertEquals(2, stream.available()); + assertEquals(104, stream.read()); + assertEquals(1, stream.available()); + assertEquals(105, stream.read()); + assertEquals(0, stream.available()); + assertEquals(-1, stream.read()); + assertEquals(0, stream.available()); + assertEquals(-1, stream.read()); + assertEquals(0, stream.available()); + assertEquals(-1, stream.read()); + assertEquals(0, stream.available()); + assertEquals(-1, stream.read()); + assertEquals(0, stream.available()); + assertEquals(-1, stream.read()); + assertEquals(0, stream.available()); + } + + @Test + public void requireThatChunkedReadWorks() throws IOException { + ByteLimitedInputStream stream = create("abcdefghijklmnopqr".getBytes(StandardCharsets.US_ASCII), 9); + + assertEquals(9, stream.available()); + byte[] toBuf = new byte[4]; + assertEquals(4, stream.read(toBuf)); + assertEquals(97, toBuf[0]); + assertEquals(98, toBuf[1]); + assertEquals(99, toBuf[2]); + assertEquals(100, toBuf[3]); + assertEquals(5, stream.available()); + + assertEquals(4, stream.read(toBuf)); + assertEquals(101, toBuf[0]); + assertEquals(102, toBuf[1]); + assertEquals(103, toBuf[2]); + assertEquals(104, toBuf[3]); + assertEquals(1, stream.available()); + + assertEquals(1, stream.read(toBuf)); + assertEquals(105, toBuf[0]); + assertEquals(0, stream.available()); + + assertEquals(-1, stream.read(toBuf)); + assertEquals(0, stream.available()); + } + + @Test + public void requireMarkWorks() throws IOException { + InputStream stream = create("abcdefghijklmnopqr".getBytes(StandardCharsets.US_ASCII), 9); + assertEquals(97, stream.read()); + assertTrue(stream.markSupported()); + stream.mark(5); + assertEquals(98, stream.read()); + assertEquals(99, stream.read()); + stream.reset(); + assertEquals(98, stream.read()); + assertEquals(99, stream.read()); + assertEquals(100, stream.read()); + assertEquals(101, stream.read()); + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespaxmlparser/MockFeedReaderFactory.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespaxmlparser/MockFeedReaderFactory.java new file mode 100644 index 00000000000..513892af213 --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespaxmlparser/MockFeedReaderFactory.java @@ -0,0 +1,32 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespaxmlparser; + +import com.yahoo.document.DocumentTypeManager; +import com.yahoo.vespa.http.client.config.FeedParams; +import com.yahoo.vespa.http.server.FeedReaderFactory; + +import java.io.InputStream; + +/** + * For creating MockReader of innput stream. + * @author dybis + */ +public class MockFeedReaderFactory extends FeedReaderFactory { + + public MockFeedReaderFactory() { + super(true); + } + + @Override + public FeedReader createReader( + InputStream inputStream, + DocumentTypeManager docTypeManager, + FeedParams.DataFormat dataFormat) { + try { + return new MockReader(inputStream); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/vespaxmlparser/MockReader.java b/vespaclient-container-plugin/src/test/java/com/yahoo/vespaxmlparser/MockReader.java new file mode 100644 index 00000000000..c751849b84e --- /dev/null +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/vespaxmlparser/MockReader.java @@ -0,0 +1,69 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespaxmlparser; + +import com.yahoo.document.Document; +import com.yahoo.document.DocumentId; +import com.yahoo.document.DocumentType; +import com.yahoo.document.DocumentUpdate; +import com.yahoo.vespa.http.server.MetaStream; +import com.yahoo.vespa.http.server.util.ByteLimitedInputStream; + +import java.io.InputStream; +import java.lang.reflect.Field; + +/** + * Mock for ExternalFeedTestCase which had to override package private methods. + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class MockReader implements FeedReader { + + MetaStream stream; + boolean finished = false; + + public MockReader(InputStream stream) throws Exception { + this.stream = getMetaStream(stream); + } + + private static MetaStream getMetaStream(InputStream stream) { + if (stream instanceof MetaStream) { + return (MetaStream) stream; + } + if (!(stream instanceof ByteLimitedInputStream)) { + throw new IllegalStateException("Given unknown stream type."); + } + //Ooooooo this is so ugly + try { + ByteLimitedInputStream byteLimitedInputStream = (ByteLimitedInputStream) stream; + Field f = byteLimitedInputStream.getClass().getDeclaredField("wrappedStream"); //NoSuchFieldException + f.setAccessible(true); + return (MetaStream) f.get(byteLimitedInputStream); + } catch (Exception e) { + throw new IllegalStateException("Implementation of ByteLimitedInputStream has changed.", e); + } + } + + @Override + public FeedOperation read() throws Exception { + if (finished) { + return FeedOperation.INVALID; + } + + byte whatToDo = stream.getNextOperation(); + DocumentId id = new DocumentId("id:banana:banana::doc1"); + DocumentType docType = new DocumentType("banana"); + switch (whatToDo) { + case 0: + return FeedOperation.INVALID; + case 1: + return new DocumentFeedOperation(new Document(docType, id)); + case 2: + return new RemoveFeedOperation(id); + case 3: + return new DocumentUpdateFeedOperation(new DocumentUpdate(docType, id)); + default: + throw new RuntimeException("boom"); + } + } + +} |