/**
* 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.jersey;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.apache.http.HttpStatus;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import com.fujitsu.dc.common.utils.DcCoreUtils;
import com.fujitsu.dc.core.jersey.filter.DcCoreContainerFilter;
import com.fujitsu.dc.test.categories.Integration;
import com.fujitsu.dc.test.categories.Regression;
import com.fujitsu.dc.test.categories.Unit;
import com.fujitsu.dc.test.setup.Setup;
import com.fujitsu.dc.test.utils.DavResourceUtils;
import com.fujitsu.dc.test.utils.Http;
import com.fujitsu.dc.test.utils.TResponse;
import com.sun.jersey.core.header.InBoundHeaders;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.test.framework.JerseyTest;
/**
* OPTIONSメソッドに関するテスト.
*/
@RunWith(DcRunner.class)
@Category({Unit.class, Integration.class, Regression.class })
public class OptionsMethodTest extends JerseyTest {
/**
* Constructor.
*/
public OptionsMethodTest() {
super("com.fujitsu.dc.core.rs");
}
/**
* OPTIONSメソッドの実行.
* @param path リソースパス
* @return Tresponseオブジェクト
*/
public static TResponse optionsRequest(final String path) {
return optionsRequest(path, HttpStatus.SC_OK);
}
/**
* OPTIONSメソッドの実行.
* @param path リソースパス
* @param code 期待するレスポンスコード
* @return Tresponseオブジェクト
*/
public static TResponse optionsRequest(final String path, final int code) {
TResponse res = Http.request("options.txt")
.with("path", path)
.with("token", AbstractCase.MASTER_TOKEN_NAME)
.returns()
.statusCode(code)
.debug();
return res;
}
/**
* 認証なしのOPTIONSメソッドがリクエストされた場合にpersoniumで受け付けている全メソッドが返却されること.
* @throws URISyntaxException URISyntaxException
*/
@Test
public void 認証なしのOPTIONSメソッドがリクエストされた場合にpersoniumで受け付けている全メソッドが返却されること() throws URISyntaxException {
// 被テストオブジェクトを準備
DcCoreContainerFilter containerFilter = new DcCoreContainerFilter();
// ContainerRequiestを準備
WebApplication wa = mock(WebApplication.class);
InBoundHeaders headers = new InBoundHeaders();
// X-FORWARDED-* 系のヘッダ設定
String scheme = "https";
String host = "example.org";
headers.add(DcCoreUtils.HttpHeaders.X_FORWARDED_PROTO, scheme);
headers.add(DcCoreUtils.HttpHeaders.X_FORWARDED_HOST, host);
ContainerRequest request = new ContainerRequest(wa, HttpMethod.OPTIONS,
new URI("http://dc1.example.com/hoge"),
new URI("http://dc1.example.com/hoge/hoho"),
headers, null);
// HttpServletRequestのmockを準備
HttpServletRequest mockServletRequest = mock(HttpServletRequest.class);
when(mockServletRequest.getRequestURL()).thenReturn(new StringBuffer("http://dc1.example.com"));
ServletContext mockServletContext = mock(ServletContext.class);
when(mockServletContext.getContextPath()).thenReturn("");
when(mockServletRequest.getServletContext()).thenReturn(mockServletContext);
containerFilter.setHttpServletRequest(mockServletRequest);
try {
containerFilter.filter(request);
} catch (WebApplicationException e) {
Response response = e.getResponse();
assertEquals(response.getStatus(), HttpStatus.SC_OK);
MultivaluedMap<String, Object> meta = response.getMetadata();
List<Object> values = meta.get("Access-Control-Allow-Methods");
assertEquals(values.size(), 1);
String value = (String) values.get(0);
String[] methods = value.split(",");
Map<String, String> masterMethods = new HashMap<String, String>();
masterMethods.put(HttpMethod.OPTIONS, "");
masterMethods.put(HttpMethod.GET, "");
masterMethods.put(HttpMethod.POST, "");
masterMethods.put(HttpMethod.PUT, "");
masterMethods.put(HttpMethod.DELETE, "");
masterMethods.put(HttpMethod.HEAD, "");
masterMethods.put(com.fujitsu.dc.common.utils.DcCoreUtils.HttpMethod.MERGE, "");
masterMethods.put(com.fujitsu.dc.common.utils.DcCoreUtils.HttpMethod.MKCOL, "");
masterMethods.put(com.fujitsu.dc.common.utils.DcCoreUtils.HttpMethod.MOVE, "");
masterMethods.put(com.fujitsu.dc.common.utils.DcCoreUtils.HttpMethod.PROPFIND, "");
masterMethods.put(com.fujitsu.dc.common.utils.DcCoreUtils.HttpMethod.PROPPATCH, "");
masterMethods.put(com.fujitsu.dc.common.utils.DcCoreUtils.HttpMethod.ACL, "");
for (String method : methods) {
if (method.trim() == "") {
continue;
}
String m = masterMethods.remove(method.trim());
if (m == null) {
fail("Method " + method + " is not defined.");
}
}
if (!masterMethods.isEmpty()) {
fail("UnExcpected Error.");
}
}
}
/**
* 認証ありのユニットレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること.
*/
@Test
public void 認証ありのユニットレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること() {
// Unitスキーマ
assertTrue(checkResponse(optionsRequest("/__ctl/\\$metadata"), "OPTIONS,GET"));
// Cell
assertTrue(checkResponse(optionsRequest("/__ctl/Cell"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest("/__ctl/Cell('testcell1')"), "OPTIONS,GET,PUT,MERGE,DELETE"));
}
/**
* 認証ありのセルレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること.
*/
@Test
public void 認証ありのセルレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること() {
// Cellスキーマ
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/\\$metadata"), "OPTIONS,GET"));
// Account
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Account"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Account('account1')"),
"OPTIONS,GET,PUT,MERGE,DELETE"));
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Account('account1')/_Role"), "OPTIONS,GET,POST"));
// Role(NavigationProperty) ※セル制御レベルで共通
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Role('role1')/_Box"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Role('role1')/_Account"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Role('role1')/_ExtCell"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Role('role1')/_Relation"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Role('role1')/_ExtRole"), "OPTIONS,GET,POST"));
// Box
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Box"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/Box('box1')"), "OPTIONS,GET,PUT,MERGE,DELETE"));
// TODO Message 204が返却される
// assertTrue(checkResponse(optionsRequest("/testcell1/__message"), "OPTIONS"));
// assertTrue(checkResponse(optionsRequest("/testcell1/__message/send"), "OPTIONS,POST"));
// assertTrue(checkResponse(optionsRequest("/testcell1/__message/port"), "OPTIONS,POST"));
// assertTrue(checkResponse(optionsRequest("/testcell1/__message/received/id"), "OPTIONS,POST"));
// TODO POSTは未提供メソッドのため返却してはいけない
assertTrue(checkResponse(optionsRequest("/testcell1/__ctl/ReceivedMessage"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(
optionsRequest("/testcell1/__ctl/ReceivedMessage('id')"), "OPTIONS,GET,PUT,MERGE,DELETE"));
assertTrue(checkResponse(
optionsRequest("/testcell1/__ctl/ReceivedMessage('id')/_AccountRead"), "OPTIONS,GET,POST"));
// $links
assertTrue(checkResponse(
optionsRequest("/testcell1/__ctl/Role('id')/\\$links/_Box"), "OPTIONS,GET,DELETE,PUT,POST"));
assertTrue(checkResponse(
optionsRequest("/testcell1/__ctl/Role('id')/\\$links/_Box('id')"), "OPTIONS,GET,DELETE,PUT,POST"));
}
/**
* 認証ありのユーザODATAレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること.
*/
@Test
public void 認証ありのユーザODATAレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること() {
// Collection
assertTrue(checkResponse(
optionsRequest("/testcell1/box1/setodata"), "OPTIONS,GET,DELETE,MOVE,PROPFIND,PROPPATCH,ACL"));
// ユーザスキーマ
assertTrue(checkResponse(optionsRequest("/testcell1/box1/setodata/\\$metadata"), "OPTIONS,GET"));
// TODO 204が返却される
// assertTrue(checkResponse(optionsRequest("/testcell1/box1/setodata/\\$metadata/\\$metadata"), "OPTIONS,GET"));
// Entity(他のスキーマ定義と共通)
assertTrue(checkResponse(
optionsRequest("/testcell1/box1/setodata/\\$metadata/EntityType"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/\\$metadata/EntityType('id')"),
"OPTIONS,GET,PUT,MERGE,DELETE"));
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/\\$metadata/EntityType('id')/_AssociationEnd"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/\\$metadata/EntityType('id')/_Property"), "OPTIONS,GET,POST"));
// ユーザデータ
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/Category"), "OPTIONS,GET,POST"));
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/Category('id')"), "OPTIONS,GET,PUT,MERGE,DELETE"));
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/Price('id')/_Sales"), "OPTIONS,GET,POST"));
// $links
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/Price('id')/\\$links/_Sales"),
"OPTIONS,GET,DELETE,PUT,POST"));
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setodata/Price('id')/\\$links/_Sales('id')"),
"OPTIONS,GET,DELETE,PUT,POST"));
}
/**
* 認証ありのDAV_SVCレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること.
*/
@Test
public void 認証ありのDAV_SVCレベルOPTIONSメソッドがpersoniumで受け付けているメソッドが返却されること() {
// Collection(WebDAV/Service)
assertTrue(checkResponse(
optionsRequest("/testcell1/box1/setdavcol"),
"OPTIONS,GET,PUT,DELETE,MKCOL,MOVE,PROPFIND,PROPPATCH,ACL"));
assertTrue(checkResponse(
optionsRequest("/testcell1/box1/service_relay"), "OPTIONS,DELETE,MOVE,PROPFIND,PROPPATCH,ACL"));
// Serviceソースコレクション
assertTrue(checkResponse(
optionsRequest("/testcell1/box1/service_relay/__src"), "OPTIONS,PROPFIND"));
// WebDAVファイル
assertTrue(checkResponse(optionsRequest(
"/testcell1/box1/setdavcol/dav.txt"),
"OPTIONS,GET,PUT,DELETE,MOVE,PROPFIND,PROPPATCH,ACL"));
// TODO サービスソース 204が返却される
// assertTrue(checkResponse(optionsRequest("/testcell1/box1/service_relay/svc"),
// "OPTIONS,GET,POST,PUT,DELETE,HEAD"));
// __src配下
try {
String path = String.format("%s/service_relay/__src/test.js", Setup.TEST_BOX1);
DavResourceUtils.createWebDavFile(AbstractCase.MASTER_TOKEN_NAME, Setup.TEST_CELL1,
path, "hello", "text/javascript", HttpStatus.SC_CREATED);
assertTrue(checkResponse(
optionsRequest("/testcell1/box1/service_relay/__src/test.js"),
"OPTIONS,GET,PUT,DELETE,MOVE,PROPFIND,PROPPATCH,ACL"));
} finally {
DavResourceUtils.deleteWebDavFile(Setup.TEST_CELL1, AbstractCase.MASTER_TOKEN_NAME, Setup.TEST_BOX1,
"service_relay/__src/test.js");
}
}
private boolean checkResponse(TResponse res, String methodStr) {
String values = res.getHeader("Access-Control-Allow-Methods");
if (methodStr == null || methodStr.length() == 0) {
return (values.length() == 0);
} else {
return methodStr.equals(values.replaceAll(" ", ""));
}
}
}