Michael Blow has uploaded a new change for review.
https://asterix-gerrit.ics.uci.edu/3191
Change subject: [NO ISSUE] Handle Accept-Charset in RestApiServlet
......................................................................
[NO ISSUE] Handle Accept-Charset in RestApiServlet
also, exercise accept-charset in TestExecutor
Change-Id: I8f37eb684bf2457e5ff451bf5c8fbca742d531f2
---
M
asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
M
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
M
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
M
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
M
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
M
asterixdb/asterix-common/src/test/java/org/apache/asterix/test/server/RSSFeedServlet.java
6 files changed, 81 insertions(+), 34 deletions(-)
git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb
refs/changes/91/3191/1
diff --git
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
index 347b2d7..221984e 100644
---
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
+++
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
@@ -86,7 +86,6 @@
* based on the Accept: header and other servlet parameters.
*/
static SessionOutput initResponse(IServletRequest request,
IServletResponse response) throws IOException {
- HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_PLAIN,
request);
// CLEAN_JSON output is the default; most generally useful for a
// programmatic HTTP API
OutputFormat format = OutputFormat.CLEAN_JSON;
@@ -136,20 +135,20 @@
// Now that format is set, output the content-type
switch (format) {
case ADM:
- HttpUtil.setContentType(response, "application/x-adm");
+ HttpUtil.setContentType(response, "application/x-adm",
request);
break;
case CLEAN_JSON:
// No need to reflect "clean-ness" in output type; fall through
case LOSSLESS_JSON:
- HttpUtil.setContentType(response, "application/json");
+ HttpUtil.setContentType(response, "application/json", request);
break;
case CSV:
// Check for header parameter or in Accept:.
if ("present".equals(request.getParameter("header")) ||
accept.contains("header=present")) {
- HttpUtil.setContentType(response, "text/csv;
header=present");
+ HttpUtil.setContentType(response, "text/csv;
header=present", request);
sessionConfig.set(SessionConfig.FORMAT_CSV_HEADER, true);
} else {
- HttpUtil.setContentType(response, "text/csv;
header=absent");
+ HttpUtil.setContentType(response, "text/csv;
header=absent", request);
}
break;
default:
diff --git
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
index e85fedf..969d23d 100644
---
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
+++
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/CancellationTestExecutor.java
@@ -21,6 +21,7 @@
import java.io.InputStream;
import java.net.URI;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;
@@ -49,7 +50,7 @@
@Override
public InputStream executeQueryService(String str,
TestCaseContext.OutputFormat fmt, URI uri,
- List<TestCase.CompilationUnit.Parameter> params, boolean
jsonEncoded,
+ List<TestCase.CompilationUnit.Parameter> params, boolean
jsonEncoded, Charset responseCharset,
Predicate<Integer> responseCodeValidator, boolean cancellable)
throws Exception {
String clientContextId = UUID.randomUUID().toString();
final List<TestCase.CompilationUnit.Parameter> newParams = cancellable
@@ -57,7 +58,7 @@
Callable<InputStream> query = () -> {
try {
return CancellationTestExecutor.super.executeQueryService(str,
fmt, uri, newParams, jsonEncoded,
- responseCodeValidator, true);
+ responseCharset, responseCodeValidator, true);
} catch (Exception e) {
e.printStackTrace();
throw e;
diff --git
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
index 37e1213..3b57039 100644
---
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
+++
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
@@ -91,8 +91,8 @@
return extract(resultStream, EnumSet.of(ResultField.METRICS));
}
- public static String extractHandle(InputStream resultStream) throws
Exception {
- String result = IOUtils.toString(resultStream, StandardCharsets.UTF_8);
+ public static String extractHandle(InputStream resultStream, Charset
responseCharset) throws Exception {
+ String result = IOUtils.toString(resultStream, responseCharset);
ObjectNode resultJson = OBJECT_MAPPER.readValue(result,
ObjectNode.class);
final JsonNode handle = resultJson.get("handle");
if (handle != null) {
diff --git
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index b143ea9..16db6f8 100644
---
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -35,12 +35,14 @@
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
@@ -155,6 +157,8 @@
private static Map<String, InetSocketAddress> ncEndPoints;
private static Map<String, InetSocketAddress> replicationAddress;
+ private static final List<Charset> charsetsRemaining = new ArrayList<>();
+
/*
* Instance members
*/
@@ -211,12 +215,12 @@
}
public void runScriptAndCompareWithResult(File scriptFile, File
expectedFile, File actualFile,
- ComparisonEnum compare) throws Exception {
+ ComparisonEnum compare, Charset actualEncoding) throws Exception {
LOGGER.info("Expected results file: {} ", expectedFile);
BufferedReader readerExpected =
- new BufferedReader(new InputStreamReader(new
FileInputStream(expectedFile), "UTF-8"));
+ new BufferedReader(new InputStreamReader(new
FileInputStream(expectedFile), StandardCharsets.UTF_8));
BufferedReader readerActual =
- new BufferedReader(new InputStreamReader(new
FileInputStream(actualFile), "UTF-8"));
+ new BufferedReader(new InputStreamReader(new
FileInputStream(actualFile), actualEncoding));
boolean regex = false;
try {
if (ComparisonEnum.BINARY.equals(compare)) {
@@ -570,21 +574,23 @@
}
public InputStream executeQueryService(String str, URI uri, OutputFormat
fmt) throws Exception {
- return executeQueryService(str, fmt, uri, new ArrayList<>(), false);
+ return executeQueryService(str, fmt, uri, new ArrayList<>(), false,
StandardCharsets.UTF_8);
}
public InputStream executeQueryService(String str, OutputFormat fmt, URI
uri, List<Parameter> params,
- boolean jsonEncoded) throws Exception {
- return executeQueryService(str, fmt, uri, params, jsonEncoded, null,
false);
+ boolean jsonEncoded, Charset responseCharset) throws Exception {
+ return executeQueryService(str, fmt, uri, params, jsonEncoded,
responseCharset, null, false);
}
public InputStream executeQueryService(String str, OutputFormat fmt, URI
uri, List<Parameter> params,
boolean jsonEncoded, Predicate<Integer> responseCodeValidator)
throws Exception {
- return executeQueryService(str, fmt, uri, params, jsonEncoded,
responseCodeValidator, false);
+ return executeQueryService(str, fmt, uri, params, jsonEncoded,
StandardCharsets.UTF_8, responseCodeValidator,
+ false);
}
public InputStream executeQueryService(String str, OutputFormat fmt, URI
uri, List<Parameter> params,
- boolean jsonEncoded, Predicate<Integer> responseCodeValidator,
boolean cancellable) throws Exception {
+ boolean jsonEncoded, Charset responseCharset, Predicate<Integer>
responseCodeValidator, boolean cancellable)
+ throws Exception {
List<Parameter> newParams = upsertParam(params, "format",
ParameterTypeEnum.STRING, fmt.mimeType());
newParams = upsertParam(newParams,
QueryServiceServlet.Parameter.PLAN_FORMAT.str(), ParameterTypeEnum.STRING,
DEFAULT_PLAN_FORMAT);
@@ -602,11 +608,47 @@
// Set accepted output response type
method.setHeader("Origin", uri.getScheme() + uri.getAuthority());
method.setHeader("Accept", OutputFormat.CLEAN_JSON.mimeType());
+ method.setHeader("Accept-Charset", responseCharset.name());
HttpResponse response = executeHttpRequest(method);
if (responseCodeValidator != null) {
checkResponse(response, responseCodeValidator);
}
return response.getEntity().getContent();
+ }
+
+ private Charset selectCharset(File result) throws IOException {
+ // choose an encoding that works for this input
+ return selectCharset(FileUtils.readFileToString(result,
StandardCharsets.UTF_8));
+ }
+
+ private Charset selectCharset(String payload) {
+ // choose an encoding that works for this input
+ return nextCharset(charset -> canEncodeDecode(charset, payload));
+ }
+
+ public static Charset nextCharset(Predicate<Charset> test) {
+ synchronized (charsetsRemaining) {
+ while (true) {
+ for (Iterator<Charset> iter = charsetsRemaining.iterator();
iter.hasNext();) {
+ Charset next = iter.next();
+ if (test.test(next)) {
+ iter.remove();
+ return next;
+ }
+ }
+ List<Charset> allCharsets = new
ArrayList<>(Charset.availableCharsets().values());
+ Collections.shuffle(allCharsets);
+ charsetsRemaining.addAll(allCharsets);
+ }
+ }
+ }
+
+ private static boolean canEncodeDecode(Charset charset, String input) {
+ if (input.equals(new String(input.getBytes(charset), charset))) {
+ return true;
+ }
+ LOGGER.debug("cannot encode / decode {} with {}", input,
charset.displayName());
+ return false;
}
protected List<Parameter> upsertParam(List<Parameter> params, String name,
ParameterTypeEnum type, String value) {
@@ -918,18 +960,18 @@
expectedResultFileCtxs);
break;
case "txnqbc": // qbc represents query before crash
- resultStream = query(cUnit, testFile.getName(), statement);
+ resultStream = query(cUnit, testFile.getName(), statement,
StandardCharsets.UTF_8);
qbcFile = getTestCaseQueryBeforeCrashFile(actualPath,
testCaseCtx, cUnit);
writeOutputToFile(qbcFile, resultStream);
break;
case "txnqar": // qar represents query after recovery
- resultStream = query(cUnit, testFile.getName(), statement);
+ resultStream = query(cUnit, testFile.getName(), statement,
StandardCharsets.UTF_8);
File qarFile = new File(actualPath + File.separator
+
testCaseCtx.getTestCase().getFilePath().replace(File.separator, "_") + "_" +
cUnit.getName()
+ "_qar.adm");
writeOutputToFile(qarFile, resultStream);
qbcFile = getTestCaseQueryBeforeCrashFile(actualPath,
testCaseCtx, cUnit);
- runScriptAndCompareWithResult(testFile, qbcFile, qarFile,
ComparisonEnum.TEXT);
+ runScriptAndCompareWithResult(testFile, qbcFile, qarFile,
ComparisonEnum.TEXT, StandardCharsets.UTF_8);
break;
case "txneu": // eu represents erroneous update
try {
@@ -1171,8 +1213,9 @@
} else {
throw new IllegalArgumentException("Unexpected format for method "
+ reqType + ": " + extension);
}
+ Charset responseCharset = selectCharset(expectedResultFile);
if (handleVar != null) {
- String handle = ResultExtractor.extractHandle(resultStream);
+ String handle = ResultExtractor.extractHandle(resultStream,
responseCharset);
if (handle != null) {
variableCtx.put(handleVar, handle);
} else {
@@ -1189,7 +1232,7 @@
}
} else {
writeOutputToFile(actualResultFile, resultStream);
- runScriptAndCompareWithResult(testFile, expectedResultFile,
actualResultFile, compare);
+ runScriptAndCompareWithResult(testFile, expectedResultFile,
actualResultFile, compare, responseCharset);
}
}
queryCount.increment();
@@ -1207,23 +1250,25 @@
URI uri = testFile.getName().endsWith("aql") ?
getEndpoint(Servlets.QUERY_AQL)
: getEndpoint(Servlets.QUERY_SERVICE);
boolean isJsonEncoded =
isJsonEncoded(extractHttpRequestType(statement));
+ Charset responseCharset =
+ expectedResultFile == null ? StandardCharsets.UTF_8 :
selectCharset(expectedResultFile);
InputStream resultStream;
if (DELIVERY_IMMEDIATE.equals(delivery)) {
- resultStream =
- executeQueryService(statement, fmt, uri, params,
isJsonEncoded, null, isCancellable(reqType));
+ resultStream = executeQueryService(statement, fmt, uri, params,
isJsonEncoded, responseCharset, null,
+ isCancellable(reqType));
resultStream = METRICS_QUERY_TYPE.equals(reqType) ?
ResultExtractor.extractMetrics(resultStream)
: ResultExtractor.extract(resultStream);
} else {
String handleVar = getHandleVariable(statement);
resultStream = executeQueryService(statement, fmt, uri,
- upsertParam(params, "mode", ParameterTypeEnum.STRING,
delivery), isJsonEncoded);
- String handle = ResultExtractor.extractHandle(resultStream);
+ upsertParam(params, "mode", ParameterTypeEnum.STRING,
delivery), isJsonEncoded, responseCharset);
+ String handle = ResultExtractor.extractHandle(resultStream,
responseCharset);
Assert.assertNotNull("no handle for " + reqType + " test " +
testFile.toString(), handleVar);
variableCtx.put(handleVar, toQueryServiceHandle(handle));
}
if (actualResultFile == null) {
if (testFile.getName().startsWith(DIAGNOSE)) {
- LOGGER.info("Diagnostic output: {}",
IOUtils.toString(resultStream, StandardCharsets.UTF_8));
+ LOGGER.info("Diagnostic output: {}",
IOUtils.toString(resultStream, responseCharset));
} else {
Assert.fail("no result file for " + testFile.toString() + ";
queryCount: " + queryCount
+ ", filectxs.size: " + numResultFiles);
@@ -1238,7 +1283,7 @@
+ ", filectxs.size: " + numResultFiles);
}
}
- runScriptAndCompareWithResult(testFile, expectedResultFile,
actualResultFile, compare);
+ runScriptAndCompareWithResult(testFile, expectedResultFile,
actualResultFile, compare, responseCharset);
if (!reqType.equals("validate")) {
queryCount.increment();
}
@@ -1964,10 +2009,11 @@
return !NON_CANCELLABLE.contains(type);
}
- private InputStream query(CompilationUnit cUnit, String testFile, String
statement) throws Exception {
+ private InputStream query(CompilationUnit cUnit, String testFile, String
statement, Charset responseCharset)
+ throws Exception {
final URI uri = getQueryServiceUri(testFile);
final InputStream inputStream = executeQueryService(statement,
OutputFormat.forCompilationUnit(cUnit), uri,
- cUnit.getParameter(), true, null, false);
+ cUnit.getParameter(), true, responseCharset, null, false);
return ResultExtractor.extract(inputStream);
}
diff --git
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
index e4e300a..5dd41c3 100644
---
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
+++
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
@@ -25,6 +25,7 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -149,7 +150,8 @@
}
writer.close();
// Compares the actual result and the expected result.
- runScriptAndCompareWithResult(queryFile, expectedFile,
actualResultFile, ComparisonEnum.TEXT);
+ runScriptAndCompareWithResult(queryFile, expectedFile,
actualResultFile, ComparisonEnum.TEXT,
+ StandardCharsets.UTF_8);
} catch (Exception e) {
GlobalConfig.ASTERIX_LOGGER.warn("Failed while testing file " +
queryFile);
throw e;
diff --git
a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/server/RSSFeedServlet.java
b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/server/RSSFeedServlet.java
index 639e036..17c98bc 100644
---
a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/server/RSSFeedServlet.java
+++
b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/server/RSSFeedServlet.java
@@ -67,13 +67,12 @@
String feedType = req.getParameter(FEED_TYPE);
feedType = (feedType != null) ? feedType : defaultFeedType;
feed.setFeedType(feedType);
- HttpUtil.setContentType(res, MIME_TYPE);
+ HttpUtil.setContentType(res, MIME_TYPE, req);
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed, res.writer());
} catch (FeedException | ParseException ex) {
GlobalConfig.ASTERIX_LOGGER.log(Level.WARN, ex.getMessage(), ex);
- String msg = COULD_NOT_GENERATE_FEED_ERROR;
- res.writer().print(msg);
+ res.writer().print(COULD_NOT_GENERATE_FEED_ERROR);
res.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
}
--
To view, visit https://asterix-gerrit.ics.uci.edu/3191
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8f37eb684bf2457e5ff451bf5c8fbca742d531f2
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: stabilization-f69489
Gerrit-Owner: Michael Blow <[email protected]>