/** * personium.io * Copyright 2014 FUJITSU LIMITED * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.fujitsu.dc.test.utils; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.util.List; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MultivaluedMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.io.IOUtils; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; import com.sun.jersey.core.header.InBoundHeaders; /** * テストHTTP応答. */ public final class TResponse { /** * ログ用オブジェクト. */ private static Logger log = LoggerFactory.getLogger(TResponse.class); int statusCode; MultivaluedMap<String, String> headers = new InBoundHeaders(); StringWriter bodyWriter = new StringWriter(); /** * StatusCodeが期待の値であることを確認します。 * expectedStatusCodeが-1の場合ステータスコードをチェックしない。 * @param expectedStatusCode 期待されるStatusCode * @return TResponse */ public TResponse statusCode(int expectedStatusCode) { if (expectedStatusCode != -1) { assertEquals(expectedStatusCode, this.statusCode); } return this; } /** * locationHeaderが期待の値であることを確認します。 * @param expectedLocationHeaderValue 期待されるLocationHeaderの値 * @return TResponse */ public TResponse location(String expectedLocationHeaderValue) { assertEquals(expectedLocationHeaderValue, this.headers.getFirst(HttpHeaders.LOCATION)); return this; } /** * Content-Typeヘッダが期待の値であることを確認します。 * @param expectedContentTypeHeaderValue 期待されるHeaderの値 * @return TResponse */ public TResponse contentType(String expectedContentTypeHeaderValue) { assertEquals(expectedContentTypeHeaderValue, this.headers.getFirst(HttpHeaders.CONTENT_TYPE)); return this; } /** * 任意のレスポンスヘッダが期待の値であることを確認します。 * @param headerKey 比較するHeader * @param expectedHeaderValue 期待されるHeaderの値 * @return TResponse */ public TResponse checkHeader(String headerKey, String expectedHeaderValue) { assertEquals(expectedHeaderValue, this.headers.getFirst(headerKey)); return this; } /** * Json形式のエラーレスポンスのチェック. * @param expectedCode 期待するエラ―コード * @param expectedValue 期待するメッセージ * @return TResponse */ public TResponse checkErrorResponse(String expectedCode, String expectedValue) { String code = (String) ((JSONObject) this.bodyAsJson()).get("code"); String value = (String) ((JSONObject) ((JSONObject) this.bodyAsJson()).get("message")).get("value"); assertEquals(expectedCode, code); assertEquals(expectedValue, value); return this; } /** * @return the statusCode */ public int getStatusCode() { return this.statusCode; } /** * @return the statusCode */ public String getLocationHeader() { return this.headers.getFirst(HttpHeaders.LOCATION); } /** * @return Response Body */ public String getBody() { return this.bodyWriter.toString(); } /** * @param headerKey ヘッダ名 * @return ヘッダ値 */ public String getHeader(String headerKey) { return this.headers.getFirst(headerKey); } /** * @param headerKey ヘッダ名 * @return ヘッダ値の配列 */ public List<String> getHeaders(String headerKey) { return this.headers.get(headerKey); } /** * レスポンスボディをJSONで取得. * @return JSONオブジェクト */ public JSONObject bodyAsJson() { String res = null; res = this.bodyWriter.toString(); JSONObject jsonobject = null; try { jsonobject = (JSONObject) new JSONParser().parse(res); } catch (ParseException e) { fail(e.getMessage()); } return jsonobject; } /** * レスポンスボディをXMLで取得. * @return XML DOMオブジェクト */ public Document bodyAsXml() { String str = ""; try { str = this.bodyWriter.toString(); } catch (Exception e) { fail(e.getMessage()); } DocumentBuilder builder = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { fail(e.getMessage()); } Document document = null; InputStream is = new ByteArrayInputStream(str.getBytes()); try { document = builder.parse(is); } catch (SAXException e) { fail(e.getMessage()); } catch (IOException e) { fail(e.getMessage()); } return document; } /** * locationHeaderが期待の値であることを確認します。 * @param inspector ロジック * @return TResponse */ public TResponse inspect(Inspector inspector) { inspector.inspect(this); return this; } /** * inspector. */ public interface Inspector { /** * @param response response */ void inspect(TResponse response); } TResponse(BufferedReader sReader) { String line = null; try { line = sReader.readLine(); String[] l1 = line.split(" "); this.statusCode = Integer.valueOf(l1[1]); for (;;) { if (this.readHeader(sReader) <= 0) { break; } } String body = null; if ("chunked".equals(this.headers.getFirst("Transfer-Encoding"))) { body = readBodyChunked(sReader); } else { body = readBodyNonChunk(sReader); } log.debug(body); this.bodyWriter.write(body); } catch (IOException e) { throw new RuntimeException(e); } finally { try { sReader.close(); } catch (IOException e) { throw new RuntimeException(e); } } } String readBodyNonChunk(BufferedReader is) throws IOException { return IOUtils.toString(is); } String readBodyChunked(BufferedReader br) throws IOException { StringBuilder body = new StringBuilder(); String line; while ((line = br.readLine()) != null) { int hex = 2 * 2 * 2 * 2; int chunk = Integer.parseInt(line, hex); if (chunk == 0) { break; } int chr; for (int i = 0; i < chunk; i++) { chr = br.read(); body.append((char) chr); } chr = br.read(); if (chr != '\r') { fail("Chunk終了後のCRが無い"); } chr = br.read(); if (chr != '\n') { fail("Chunk終了後のLFが無い"); } } return body.toString(); } int readHeader(BufferedReader br) throws IOException { String line = br.readLine(); if (line == null) { return -1; } if (line.length() == 0) { return 0; } int idx = line.indexOf(":"); String k = line.substring(0, idx); String v = line.substring(idx + 1); this.headers.add(k, v.trim()); return 1; } /** * デバッグ出力します. * @return TResponse */ public TResponse debug() { log.debug("SC=" + this.statusCode); log.debug("response headers-----"); for (String k : this.headers.keySet()) { log.debug(" " + k + " : " + this.headers.getFirst(k)); } log.debug("response body-----"); log.debug(this.getBody()); return this; } }