/** * Copyright 2016 StreamSets Inc. * * Licensed under the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 com.streamsets.pipeline.lib.sdcipc; import com.streamsets.pipeline.api.Field; import com.streamsets.pipeline.api.OnRecordError; import com.streamsets.pipeline.api.Record; import com.streamsets.pipeline.api.Source; import com.streamsets.pipeline.api.ext.ContextExtensions; import com.streamsets.pipeline.api.ext.RecordReader; import com.streamsets.pipeline.api.ext.RecordWriter; import com.streamsets.pipeline.lib.http.HttpRequestFragmenter; import com.streamsets.pipeline.sdk.ContextInfoCreator; import com.streamsets.pipeline.sdk.RecordCreator; import org.apache.commons.io.output.ByteArrayOutputStream; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class TestSdcIpcRequestFragmenter { @Test public void testValidate() throws IOException { HttpRequestFragmenter fragmenter = new SdcIpcRequestFragmenter(); fragmenter.init(null); HttpServletRequest req = Mockito.mock(HttpServletRequest.class); HttpServletResponse res = Mockito.mock(HttpServletResponse.class); Assert.assertFalse(fragmenter.validate(req,res)); Mockito.verify(res).sendError(Mockito.eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), Mockito.anyString()); Mockito.reset(res); Mockito.when(req.getContentType()).thenReturn("foo"); Assert.assertFalse(fragmenter.validate(req,res)); Mockito.verify(res).sendError(Mockito.eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), Mockito.anyString()); Mockito.reset(res); Mockito.when(req.getContentType()).thenReturn("APPLICATION/BINARY"); Assert.assertFalse(fragmenter.validate(req,res)); Mockito.verify(res).sendError(Mockito.eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), Mockito.anyString()); Mockito.reset(res); Mockito.when(req.getHeader(Mockito.eq("X-SDC-JSON1-FRAGMENTABLE"))).thenReturn("TRUE"); Assert.assertTrue(fragmenter.validate(req,res)); fragmenter.destroy(); } @Test public void testCopy() throws IOException { // empty IS InputStream is = new ByteArrayInputStream(new byte[0]); ByteArrayOutputStream baos = new ByteArrayOutputStream(); Assert.assertTrue(SdcIpcRequestFragmenter.copy(is, baos, 1)); Assert.assertEquals(0, baos.size()); // IS size + 1 == limit is = new ByteArrayInputStream(new byte[10]); baos = new ByteArrayOutputStream(); Assert.assertTrue(SdcIpcRequestFragmenter.copy(is, baos, 11)); Assert.assertEquals(10, baos.size()); // IS size == limit is = new ByteArrayInputStream(new byte[10]); baos = new ByteArrayOutputStream(); Assert.assertFalse(SdcIpcRequestFragmenter.copy(is, baos, 10)); Assert.assertEquals(10, baos.size()); Assert.assertTrue(SdcIpcRequestFragmenter.copy(is, baos, 1)); Assert.assertEquals(10, baos.size()); // IS size > limit is = new ByteArrayInputStream(new byte[15]); baos = new ByteArrayOutputStream(); Assert.assertFalse(SdcIpcRequestFragmenter.copy(is, baos, 10)); Assert.assertEquals(10, baos.size()); Assert.assertTrue(SdcIpcRequestFragmenter.copy(is, baos, 10)); Assert.assertEquals(15, baos.size()); // verify copy fidelity byte[] arr = new byte[15]; for (int i = 0; i < arr.length; i++) { arr[i] = (byte) i; } is = new ByteArrayInputStream(arr); baos = new ByteArrayOutputStream(); Assert.assertFalse(SdcIpcRequestFragmenter.copy(is, baos, 10)); Assert.assertEquals(10, baos.size()); Assert.assertTrue(SdcIpcRequestFragmenter.copy(is, baos, 10)); Assert.assertEquals(15, baos.size()); Assert.assertArrayEquals(arr, baos.toByteArray()); } @Test public void testFindEndOfLastLineBeforeLimit() throws IOException { // empty array byte[] arr = new byte[0]; Assert.assertEquals(-1, SdcIpcRequestFragmenter.findEndOfLastLineBeforeLimit(arr, 0)); // no EOL arr = new byte[]{0, 1, 2}; Assert.assertEquals(-1, SdcIpcRequestFragmenter.findEndOfLastLineBeforeLimit(arr, 3)); // EOL arr = new byte[]{0, '\n', 2}; Assert.assertEquals(2, SdcIpcRequestFragmenter.findEndOfLastLineBeforeLimit(arr, 3)); } @Test public void testFragmentToFragmentInternal() throws Exception { SdcIpcRequestFragmenter fragmenter = new SdcIpcRequestFragmenter(); fragmenter = Mockito.spy(fragmenter); List<byte[]> list = new ArrayList<>(); Mockito .doReturn(list) .when(fragmenter) .fragmentInternal(Mockito.any(InputStream.class), Mockito.anyInt(), Mockito.anyInt()); InputStream is = Mockito.mock(InputStream.class); fragmenter.init(null); Assert.assertEquals(list, fragmenter.fragment(is, 1, 2)); Mockito.verify(fragmenter, Mockito.times(1)).fragmentInternal(Mockito.eq(is), Mockito.eq(1000), Mockito.eq(2000)); fragmenter.destroy(); } @Test public void testExtract() throws IOException { // empty input InputStream is = new ByteArrayInputStream(new byte[0]); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] arr = SdcIpcRequestFragmenter.extract(is, baos, 5); Assert.assertNull(arr); Assert.assertEquals(0, baos.size()); // input size < limit is = new ByteArrayInputStream(new byte[]{1, 2, '\n'}); baos = new ByteArrayOutputStream(); arr = SdcIpcRequestFragmenter.extract(is, baos, 5); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, '\n'}, arr); Assert.assertEquals(0, baos.size()); // input size == limit, EOL at EOF is = new ByteArrayInputStream(new byte[]{1, 2, 3, 4, '\n'}); baos = new ByteArrayOutputStream(); arr = SdcIpcRequestFragmenter.extract(is, baos, 5); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, 3, 4, '\n'}, arr); Assert.assertEquals(0, baos.size()); // input size == limit, EOL before EOF is = new ByteArrayInputStream(new byte[]{1, 2, '\n', 4, 5}); baos = new ByteArrayOutputStream(); arr = SdcIpcRequestFragmenter.extract(is, baos, 5); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, '\n'}, arr); Assert.assertArrayEquals(new byte[]{4, 5}, baos.toByteArray()); // input size > limit is = new ByteArrayInputStream(new byte[]{1, 2, '\n', 4, 5, '\n'}); baos = new ByteArrayOutputStream(); arr = SdcIpcRequestFragmenter.extract(is, baos, 5); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, '\n'}, arr); Assert.assertArrayEquals(new byte[]{4, 5}, baos.toByteArray()); arr = SdcIpcRequestFragmenter.extract(is, baos, 5); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 4, 5, '\n'}, arr); Assert.assertEquals(0, baos.size()); } @Test(expected = IOException.class) public void testExtractMessageExceededLimit() throws IOException { InputStream is = new ByteArrayInputStream(new byte[]{1, 2, 3, 4, 5, '\n'}); ByteArrayOutputStream baos = new ByteArrayOutputStream(); SdcIpcRequestFragmenter.extract(is, baos, 5); } @Test(expected = IOException.class) public void testFragmentEmptyInput() throws IOException { InputStream is = new ByteArrayInputStream(new byte[]{}); new SdcIpcRequestFragmenter().fragmentInternal(is, 5, 100); } @Test(expected = IOException.class) public void testFragmentWrongMagicByte() throws IOException { InputStream is = new ByteArrayInputStream(new byte[]{1}); new SdcIpcRequestFragmenter().fragmentInternal(is, 5, 100); } @Test(expected = IOException.class) public void testFragmentDataSizeExceeded() throws IOException { InputStream is = new ByteArrayInputStream(new byte[]{ SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, 3, '\n', 1, 2, 3, 4, '\n', 1, 2, 3 }); new SdcIpcRequestFragmenter().fragmentInternal(is, 6, 10); } @Test public void testfragmentInternal() throws IOException { InputStream is = new ByteArrayInputStream(new byte[]{ SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, '\n', 1, 2, 3, '\n', 1, 2, 3, '\n', 1, 2, '\n' }); List<byte[]> fragments = new SdcIpcRequestFragmenter().fragmentInternal(is, 6, 100); Assert.assertEquals(4, fragments.size()); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, '\n'}, fragments.get(0)); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, 3, '\n'}, fragments.get(1)); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, 3, '\n',}, fragments.get(2)); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, '\n'}, fragments.get(3)); is = new ByteArrayInputStream(new byte[]{ SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, '\n', 1, 2, '\n', 1, 2, '\n', 1, '\n' }); fragments = new SdcIpcRequestFragmenter().fragmentInternal(is, 8, 100); Assert.assertEquals(2, fragments.size()); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, '\n', 1, 2, '\n'}, fragments.get(0)); Assert.assertArrayEquals(new byte[]{SdcIpcRequestFragmenter.JSON1_MAGIC_NUMBER, 1, 2, '\n', 1, '\n'}, fragments.get(1)); } @Test public void testFragmentWithSDCData() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); Source.Context context = ContextInfoCreator.createSourceContext("foo", false, OnRecordError.TO_ERROR, Arrays.asList("a")); ContextExtensions ext = (ContextExtensions) context; RecordWriter rw = ext.createRecordWriter(baos); Record r1 = RecordCreator.create(); r1.set(Field.create(true)); Record r2 = RecordCreator.create(); r2.set(Field.create(1)); Record r3 = RecordCreator.create(); r3.set(Field.create("a")); List<Record> records = Arrays.asList(r1, r2 , r3); for (Record record : records) { rw.write(record); } rw.close(); List<byte[]> fragments = new SdcIpcRequestFragmenter().fragmentInternal(new ByteArrayInputStream(baos.toByteArray()), 800, 2000); Assert.assertEquals(2, fragments.size()); List<Record> got = new ArrayList<>(); for (byte[] fragment : fragments) { InputStream is = new ByteArrayInputStream(fragment); RecordReader rr = ext.createRecordReader(is, 0, 500); Record r = rr.readRecord(); while (r != null) { got.add(r); r = rr.readRecord(); } rr.close(); } Assert.assertEquals(records, got); } }