Index: C:/Documents and Settings/alf.hogemark/workspace/Jmeter 2.2/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java =================================================================== --- C:/Documents and Settings/alf.hogemark/workspace/Jmeter 2.2/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java (revision 0) +++ C:/Documents and Settings/alf.hogemark/workspace/Jmeter 2.2/test/src/org/apache/jmeter/protocol/http/sampler/TestHTTPSamplersAgainstHttpMirrorServer.java (revision 0) @@ -0,0 +1,514 @@ +/* + * Licensed to 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 org.apache.jmeter.protocol.http.sampler; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.Locale; + +import org.apache.jmeter.config.Arguments; +import org.apache.jmeter.engine.util.ValueReplacer; +import org.apache.jmeter.protocol.http.control.HttpMirrorControl; +import org.apache.jmeter.protocol.http.util.HTTPArgument; +import org.apache.jmeter.testelement.TestPlan; +import org.apache.jmeter.threads.JMeterContextService; +import org.apache.jmeter.threads.JMeterVariables; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.oro.text.regex.MatchResult; +import org.apache.oro.text.regex.Pattern; +import org.apache.oro.text.regex.PatternMatcherInput; +import org.apache.oro.text.regex.Perl5Compiler; +import org.apache.oro.text.regex.Perl5Matcher; + +import junit.framework.TestCase; + +/** + * Class for performing actual samples for HTTPSampler and HTTPSampler2. + * The samples are executed against the HttpMirrorServer, which is + * started when the unit tests are executed. + */ +public class TestHTTPSamplersAgainstHttpMirrorServer extends TestCase { + private final static int HTTP_SAMPLER = 0; + private final static int HTTP_SAMPLER2 = 1; + private HttpMirrorControl webServerControl; + private int webServerPort = 8080; + + public TestHTTPSamplersAgainstHttpMirrorServer(String arg0) { + super(arg0); + } + protected void setUp() throws Exception { + webServerControl = new HttpMirrorControl(); + webServerControl.setPort(webServerPort); + webServerControl.startHttpMirror(); + } + + protected void tearDown() throws Exception { + // Shutdown web server + webServerControl.stopHttpMirror(); + webServerControl = null; + } + + public void testPostRequest_UrlEncoded() throws Exception { + // Test HTTPSampler + String samplerDefaultEncoding = "ISO-8859-1".toLowerCase(); + testPostRequest_UrlEncoded(HTTP_SAMPLER, samplerDefaultEncoding); + + // Test HTTPSampler2 + samplerDefaultEncoding = "US-ASCII"; + testPostRequest_UrlEncoded(HTTP_SAMPLER2, samplerDefaultEncoding); + } + + public void testPostRequest_FormMultipart() throws Exception { + // Test HTTPSampler + String samplerDefaultEncoding = "ISO-8859-1".toLowerCase(); + testPostRequest_FormMultipart(HTTP_SAMPLER, samplerDefaultEncoding); + + // Test HTTPSampler2 + samplerDefaultEncoding = "US-ASCII"; + testPostRequest_FormMultipart(HTTP_SAMPLER2, samplerDefaultEncoding); + } + + private void testPostRequest_UrlEncoded(int samplerType, String samplerDefaultEncoding) throws Exception { + String titleField = "title"; + String titleValue = "mytitle"; + String descriptionField = "description"; + String descriptionValue = "mydescription"; + + // Test sending data with default encoding + HTTPSamplerBase sampler = createHttpSampler(samplerType); + String contentEncoding = ""; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + HTTPSampleResult res = executeSampler(sampler); + checkPostRequestUrlEncoded(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, titleValue, descriptionField, descriptionValue); + + // Test sending data as ISO-8859-1 + sampler = createHttpSampler(samplerType); + contentEncoding = "ISO-8859-1"; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + res = executeSampler(sampler); + checkPostRequestUrlEncoded(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, titleValue, descriptionField, descriptionValue); + + // Test sending data as UTF-8 + sampler = createHttpSampler(samplerType); + contentEncoding = "UTF-8"; + titleValue = "mytitle\u0153\u20a1\u0115\u00c5"; + descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5"; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + res = executeSampler(sampler); + checkPostRequestUrlEncoded(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, titleValue, descriptionField, descriptionValue); + + // Test sending data as UTF-8, where user defined variables are used + // to set the value for form data + JMeterUtils.setLocale(Locale.ENGLISH); + TestPlan testPlan = new TestPlan(); + JMeterVariables vars = new JMeterVariables(); + vars.put("title_prefix", "a test\u00c5"); + vars.put("description_suffix", "the_end"); + JMeterContextService.getContext().setVariables(vars); + JMeterContextService.getContext().setSamplingStarted(true); + ValueReplacer replacer = new ValueReplacer(); + replacer.setUserDefinedVariables(testPlan.getUserDefinedVariables()); + + sampler = createHttpSampler(samplerType); + contentEncoding = "UTF-8"; + titleValue = "${title_prefix}mytitle\u0153\u20a1\u0115\u00c5"; + descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5${description_suffix}"; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + // Replace the variables in the sampler + replacer.replaceValues(sampler); + res = executeSampler(sampler); + String expectedTitleValue = "a test\u00c5mytitle\u0153\u20a1\u0115\u00c5"; + String expectedDescriptionValue = "mydescription\u0153\u20a1\u0115\u00c5the_end"; + checkPostRequestUrlEncoded(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, expectedTitleValue, descriptionField, expectedDescriptionValue); + } + + private void testPostRequest_FormMultipart(int samplerType, String samplerDefaultEncoding) throws Exception { + String titleField = "title"; + String titleValue = "mytitle"; + String descriptionField = "description"; + String descriptionValue = "mydescription"; + + // Test sending data with default encoding + HTTPSamplerBase sampler = createHttpSampler(samplerType); + String contentEncoding = ""; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + sampler.setDoMultipartPost(true); + HTTPSampleResult res = executeSampler(sampler); + checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, titleValue, descriptionField, descriptionValue); + + // Test sending data as ISO-8859-1 + sampler = createHttpSampler(samplerType); + contentEncoding = "ISO-8859-1"; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + sampler.setDoMultipartPost(true); + res = executeSampler(sampler); + checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, titleValue, descriptionField, descriptionValue); + + // Test sending data as UTF-8 + sampler = createHttpSampler(samplerType); + contentEncoding = "UTF-8"; + titleValue = "mytitle\u0153\u20a1\u0115\u00c5"; + descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5"; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + sampler.setDoMultipartPost(true); + res = executeSampler(sampler); + checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, titleValue, descriptionField, descriptionValue); + + // Test sending data as UTF-8, with values that would have been urlencoded + // if it was not sent as multipart + sampler = createHttpSampler(samplerType); + contentEncoding = "UTF-8"; + titleValue = "mytitle\u0153+\u20a1 \u0115&yes\u00c5"; + descriptionValue = "mydescription \u0153 \u20a1 \u0115 \u00c5"; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + sampler.setDoMultipartPost(true); + res = executeSampler(sampler); + checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, titleValue, descriptionField, descriptionValue); + + // Test sending data as UTF-8, where user defined variables are used + // to set the value for form data + JMeterUtils.setLocale(Locale.ENGLISH); + TestPlan testPlan = new TestPlan(); + JMeterVariables vars = new JMeterVariables(); + vars.put("title_prefix", "a test\u00c5"); + vars.put("description_suffix", "the_end"); + JMeterContextService.getContext().setVariables(vars); + JMeterContextService.getContext().setSamplingStarted(true); + ValueReplacer replacer = new ValueReplacer(); + replacer.setUserDefinedVariables(testPlan.getUserDefinedVariables()); + + sampler = createHttpSampler(samplerType); + contentEncoding = "UTF-8"; + titleValue = "${title_prefix}mytitle\u0153\u20a1\u0115\u00c5"; + descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5${description_suffix}"; + setupUrl(sampler, contentEncoding); + setupFormData(sampler, false, titleField, titleValue, descriptionField, descriptionValue); + sampler.setDoMultipartPost(true); + // Replace the variables in the sampler + replacer.replaceValues(sampler); + res = executeSampler(sampler); + String expectedTitleValue = "a test\u00c5mytitle\u0153\u20a1\u0115\u00c5"; + String expectedDescriptionValue = "mydescription\u0153\u20a1\u0115\u00c5the_end"; + checkPostRequestFormMultipart(sampler, res, samplerDefaultEncoding, contentEncoding, titleField, expectedTitleValue, descriptionField, expectedDescriptionValue); + } + + private HTTPSampleResult executeSampler(HTTPSamplerBase sampler) { + sampler.setRunningVersion(true); + sampler.threadStarted(); + HTTPSampleResult res = (HTTPSampleResult) sampler.sample(); + sampler.threadFinished(); + sampler.setRunningVersion(false); + return res; + } + + private void checkPostRequestUrlEncoded( + HTTPSamplerBase sampler, + HTTPSampleResult res, + String samplerDefaultEncoding, + String contentEncoding, + String titleField, + String titleValue, + String descriptionField, + String descriptionValue) throws IOException { + if(contentEncoding == null || contentEncoding.length() == 0) { + contentEncoding = samplerDefaultEncoding; + } + // Check URL + assertEquals(sampler.getUrl(), res.getURL()); + String expectedPostBody = titleField + "=" + URLEncoder.encode(titleValue, contentEncoding) + "&" + descriptionField + "=" + URLEncoder.encode(descriptionValue, contentEncoding); + // Check request headers + assertTrue(isInRequestHeaders(res.getRequestHeaders(), HTTPSamplerBase.HEADER_CONTENT_TYPE, HTTPSamplerBase.APPLICATION_X_WWW_FORM_URLENCODED)); + assertTrue( + isInRequestHeaders( + res.getRequestHeaders(), + HTTPSamplerBase.HEADER_CONTENT_LENGTH, + Integer.toString(expectedPostBody.getBytes(contentEncoding).length) + ) + ); + // Check post body from the result query string + checkArraysHaveSameContent(expectedPostBody.getBytes(contentEncoding), res.getQueryString().getBytes(contentEncoding)); + + // Find the data sent to the mirror server, which the mirror server is sending back to us + String dataSentToMirrorServer = new String(res.getResponseData(), contentEncoding); + int posDividerHeadersAndBody = getPositionOfBody(dataSentToMirrorServer); + String headersSent = null; + String bodySent = null; + if(posDividerHeadersAndBody >= 0) { + headersSent = dataSentToMirrorServer.substring(0, posDividerHeadersAndBody); + // Skip the blank line with crlf dividing headers and body + bodySent = dataSentToMirrorServer.substring(posDividerHeadersAndBody+2); + } + // Check response headers + assertTrue(isInRequestHeaders(headersSent, HTTPSamplerBase.HEADER_CONTENT_TYPE, HTTPSamplerBase.APPLICATION_X_WWW_FORM_URLENCODED)); + assertTrue( + isInRequestHeaders( + headersSent, + HTTPSamplerBase.HEADER_CONTENT_LENGTH, + Integer.toString(expectedPostBody.getBytes(contentEncoding).length) + ) + ); + // Check post body which was sent to the mirror server, and + // sent back by the mirror server + checkArraysHaveSameContent(expectedPostBody.getBytes(contentEncoding), bodySent.getBytes(contentEncoding)); + } + + private void checkPostRequestFormMultipart( + HTTPSamplerBase sampler, + HTTPSampleResult res, + String samplerDefaultEncoding, + String contentEncoding, + String titleField, + String titleValue, + String descriptionField, + String descriptionValue) throws IOException { + if(contentEncoding == null || contentEncoding.length() == 0) { + contentEncoding = samplerDefaultEncoding; + } + // Check URL + assertEquals(sampler.getUrl(), res.getURL()); + String boundaryString = getBoundaryStringFromContentType(res.getRequestHeaders()); + assertNotNull(boundaryString); + byte[] expectedPostBody = createExpectedFormdataOutput(boundaryString, contentEncoding, titleField, titleValue, descriptionField, descriptionValue, true, true); + // Check request headers + assertTrue(isInRequestHeaders(res.getRequestHeaders(), HTTPSamplerBase.HEADER_CONTENT_TYPE, HTTPSamplerBase.MULTIPART_FORM_DATA + "; boundary=" + boundaryString)); + assertTrue( + isInRequestHeaders( + res.getRequestHeaders(), + HTTPSamplerBase.HEADER_CONTENT_LENGTH, + Integer.toString(expectedPostBody.length) + ) + ); + // Check post body from the result query string + checkArraysHaveSameContent(expectedPostBody, res.getQueryString().getBytes(contentEncoding)); + + // Find the data sent to the mirror server, which the mirror server is sending back to us + String dataSentToMirrorServer = new String(res.getResponseData(), contentEncoding); + int posDividerHeadersAndBody = getPositionOfBody(dataSentToMirrorServer); + String headersSent = null; + String bodySent = null; + if(posDividerHeadersAndBody >= 0) { + headersSent = dataSentToMirrorServer.substring(0, posDividerHeadersAndBody); + // Skip the blank line with crlf dividing headers and body + bodySent = dataSentToMirrorServer.substring(posDividerHeadersAndBody+2); + } + // Check response headers + assertTrue(isInRequestHeaders(headersSent, HTTPSamplerBase.HEADER_CONTENT_TYPE, HTTPSamplerBase.MULTIPART_FORM_DATA + "; boundary=" + boundaryString)); + assertTrue( + isInRequestHeaders( + headersSent, + HTTPSamplerBase.HEADER_CONTENT_LENGTH, + Integer.toString(expectedPostBody.length) + ) + ); + // Check post body which was sent to the mirror server, and + // sent back by the mirror server + checkArraysHaveSameContent(expectedPostBody, bodySent.getBytes(contentEncoding)); + } + + private boolean isInRequestHeaders(String requestHeaders, String headerName, String headerValue) { + return checkRegularExpression(requestHeaders, headerName + ": " + headerValue); + } + + private boolean checkRegularExpression(String stringToCheck, String regularExpression) { + Perl5Matcher localMatcher = JMeterUtils.getMatcher(); + Pattern pattern = JMeterUtils.getPattern(regularExpression, Perl5Compiler.READ_ONLY_MASK | Perl5Compiler.CASE_INSENSITIVE_MASK | Perl5Compiler.SINGLELINE_MASK); + return localMatcher.contains(stringToCheck, pattern); + } + + private int getPositionOfBody(String stringToCheck) { + Perl5Matcher localMatcher = JMeterUtils.getMatcher(); + // The headers and body are divided by a blank line + String regularExpression = "^.$"; + Pattern pattern = JMeterUtils.getPattern(regularExpression, Perl5Compiler.READ_ONLY_MASK | Perl5Compiler.CASE_INSENSITIVE_MASK | Perl5Compiler.MULTILINE_MASK); + + PatternMatcherInput input = new PatternMatcherInput(stringToCheck); + while(localMatcher.contains(input, pattern)) { + MatchResult match = localMatcher.getMatch(); + return match.beginOffset(0); + } + // No divider was found + return -1; + } + + private String getBoundaryStringFromContentType(String requestHeaders) { + Perl5Matcher localMatcher = JMeterUtils.getMatcher(); + String regularExpression = "^" + HTTPSamplerBase.HEADER_CONTENT_TYPE + ": multipart/form-data; boundary=(.+)$"; + Pattern pattern = JMeterUtils.getPattern(regularExpression, Perl5Compiler.READ_ONLY_MASK | Perl5Compiler.CASE_INSENSITIVE_MASK | Perl5Compiler.MULTILINE_MASK); + if(localMatcher.contains(requestHeaders, pattern)) { + MatchResult match = localMatcher.getMatch(); + return match.group(1); + } + else { + return null; + } + } + + private void setupUrl(HTTPSamplerBase sampler, String contentEncoding) { + String protocol = "http"; + // String domain = "localhost"; + String domain = "localhost"; + String path = "/test/somescript.jsp"; + int port = 8080; + sampler.setProtocol(protocol); + sampler.setMethod(HTTPSamplerBase.POST); + sampler.setPath(path); + sampler.setDomain(domain); + sampler.setPort(port); + sampler.setContentEncoding(contentEncoding); + } + + /** + * Setup the form data with specified values + * + * @param httpSampler + */ + private void setupFormData(HTTPSamplerBase httpSampler, boolean isEncoded, String titleField, String titleValue, String descriptionField, String descriptionValue) { + Arguments args = new Arguments(); + HTTPArgument argument1 = new HTTPArgument(titleField, titleValue, isEncoded); + HTTPArgument argument2 = new HTTPArgument(descriptionField, descriptionValue, isEncoded); + args.addArgument(argument1); + args.addArgument(argument2); + httpSampler.setArguments(args); + } + + /** + * Check that the the two byte arrays have identical content + * + * @param expected + * @param actual + */ + private void checkArraysHaveSameContent(byte[] expected, byte[] actual) { + if(expected != null && actual != null) { + if(expected.length != actual.length) { + fail("arrays have different length, expected is " + expected.length + ", actual is " + actual.length); + } + else { + for(int i = 0; i < expected.length; i++) { + if(expected[i] != actual[i]) { + fail("byte at position " + i + " is different, expected is " + expected[i] + ", actual is " + actual[i]); + } + } + } + } + else { + fail("expected or actual byte arrays were null"); + } + } + + /** + * Create the expected output multipart/form-data, with only form data, + * and no file multipart. + * This method is copied from the PostWriterTest class + * + * @param lastMultipart true if this is the last multipart in the request + */ + private byte[] createExpectedFormdataOutput( + String boundaryString, + String contentEncoding, + String titleField, + String titleValue, + String descriptionField, + String descriptionValue, + boolean firstMultipart, + boolean lastMultipart) throws IOException { + // The encoding used for http headers and control information + final String httpEncoding = "ISO-8859-1"; + final byte[] CRLF = { 0x0d, 0x0A }; + final byte[] DASH_DASH = new String("--").getBytes(httpEncoding); + + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + if(firstMultipart) { + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); + output.write(CRLF); + } + output.write("Content-Disposition: form-data; name=\"".getBytes(httpEncoding)); + output.write(titleField.getBytes(httpEncoding)); + output.write("\"".getBytes(httpEncoding)); + output.write(CRLF); + output.write("Content-Type: text/plain".getBytes(httpEncoding)); + if(contentEncoding != null) { + output.write("; charset=".getBytes(httpEncoding)); + output.write(contentEncoding.getBytes(httpEncoding)); + } + output.write(CRLF); + output.write("Content-Transfer-Encoding: 8bit".getBytes(httpEncoding)); + output.write(CRLF); + output.write(CRLF); + if(contentEncoding != null) { + output.write(titleValue.getBytes(contentEncoding)); + } + else { + output.write(titleValue.getBytes()); + } + output.write(CRLF); + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); + output.write(CRLF); + output.write("Content-Disposition: form-data; name=\"".getBytes(httpEncoding)); + output.write(descriptionField.getBytes(httpEncoding)); + output.write("\"".getBytes(httpEncoding)); + output.write(CRLF); + output.write("Content-Type: text/plain".getBytes(httpEncoding)); + if(contentEncoding != null) { + output.write("; charset=".getBytes(httpEncoding)); + output.write(contentEncoding.getBytes(httpEncoding)); + } + output.write(CRLF); + output.write("Content-Transfer-Encoding: 8bit".getBytes(httpEncoding)); + output.write(CRLF); + output.write(CRLF); + if(contentEncoding != null) { + output.write(descriptionValue.getBytes(contentEncoding)); + } + else { + output.write(descriptionValue.getBytes()); + } + output.write(CRLF); + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); + if(lastMultipart) { + output.write(DASH_DASH); + } + output.write(CRLF); + + output.flush(); + output.close(); + + return output.toByteArray(); + } + + private HTTPSamplerBase createHttpSampler(int samplerType) { + if(samplerType == HTTP_SAMPLER2) { + return new HTTPSampler2(); + } + else { + return new HTTPSampler(); + } + } +} Index: C:/Documents and Settings/alf.hogemark/workspace/Jmeter 2.2/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java =================================================================== --- C:/Documents and Settings/alf.hogemark/workspace/Jmeter 2.2/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java (revision 523999) +++ C:/Documents and Settings/alf.hogemark/workspace/Jmeter 2.2/test/src/org/apache/jmeter/protocol/http/sampler/PostWriterTest.java (working copy) @@ -26,7 +26,8 @@ import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; -import java.net.URLConnection; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; @@ -38,20 +39,25 @@ public class PostWriterTest extends TestCase { private final static byte[] CRLF = { 0x0d, 0x0A }; + private static byte[] TEST_FILE_CONTENT; - private URLConnection connection; + private StubURLConnection connection; private HTTPSampler sampler; private File temporaryFile; + private PostWriter postWriter; protected void setUp() throws Exception { - connection = new StubURLConnection("http://fake_url/test"); + establishConnection(); sampler = new HTTPSampler();// This must be the original (Java) HTTP sampler + // Create the test file content + TEST_FILE_CONTENT = new String("foo content &?=01234+56789-\u007c\u2aa1\u266a\u0153\u20a1\u0115\u0364\u00c5\u2052").getBytes("UTF-8"); + // create a temporary file to make sure we always have a file to give to the PostWriter // Whereever we are or Whatever the current path is. temporaryFile = File.createTempFile("foo", "txt"); OutputStream output = new FileOutputStream(temporaryFile); - output.write("foo content".getBytes()); + output.write(TEST_FILE_CONTENT); output.flush(); output.close(); } @@ -63,38 +69,462 @@ /* * Test method for 'org.apache.jmeter.protocol.http.sampler.PostWriter.sendPostData(URLConnection, HTTPSampler)' + * This method test sending a request which contains both formdata and file content */ public void testSendPostData() throws IOException { - setupFilename(sampler); - setupCommons(sampler); + setupFilepart(sampler); + String titleValue = "mytitle"; + String descriptionValue = "mydescription"; + setupFormData(sampler, titleValue, descriptionValue); - PostWriter.sendPostData(connection, sampler); + // Test sending data with default encoding + String contentEncoding = ""; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + byte[] expectedFormBody = createExpectedOutput(postWriter.getBoundary(), "iso-8859-1", titleValue, descriptionValue, TEST_FILE_CONTENT); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as ISO-8859-1 + establishConnection(); + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedOutput(postWriter.getBoundary(), contentEncoding, titleValue, descriptionValue, TEST_FILE_CONTENT); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); - assertEquals(createExpectedOutputStream().toString(), connection.getOutputStream().toString()); + // Test sending data as UTF-8 + establishConnection(); + titleValue = "mytitle\u0153\u20a1\u0115\u00c5"; + descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5"; + contentEncoding = "UTF-8"; + sampler.setContentEncoding(contentEncoding); + setupFormData(sampler, titleValue, descriptionValue); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedOutput(postWriter.getBoundary(), contentEncoding, titleValue, descriptionValue, TEST_FILE_CONTENT); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending UTF-8 data with ISO-8859-1 content encoding + establishConnection(); + contentEncoding = "UTF-8"; + sampler.setContentEncoding("ISO-8859-1"); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedOutput(postWriter.getBoundary(), contentEncoding, titleValue, descriptionValue, TEST_FILE_CONTENT); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveDifferentContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); } /* * Test method for 'org.apache.jmeter.protocol.http.sampler.PostWriter.sendPostData(URLConnection, HTTPSampler)' + * This method test sending a HTTPSampler with form parameters, and only + * the filename of a file. */ public void testSendPostData_NoFilename() throws IOException { setupNoFilename(sampler); - setupCommons(sampler); + String titleValue = "mytitle"; + String descriptionValue = "mydescription"; + setupFormData(sampler, titleValue, descriptionValue); - PostWriter.sendPostData(connection, sampler); + // Test sending data with default encoding + String contentEncoding = ""; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); - assertEquals("title=mytitle&description=mydescription", connection.getOutputStream().toString()); + checkContentTypeUrlEncoded(connection); + byte[] expectedUrl = "title=mytitle&description=mydescription".getBytes(); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + expectedUrl = "title=mytitle&description=mydescription".getBytes("UTF-8"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as ISO-8859-1 + establishConnection(); + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + expectedUrl = "title=mytitle&description=mydescription".getBytes(contentEncoding); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + expectedUrl = "title=mytitle&description=mydescription".getBytes("UTF-8"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + connection.disconnect(); } /* + * Test method for 'org.apache.jmeter.protocol.http.sampler.PostWriter.sendPostData(URLConnection, HTTPSampler)' + * This method test sending file content as the only content of the post body + */ + public void testSendPostData_FileAsBody() throws IOException { + setupFilepart(sampler, "", temporaryFile, ""); + + // Check using default encoding + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentLength(connection, TEST_FILE_CONTENT.length); + checkArraysHaveSameContent(TEST_FILE_CONTENT, connection.getOutputStreamContent()); + connection.disconnect(); + + // Check using UTF-8 encoding + establishConnection(); + sampler.setContentEncoding("UTF-8"); + // File content is sent as binary, so the content encoding should not change the file data + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentLength(connection, TEST_FILE_CONTENT.length); + checkArraysHaveSameContent(TEST_FILE_CONTENT, connection.getOutputStreamContent()); + checkArraysHaveDifferentContent(new String(TEST_FILE_CONTENT).getBytes("UTF-8"), connection.getOutputStreamContent()); + + // If we have both file as body, and form data, then only form data will be sent + setupFormData(sampler); + establishConnection(); + sampler.setContentEncoding(""); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + byte[] expectedUrl = "title=mytitle&description=mydescription".getBytes(); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + } + + /* + * Test method for 'org.apache.jmeter.protocol.http.sampler.PostWriter.sendPostData(URLConnection, HTTPSampler)' + * This method test sending only a file multipart. + */ + public void testSendFileData_Multipart() throws IOException { + String fileField = "upload"; + String mimeType = "text/plain"; + File file = temporaryFile; + byte[] fileContent = TEST_FILE_CONTENT; + setupFilepart(sampler, fileField, file, mimeType); + + // Test sending data with default encoding + String contentEncoding = ""; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + byte[] expectedFormBody = createExpectedFilepartOutput(postWriter.getBoundary(), fileField, file, mimeType, fileContent, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as ISO-8859-1 + establishConnection(); + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedFilepartOutput(postWriter.getBoundary(), fileField, file, mimeType, fileContent, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as UTF-8 + establishConnection(); + fileField = "some_file_field"; + mimeType = "image/png"; + contentEncoding = "UTF-8"; + sampler.setContentEncoding(contentEncoding); + setupFilepart(sampler, fileField, file, mimeType); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedFilepartOutput(postWriter.getBoundary(), fileField, file, mimeType, fileContent, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + } + + /* + * Test method for 'org.apache.jmeter.protocol.http.sampler.PostWriter.sendPostData(URLConnection, HTTPSampler)' + * This method test sending only a formdata, as a multipart/form-data request. + */ + public void testSendFormData_Multipart() throws IOException { + String titleField = "title"; + String titleValue = "mytitle"; + String descriptionField = "description"; + String descriptionValue = "mydescription"; + setupFormData(sampler, titleValue, descriptionValue); + // Tell sampler to do multipart, even if we have no files to upload + sampler.setDoMultipartPost(true); + + // Test sending data with default encoding + String contentEncoding = ""; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + byte[] expectedFormBody = createExpectedFormdataOutput(postWriter.getBoundary(), "iso-8859-1", titleField, titleValue, descriptionField, descriptionValue, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as ISO-8859-1 + establishConnection(); + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedFormdataOutput(postWriter.getBoundary(), contentEncoding, titleField, titleValue, descriptionField, descriptionValue, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as ISO-8859-1, with values that need to be urlencoded + establishConnection(); + titleValue = "mytitle+123 456&yes"; + descriptionValue = "mydescription and some spaces"; + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + setupFormData(sampler, titleValue, descriptionValue); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedFormdataOutput(postWriter.getBoundary(), contentEncoding, titleField, titleValue, descriptionField, descriptionValue, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as UTF-8 + establishConnection(); + titleValue = "mytitle\u0153\u20a1\u0115\u00c5"; + descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5"; + contentEncoding = "UTF-8"; + sampler.setContentEncoding(contentEncoding); + setupFormData(sampler, titleValue, descriptionValue); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedFormdataOutput(postWriter.getBoundary(), contentEncoding, titleField, titleValue, descriptionField, descriptionValue, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as UTF-8, with values that would have been urlencoded + // if it was not sent as multipart + establishConnection(); + titleValue = "mytitle\u0153+\u20a1 \u0115&yes\u00c5"; + descriptionValue = "mydescription \u0153 \u20a1 \u0115 \u00c5"; + contentEncoding = "UTF-8"; + sampler.setContentEncoding(contentEncoding); + setupFormData(sampler, titleValue, descriptionValue); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeMultipart(connection, postWriter.getBoundary()); + expectedFormBody = createExpectedFormdataOutput(postWriter.getBoundary(), contentEncoding, titleField, titleValue, descriptionField, descriptionValue, true, true); + checkContentLength(connection, expectedFormBody.length); + checkArraysHaveSameContent(expectedFormBody, connection.getOutputStreamContent()); + connection.disconnect(); + } + + /* + * Test method for 'org.apache.jmeter.protocol.http.sampler.PostWriter.sendPostData(URLConnection, HTTPSampler)' + * This method test sending only a formdata, as urlencoded data + */ + public void testSendFormData_Urlencoded() throws IOException { + String titleValue = "mytitle"; + String descriptionValue = "mydescription"; + setupFormData(sampler, titleValue, descriptionValue); + + // Test sending data with default encoding + String contentEncoding = ""; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + byte[] expectedUrl = new String("title=" + titleValue + "&description=" + descriptionValue).getBytes("US-ASCII"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), "ISO-8859-1"), + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), "ISO-8859-1")); + connection.disconnect(); + + // Test sending data as ISO-8859-1 + establishConnection(); + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + expectedUrl = new String("title=" + titleValue + "&description=" + descriptionValue).getBytes("US-ASCII"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding), + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding)); + connection.disconnect(); + + // Test sending data as ISO-8859-1, with values that need to be urlencoded + establishConnection(); + titleValue = "mytitle+123 456&yes"; + descriptionValue = "mydescription and some spaces"; + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + setupFormData(sampler, titleValue, descriptionValue); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + String expectedString = "title=" + URLEncoder.encode(titleValue, contentEncoding) + "&description=" + URLEncoder.encode(descriptionValue, contentEncoding); + expectedUrl = expectedString.getBytes(contentEncoding); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding), + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding)); + String unencodedString = "title=" + titleValue + "&description=" + descriptionValue; + byte[] unexpectedUrl = unencodedString.getBytes("UTF-8"); + checkArraysHaveDifferentContent(unexpectedUrl, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending data as UTF-8 + establishConnection(); + titleValue = "mytitle\u0153\u20a1\u0115\u00c5"; + descriptionValue = "mydescription\u0153\u20a1\u0115\u00c5"; + contentEncoding = "UTF-8"; + sampler.setContentEncoding(contentEncoding); + setupFormData(sampler, titleValue, descriptionValue); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + expectedString = "title=" + URLEncoder.encode(titleValue, contentEncoding) + "&description=" + URLEncoder.encode(descriptionValue, contentEncoding); + expectedUrl = expectedString.getBytes("US-ASCII"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding), + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding)); + connection.disconnect(); + + // Test sending data as UTF-8, with values that needs to be urlencoded + establishConnection(); + titleValue = "mytitle\u0153+\u20a1 \u0115&yes\u00c5"; + descriptionValue = "mydescription \u0153 \u20a1 \u0115 \u00c5"; + contentEncoding = "UTF-8"; + sampler.setContentEncoding(contentEncoding); + setupFormData(sampler, titleValue, descriptionValue); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + expectedString = "title=" + URLEncoder.encode(titleValue, "UTF-8") + "&description=" + URLEncoder.encode(descriptionValue, "UTF-8"); + expectedUrl = expectedString.getBytes("US-ASCII"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding), + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding)); + unencodedString = "title=" + titleValue + "&description=" + descriptionValue; + unexpectedUrl = unencodedString.getBytes("US-ASCII"); + checkArraysHaveDifferentContent(unexpectedUrl, connection.getOutputStreamContent()); + connection.disconnect(); + + // Test sending parameters which are urlencoded beforehand + // The values must be URL encoded with UTF-8 encoding, because that + // is what the HTTPArgument assumes + // %C3%85 in UTF-8 is the same as %C5 in ISO-8859-1, which is the same as Å + titleValue = "mytitle%20and%20space%2Ftest%C3%85"; + descriptionValue = "mydescription+and+plus+as+space%2Ftest%C3%85"; + setupFormData(sampler, true, titleValue, descriptionValue); + + // Test sending data with default encoding + establishConnection(); + contentEncoding = ""; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + expectedUrl = new String("title=" + titleValue.replaceAll("%20", "+").replaceAll("%C3%85", "%C5") + "&description=" + descriptionValue.replaceAll("%C3%85", "%C5")).getBytes("US-ASCII"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), "ISO-8859-1"), // HTTPSampler uses ISO-8859-1 as default encoding + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), "ISO-8859-1")); // HTTPSampler uses ISO-8859-1 as default encoding + connection.disconnect(); + + // Test sending data as ISO-8859-1 + establishConnection(); + contentEncoding = "ISO-8859-1"; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + expectedUrl = new String("title=" + titleValue.replaceAll("%20", "+").replaceAll("%C3%85", "%C5") + "&description=" + descriptionValue.replaceAll("%C3%85", "%C5")).getBytes("US-ASCII"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding), + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding)); + connection.disconnect(); + + // Test sending data as UTF-8 + establishConnection(); + contentEncoding = "UTF-8"; + sampler.setContentEncoding(contentEncoding); + postWriter.setHeaders(connection, sampler); + postWriter.sendPostData(connection, sampler); + + checkContentTypeUrlEncoded(connection); + expectedUrl = new String("title=" + titleValue.replaceAll("%20", "+") + "&description=" + descriptionValue).getBytes("US-ASCII"); + checkContentLength(connection, expectedUrl.length); + checkArraysHaveSameContent(expectedUrl, connection.getOutputStreamContent()); + assertEquals( + URLDecoder.decode(new String(expectedUrl, "US-ASCII"), contentEncoding), + URLDecoder.decode(new String(connection.getOutputStreamContent(), "US-ASCII"), contentEncoding)); + connection.disconnect(); + } + + /* * Test method for 'org.apache.jmeter.protocol.http.sampler.PostWriter.setHeaders(URLConnection, HTTPSampler)' */ public void testSetHeaders() throws IOException { - setupFilename(sampler); - setupCommons(sampler); + setupFilepart(sampler); + setupFormData(sampler); - PostWriter.setHeaders(connection, sampler); - - assertEquals("multipart/form-data; boundary=" + PostWriter.BOUNDARY, connection.getRequestProperty("Content-Type")); + postWriter.setHeaders(connection, sampler); + checkContentTypeMultipart(connection, postWriter.getBoundary()); } /* @@ -102,12 +532,11 @@ */ public void testSetHeaders_NoFilename() throws IOException { setupNoFilename(sampler); - setupCommons(sampler); + setupFormData(sampler); - PostWriter.setHeaders(connection, sampler); - - assertEquals(HTTPSamplerBase.APPLICATION_X_WWW_FORM_URLENCODED, connection.getRequestProperty("Content-Type")); - assertEquals("39", connection.getRequestProperty("Content-Length")); + postWriter.setHeaders(connection, sampler); + checkContentTypeUrlEncoded(connection); + checkContentLength(connection, "title=mytitle&description=mydescription".length()); } /** @@ -117,96 +546,311 @@ * @throws IOException */ private void setupNoFilename(HTTPSampler httpSampler) { - httpSampler.setFilename(""); - httpSampler.setMimetype("application/octet-stream"); + setupFilepart(sampler, "upload", null, "application/octet-stream"); } /** - * setup commons parts of HTTPSampler with a filename. + * Setup the filepart with default values * * @param httpSampler - * @throws IOException */ - private void setupFilename(HTTPSampler httpSampler) { - // httpSampler.setFilename("test/src/org/apache/jmeter/protocol/http/sampler/foo.txt"); - httpSampler.setFilename(temporaryFile.getAbsolutePath()); - httpSampler.setMimetype("text/plain"); + private void setupFilepart(HTTPSampler httpSampler) { + setupFilepart(sampler, "upload", temporaryFile, "text/plain"); } /** - * setup commons parts of HTTPSampler form test* methods. + * Setup the filepart with specified values * * @param httpSampler - * @throws IOException */ - private void setupCommons(HTTPSampler httpSampler) { - httpSampler.setFileField("upload"); + private void setupFilepart(HTTPSampler httpSampler, String fileField, File file, String mimeType) { + httpSampler.setFileField(fileField); + if(file != null) { + httpSampler.setFilename(file.getAbsolutePath()); + } + else { + httpSampler.setFilename(""); + } + httpSampler.setMimetype(mimeType); + } + + /** + * Setup the form data with default values + * + * @param httpSampler + */ + private void setupFormData(HTTPSampler httpSampler) { + setupFormData(httpSampler, "mytitle", "mydescription"); + } + + /** + * Setup the form data with specified values + * + * @param httpSampler + */ + private void setupFormData(HTTPSampler httpSampler, String titleValue, String descriptionValue) { + setupFormData(sampler, false, titleValue, descriptionValue); + } + + /** + * Setup the form data with specified values + * + * @param httpSampler + */ + private void setupFormData(HTTPSampler httpSampler, boolean isEncoded, String titleValue, String descriptionValue) { Arguments args = new Arguments(); - args.addArgument(new HTTPArgument("title", "mytitle")); - args.addArgument(new HTTPArgument("description", "mydescription")); + HTTPArgument argument1 = new HTTPArgument("title", titleValue, isEncoded); + HTTPArgument argument2 = new HTTPArgument("description", descriptionValue, isEncoded); + args.addArgument(argument1); + args.addArgument(argument2); httpSampler.setArguments(args); } + private void establishConnection() throws MalformedURLException { + connection = new StubURLConnection("http://fake_url/test"); + postWriter = new PostWriter(); + } + /** - * Create the expected output with CRLF. + * Create the expected output post body for form data and file multiparts + * with default values for field names */ - private OutputStream createExpectedOutputStream() throws IOException { - /* - -----------------------------7d159c1302d0y0 - Content-Disposition: form-data; name="title" + private byte[] createExpectedOutput( + String boundaryString, + String contentEncoding, + String titleValue, + String descriptionValue, + byte[] fileContent) throws IOException { + return createExpectedOutput(boundaryString, contentEncoding, "title", titleValue, "description", descriptionValue, "upload", fileContent); + } - mytitle - -----------------------------7d159c1302d0y0 - Content-Disposition: form-data; name="description" + /** + * Create the expected output post body for form data and file multiparts + * with specified values + */ + private byte[] createExpectedOutput( + String boundaryString, + String contentEncoding, + String titleField, + String titleValue, + String descriptionField, + String descriptionValue, + String fileField, + byte[] fileContent) throws IOException { + // Create the multiparts + byte[] formdataMultipart = createExpectedFormdataOutput(boundaryString, contentEncoding, titleField, titleValue, descriptionField, descriptionValue, true, false); + byte[] fileMultipart = createExpectedFilepartOutput(boundaryString, fileField, temporaryFile, "text/plain", fileContent, false, true); + + // Join the two multiparts + ByteArrayOutputStream output = new ByteArrayOutputStream(); + output.write(formdataMultipart); + output.write(fileMultipart); + + output.flush(); + output.close(); + + return output.toByteArray(); + } - mydescription - -----------------------------7d159c1302d0y0 - Content-Disposition: form-data; name="upload"; filename="test/src/org/apache/jmeter/protocol/http/sampler/foo.txt" - Content-Type: plain/text - - foo content - -----------------------------7d159c1302d0y0-- - */ - - final OutputStream output = new ByteArrayOutputStream(); - output.write("-----------------------------7d159c1302d0y0".getBytes()); + /** + * Create the expected output multipart/form-data, with only form data, + * and no file multipart + * + * @param lastMultipart true if this is the last multipart in the request + */ + private byte[] createExpectedFormdataOutput( + String boundaryString, + String contentEncoding, + String titleField, + String titleValue, + String descriptionField, + String descriptionValue, + boolean firstMultipart, + boolean lastMultipart) throws IOException { + // The encoding used for http headers and control information + final String httpEncoding = "ISO-8859-1"; + final byte[] DASH_DASH = new String("--").getBytes(httpEncoding); + + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + if(firstMultipart) { + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); + output.write(CRLF); + } + output.write("Content-Disposition: form-data; name=\"".getBytes(httpEncoding)); + output.write(titleField.getBytes(httpEncoding)); + output.write("\"".getBytes(httpEncoding)); output.write(CRLF); - output.write("Content-Disposition: form-data; name=\"title\"".getBytes()); + output.write("Content-Type: text/plain".getBytes(httpEncoding)); + if(contentEncoding != null) { + output.write("; charset=".getBytes(httpEncoding)); + output.write(contentEncoding.getBytes(httpEncoding)); + } output.write(CRLF); + output.write("Content-Transfer-Encoding: 8bit".getBytes(httpEncoding)); output.write(CRLF); - output.write("mytitle".getBytes()); output.write(CRLF); - output.write("-----------------------------7d159c1302d0y0".getBytes()); + if(contentEncoding != null) { + output.write(titleValue.getBytes(contentEncoding)); + } + else { + output.write(titleValue.getBytes()); + } output.write(CRLF); - output.write("Content-Disposition: form-data; name=\"description\"".getBytes()); + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); output.write(CRLF); + output.write("Content-Disposition: form-data; name=\"".getBytes(httpEncoding)); + output.write(descriptionField.getBytes(httpEncoding)); + output.write("\"".getBytes(httpEncoding)); output.write(CRLF); - output.write("mydescription".getBytes()); + output.write("Content-Type: text/plain".getBytes(httpEncoding)); + if(contentEncoding != null) { + output.write("; charset=".getBytes(httpEncoding)); + output.write(contentEncoding.getBytes(httpEncoding)); + } output.write(CRLF); - output.write("-----------------------------7d159c1302d0y0".getBytes()); + output.write("Content-Transfer-Encoding: 8bit".getBytes(httpEncoding)); output.write(CRLF); + output.write(CRLF); + if(contentEncoding != null) { + output.write(descriptionValue.getBytes(contentEncoding)); + } + else { + output.write(descriptionValue.getBytes()); + } + output.write(CRLF); + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); + if(lastMultipart) { + output.write(DASH_DASH); + } + output.write(CRLF); + + output.flush(); + output.close(); + + return output.toByteArray(); + } + + /** + * Create the expected file multipart + * + * @param lastMultipart true if this is the last multipart in the request + */ + private byte[] createExpectedFilepartOutput( + String boundaryString, + String fileField, + File file, + String mimeType, + byte[] fileContent, + boolean firstMultipart, + boolean lastMultipart) throws IOException { + // The encoding used for http headers and control information + final String httpEncoding = "ISO-8859-1"; + final byte[] DASH_DASH = new String("--").getBytes(httpEncoding); + + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + if(firstMultipart) { + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); + output.write(CRLF); + } // replace all backslash with double backslash - String filename = temporaryFile.getAbsolutePath().replaceAll("\\\\","\\\\\\\\"); - output.write(("Content-Disposition: form-data; name=\"upload\"; filename=\"" + filename + "\"").getBytes()); + String filename = file.getAbsolutePath().replaceAll("\\\\","\\\\\\\\"); + output.write("Content-Disposition: form-data; name=\"".getBytes(httpEncoding)); + output.write(fileField.getBytes(httpEncoding)); + output.write(("\"; filename=\"" + filename + "\"").getBytes(httpEncoding)); output.write(CRLF); - output.write("Content-Type: text/plain".getBytes()); + output.write("Content-Type: ".getBytes(httpEncoding)); + output.write(mimeType.getBytes(httpEncoding)); output.write(CRLF); + output.write("Content-Transfer-Encoding: 8bit".getBytes(httpEncoding)); + output.write(CRLF); output.write(CRLF); - output.write("foo content".getBytes()); + output.write(fileContent); output.write(CRLF); - output.write("-----------------------------7d159c1302d0y0--".getBytes()); + output.write(DASH_DASH); + output.write(boundaryString.getBytes(httpEncoding)); + if(lastMultipart) { + output.write(DASH_DASH); + } output.write(CRLF); + output.flush(); output.close(); - return output; + + return output.toByteArray(); } /** + * Check that the the two byte arrays have identical content + * + * @param expected + * @param actual + */ + private void checkArraysHaveSameContent(byte[] expected, byte[] actual) { + if(expected != null && actual != null) { + if(expected.length != actual.length) { + fail("arrays have different length, expected is " + expected.length + ", actual is " + actual.length); + } + else { + for(int i = 0; i < expected.length; i++) { + if(expected[i] != actual[i]) { + fail("byte at position " + i + " is different, expected is " + expected[i] + ", actual is " + actual[i]); + } + } + } + } + else { + fail("expected or actual byte arrays were null"); + } + } + + /** + * Check that the the two byte arrays different content + * + * @param expected + * @param actual + */ + private void checkArraysHaveDifferentContent(byte[] expected, byte[] actual) { + if(expected != null && actual != null) { + if(expected.length == actual.length) { + boolean allSame = true; + for(int i = 0; i < expected.length; i++) { + if(expected[i] != actual[i]) { + allSame = false; + break; + } + } + if(allSame) { + fail("all bytes were equal"); + } + } + } + else { + fail("expected or actual byte arrays were null"); + } + } + + private void checkContentTypeMultipart(HttpURLConnection connection, String boundaryString) { + assertEquals("multipart/form-data; boundary=" + boundaryString, connection.getRequestProperty("Content-Type")); + } + + private void checkContentTypeUrlEncoded(HttpURLConnection connection) { + assertEquals(HTTPSamplerBase.APPLICATION_X_WWW_FORM_URLENCODED, connection.getRequestProperty("Content-Type")); + } + + private void checkContentLength(HttpURLConnection connection, int length) { + assertEquals(Integer.toString(length), connection.getRequestProperty("Content-Length")); + } + + /** * Mock an HttpURLConnection. * extends HttpURLConnection instead of just URLConnection because there is a cast in PostWriter. */ private static class StubURLConnection extends HttpURLConnection { - private OutputStream output = new ByteArrayOutputStream(); + private ByteArrayOutputStream output = new ByteArrayOutputStream(); private Map properties = new HashMap(); public StubURLConnection(String url) throws MalformedURLException { @@ -234,5 +878,9 @@ public void setRequestProperty(String key, String value) { properties.put(key, value); } + + public byte[] getOutputStreamContent() { + return output.toByteArray(); + } } }