You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mc...@apache.org on 2013/01/18 00:17:48 UTC
[12/13] git commit: Fix some bugs and add java integration test for
api rate limit plugin.
Fix some bugs and add java integration test for api rate limit plugin.
Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/86ada92f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/86ada92f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/86ada92f
Branch: refs/heads/api_limit
Commit: 86ada92ffa20d7624ff3c411ac24ea9dbd9e0196
Parents: c1a540c
Author: Min Chen <mi...@citrix.com>
Authored: Thu Jan 17 15:13:51 2013 -0800
Committer: Min Chen <mi...@citrix.com>
Committed: Thu Jan 17 15:13:51 2013 -0800
----------------------------------------------------------------------
client/tomcatconf/components.xml.in | 2 +-
plugins/api/rate-limit/pom.xml | 22 ++
.../api/command/user/ratelimit/GetApiLimitCmd.java | 3 +-
.../cloudstack/ratelimit/integration/APITest.java | 211 ++++++++++++++
.../ratelimit/integration/LoginResponse.java | 142 ++++++++++
.../integration/RateLimitIntegrationTest.java | 214 +++++++++++++++
server/test/com/cloud/api/APITest.java | 39 ++-
server/test/com/cloud/api/ListPerfTest.java | 140 ----------
8 files changed, 622 insertions(+), 151 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/client/tomcatconf/components.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in
index e19b418..8157051 100755
--- a/client/tomcatconf/components.xml.in
+++ b/client/tomcatconf/components.xml.in
@@ -185,7 +185,7 @@ under the License.
<pluggableservice name="ApiDiscoveryService" key="org.apache.cloudstack.discovery.ApiDiscoveryService" class="org.apache.cloudstack.discovery.ApiDiscoveryServiceImpl"/>
<pluggableservice name="VirtualRouterElementService" key="com.cloud.network.element.VirtualRouterElementService" class="com.cloud.network.element.VirtualRouterElement"/>
<pluggableservice name="NiciraNvpElementService" key="com.cloud.network.element.NiciraNvpElementService" class="com.cloud.network.element.NiciraNvpElement"/>
- <pluggableservice name="ApiRateLimitService" key="org.apache.cloudstack.api.ratelimit.ApiRateLimitService" class="org.apache.cloudstack.ratelimit.ApiRateLimitServiceImpl"/>
+ <pluggableservice name="ApiRateLimitService" key="org.apache.cloudstack.ratelimit.ApiRateLimitService" class="org.apache.cloudstack.ratelimit.ApiRateLimitServiceImpl"/>
<dao name="OvsTunnelInterfaceDao" class="com.cloud.network.ovs.dao.OvsTunnelInterfaceDaoImpl" singleton="false"/>
<dao name="OvsTunnelAccountDao" class="com.cloud.network.ovs.dao.OvsTunnelNetworkDaoImpl" singleton="false"/>
<dao name="NiciraNvpDao" class="com.cloud.network.dao.NiciraNvpDaoImpl" singleton="false"/>
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/plugins/api/rate-limit/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml
index 416c901..1f03309 100644
--- a/plugins/api/rate-limit/pom.xml
+++ b/plugins/api/rate-limit/pom.xml
@@ -26,4 +26,26 @@
<version>4.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
+ <build>
+ <defaultGoal>install</defaultGoal>
+ <sourceDirectory>src</sourceDirectory>
+ <testSourceDirectory>test</testSourceDirectory>
+ <testResources>
+ <testResource>
+ <directory>test/resources</directory>
+ </testResource>
+ </testResources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <argLine>-Xmx1024m</argLine>
+ <excludes>
+ <exclude>org/apache/cloudstack/ratelimit/integration/*</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java
----------------------------------------------------------------------
diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java b/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java
index ad1fb28..2b7b8e6 100644
--- a/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java
+++ b/plugins/api/rate-limit/src/org/apache/cloudstack/api/command/user/ratelimit/GetApiLimitCmd.java
@@ -46,7 +46,7 @@ import com.cloud.user.UserContext;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = "getApiLimit", responseObject=ApiLimitResponse.class, description="Get API limit count for the caller")
-public class GetApiLimitCmd extends BaseListCmd {
+public class GetApiLimitCmd extends BaseCmd {
private static final Logger s_logger = Logger.getLogger(GetApiLimitCmd.class.getName());
private static final String s_name = "getapilimitresponse";
@@ -81,6 +81,7 @@ public class GetApiLimitCmd extends BaseListCmd {
Account caller = UserContext.current().getCaller();
ApiLimitResponse response = _apiLimitService.searchApiLimit(caller);
response.setResponseName(getCommandName());
+ response.setObjectName("apilimit");
this.setResponseObject(response);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java
----------------------------------------------------------------------
diff --git a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java
new file mode 100644
index 0000000..7701b15
--- /dev/null
+++ b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java
@@ -0,0 +1,211 @@
+// 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
+// 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.cloudstack.ratelimit.integration;
+
+import java.io.BufferedReader;
+import java.io.EOFException;
+import java.io.InputStreamReader;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.cloudstack.api.response.SuccessResponse;
+
+import com.cloud.api.ApiGsonHelper;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.google.gson.Gson;
+
+/**
+ * Base class for API Test
+ *
+ * @author Min Chen
+ *
+ */
+public abstract class APITest {
+
+ protected String rootUrl = "http://localhost:8080/client/api";
+ protected String sessionKey = null;
+ protected String cookieToSent = null;
+
+
+ /**
+ * Sending an api request through Http GET
+ * @param command command name
+ * @param params command query parameters in a HashMap
+ * @return http request response string
+ */
+ protected String sendRequest(String command, HashMap<String, String> params){
+ try {
+ // Construct query string
+ StringBuilder sBuilder = new StringBuilder();
+ sBuilder.append("command=");
+ sBuilder.append(command);
+ if ( params != null && params.size() > 0){
+ Iterator<String> keys = params.keySet().iterator();
+ while (keys.hasNext()){
+ String key = keys.next();
+ sBuilder.append("&");
+ sBuilder.append(key);
+ sBuilder.append("=");
+ sBuilder.append(URLEncoder.encode(params.get(key), "UTF-8"));
+ }
+ }
+
+ // Construct request url
+ String reqUrl = rootUrl + "?" + sBuilder.toString();
+
+ // Send Http GET request
+ URL url = new URL(reqUrl);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");
+
+ if ( !command.equals("login") && cookieToSent != null){
+ // add the cookie to a request
+ conn.setRequestProperty("Cookie", cookieToSent);
+ }
+ conn.connect();
+
+
+ if ( command.equals("login")){
+ // if it is login call, store cookie
+ String headerName=null;
+ for (int i=1; (headerName = conn.getHeaderFieldKey(i))!=null; i++) {
+ if (headerName.equals("Set-Cookie")) {
+ String cookie = conn.getHeaderField(i);
+ cookie = cookie.substring(0, cookie.indexOf(";"));
+ String cookieName = cookie.substring(0, cookie.indexOf("="));
+ String cookieValue = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
+ cookieToSent = cookieName + "=" + cookieValue;
+ }
+ }
+ }
+
+ // Get the response
+ StringBuilder response = new StringBuilder();
+ BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ String line;
+ try {
+ while ((line = rd.readLine()) != null) {
+ response.append(line);
+ }
+ } catch (EOFException ex) {
+ // ignore this exception
+ System.out.println("EOF exception due to java bug");
+ }
+ rd.close();
+
+
+
+ return response.toString();
+
+ } catch (Exception e) {
+ throw new CloudRuntimeException("Problem with sending api request", e);
+ }
+ }
+
+ protected String createMD5String(String password) {
+ MessageDigest md5;
+ try {
+ md5 = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new CloudRuntimeException("Error", e);
+ }
+
+ md5.reset();
+ BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
+
+ // make sure our MD5 hash value is 32 digits long...
+ StringBuffer sb = new StringBuffer();
+ String pwStr = pwInt.toString(16);
+ int padding = 32 - pwStr.length();
+ for (int i = 0; i < padding; i++) {
+ sb.append('0');
+ }
+ sb.append(pwStr);
+ return sb.toString();
+ }
+
+
+ protected Object fromSerializedString(String result, Class<?> repCls) {
+ try {
+ if (result != null && !result.isEmpty()) {
+ // get real content
+ int start;
+ int end;
+ if (repCls == LoginResponse.class || repCls == SuccessResponse.class) {
+
+ start = result.indexOf('{', result.indexOf('{') + 1); // find
+ // the
+ // second
+ // {
+
+ end = result.lastIndexOf('}', result.lastIndexOf('}') - 1); // find
+ // the
+ // second
+ // }
+ // backwards
+
+ } else {
+ // get real content
+ start = result.indexOf('{', result.indexOf('{', result.indexOf('{') + 1) + 1); // find
+ // the
+ // third
+ // {
+ end = result.lastIndexOf('}', result.lastIndexOf('}', result.lastIndexOf('}') - 1) - 1); // find
+ // the
+ // third
+ // }
+ // backwards
+ }
+ if (start < 0 || end < 0) {
+ throw new CloudRuntimeException("Response format is wrong: " + result);
+ }
+ String content = result.substring(start, end + 1);
+ Gson gson = ApiGsonHelper.getBuilder().create();
+ return gson.fromJson(content, repCls);
+ }
+ return null;
+ } catch (RuntimeException e) {
+ throw new CloudRuntimeException("Caught runtime exception when doing GSON deserialization on: " + result, e);
+ }
+ }
+
+ /**
+ * Login call
+ * @param username user name
+ * @param password password (plain password, we will do MD5 hash here for you)
+ * @return login response string
+ */
+ protected void login(String username, String password)
+ {
+ //String md5Psw = createMD5String(password);
+ // send login request
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("response", "json");
+ params.put("username", username);
+ params.put("password", password);
+ String result = this.sendRequest("login", params);
+ LoginResponse loginResp = (LoginResponse)fromSerializedString(result, LoginResponse.class);
+ sessionKey = loginResp.getSessionkey();
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java
----------------------------------------------------------------------
diff --git a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java
new file mode 100644
index 0000000..719f39c
--- /dev/null
+++ b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java
@@ -0,0 +1,142 @@
+// 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
+// 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.cloudstack.ratelimit.integration;
+
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Login Response object
+ *
+ * @author Min Chen
+ *
+ */
+public class LoginResponse extends BaseResponse {
+
+ @SerializedName("timeout")
+ @Param(description = "session timeout period")
+ private String timeout;
+
+ @SerializedName("sessionkey")
+ @Param(description = "login session key")
+ private String sessionkey;
+
+ @SerializedName("username")
+ @Param(description = "login username")
+ private String username;
+
+ @SerializedName("userid")
+ @Param(description = "login user internal uuid")
+ private String userid;
+
+ @SerializedName("firstname")
+ @Param(description = "login user firstname")
+ private String firstname;
+
+ @SerializedName("lastname")
+ @Param(description = "login user lastname")
+ private String lastname;
+
+ @SerializedName("account")
+ @Param(description = "login user account type")
+ private String account;
+
+ @SerializedName("domainid")
+ @Param(description = "login user domain id")
+ private String domainid;
+
+ @SerializedName("type")
+ @Param(description = "login user type")
+ private int type;
+
+ public String getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(String timeout) {
+ this.timeout = timeout;
+ }
+
+ public String getSessionkey() {
+ return sessionkey;
+ }
+
+ public void setSessionkey(String sessionkey) {
+ this.sessionkey = sessionkey;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getUserid() {
+ return userid;
+ }
+
+ public void setUserid(String userid) {
+ this.userid = userid;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firstname = firstname;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+ public void setLastname(String lastname) {
+ this.lastname = lastname;
+ }
+
+ public String getAccount() {
+ return account;
+ }
+
+ public void setAccount(String account) {
+ this.account = account;
+ }
+
+ public String getDomainid() {
+ return domainid;
+ }
+
+ public void setDomainid(String domainid) {
+ this.domainid = domainid;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java
----------------------------------------------------------------------
diff --git a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java
new file mode 100644
index 0000000..72d354c
--- /dev/null
+++ b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java
@@ -0,0 +1,214 @@
+// 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
+// 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.cloudstack.ratelimit.integration;
+
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.cloudstack.api.response.ApiLimitResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+
+/**
+ * Test fixture to do integration rate limit test.
+ * Currently we commented out this test suite since it requires a real MS and Db running.
+ *
+ * @author Min Chen
+ *
+ */
+public class RateLimitIntegrationTest extends APITest {
+
+ private static int apiMax = 25; // assuming ApiRateLimitService set api.throttling.max = 25
+
+ @Before
+ public void setup(){
+ // always reset count for each testcase
+ login("admin", "password");
+
+ // issue reset api limit calls
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("response", "json");
+ params.put("sessionkey", sessionKey);
+ String resetResult = sendRequest("resetApiLimit", params);
+ assertNotNull("Reset count failed!", fromSerializedString(resetResult, SuccessResponse.class));
+
+ }
+
+
+ @Test
+ public void testNoApiLimitOnRootAdmin() throws Exception {
+ // issue list Accounts calls
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("response", "json");
+ params.put("listAll", "true");
+ params.put("sessionkey", sessionKey);
+ // assuming ApiRateLimitService set api.throttling.max = 25
+ int clientCount = 26;
+ Runnable[] clients = new Runnable[clientCount];
+ final boolean[] isUsable = new boolean[clientCount];
+
+ final CountDownLatch startGate = new CountDownLatch(1);
+
+ final CountDownLatch endGate = new CountDownLatch(clientCount);
+
+
+ for (int i = 0; i < isUsable.length; ++i) {
+ final int j = i;
+ clients[j] = new Runnable() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ try {
+ startGate.await();
+
+ sendRequest("listAccounts", params);
+
+ isUsable[j] = true;
+
+ } catch (CloudRuntimeException e){
+ isUsable[j] = false;
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ endGate.countDown();
+ }
+ }
+ };
+ }
+
+ ExecutorService executor = Executors.newFixedThreadPool(clientCount);
+
+ for (Runnable runnable : clients) {
+ executor.execute(runnable);
+ }
+
+ startGate.countDown();
+
+ endGate.await();
+
+ int rejectCount = 0;
+ for ( int i = 0; i < isUsable.length; ++i){
+ if ( !isUsable[i])
+ rejectCount++;
+ }
+
+ assertEquals("No request should be rejected!", 0, rejectCount);
+
+ }
+
+
+ @Test
+ public void testApiLimitOnUser() throws Exception {
+ // log in using normal user
+ login("demo", "password");
+ // issue list Accounts calls
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("response", "json");
+ params.put("listAll", "true");
+ params.put("sessionkey", sessionKey);
+
+ int clientCount = apiMax + 1;
+ Runnable[] clients = new Runnable[clientCount];
+ final boolean[] isUsable = new boolean[clientCount];
+
+ final CountDownLatch startGate = new CountDownLatch(1);
+
+ final CountDownLatch endGate = new CountDownLatch(clientCount);
+
+
+ for (int i = 0; i < isUsable.length; ++i) {
+ final int j = i;
+ clients[j] = new Runnable() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ try {
+ startGate.await();
+
+ sendRequest("listAccounts", params);
+
+ isUsable[j] = true;
+
+ } catch (CloudRuntimeException e){
+ isUsable[j] = false;
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ endGate.countDown();
+ }
+ }
+ };
+ }
+
+ ExecutorService executor = Executors.newFixedThreadPool(clientCount);
+
+ for (Runnable runnable : clients) {
+ executor.execute(runnable);
+ }
+
+ startGate.countDown();
+
+ endGate.await();
+
+ int rejectCount = 0;
+ for ( int i = 0; i < isUsable.length; ++i){
+ if ( !isUsable[i])
+ rejectCount++;
+ }
+
+ assertEquals("Only one request should be rejected!", 1, rejectCount);
+
+ }
+
+ @Test
+ public void testGetApiLimitOnUser() throws Exception {
+ // log in using normal user
+ login("demo", "password");
+
+ // issue an api call
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("response", "json");
+ params.put("listAll", "true");
+ params.put("sessionkey", sessionKey);
+ sendRequest("listAccounts", params);
+
+ // issue get api limit calls
+ final HashMap<String, String> params2 = new HashMap<String, String>();
+ params2.put("response", "json");
+ params2.put("sessionkey", sessionKey);
+ String getResult = sendRequest("getApiLimit", params2);
+ ApiLimitResponse getLimitResp = (ApiLimitResponse)fromSerializedString(getResult, ApiLimitResponse.class);
+ assertEquals("Issued api count is incorrect!", 2, getLimitResp.getApiIssued() ); // should be 2 apis issues plus this getlimit api
+ assertEquals("Allowed api count is incorrect!", apiMax -2, getLimitResp.getApiAllowed());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/server/test/com/cloud/api/APITest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/api/APITest.java b/server/test/com/cloud/api/APITest.java
index 69c488f..0b040ab 100644
--- a/server/test/com/cloud/api/APITest.java
+++ b/server/test/com/cloud/api/APITest.java
@@ -19,17 +19,17 @@ package com.cloud.api;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
-import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
+import org.apache.cloudstack.api.response.SuccessResponse;
+
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.gson.Gson;
@@ -147,17 +147,38 @@ public abstract class APITest {
protected Object fromSerializedString(String result, Class<?> repCls) {
try {
if (result != null && !result.isEmpty()) {
-
// get real content
- int start = result.indexOf('{', result.indexOf('{') + 1); // find the second {
- if ( start < 0 ){
- throw new CloudRuntimeException("Response format is wrong: " + result);
+ int start;
+ int end;
+ if (repCls == LoginResponse.class || repCls == SuccessResponse.class) {
+
+ start = result.indexOf('{', result.indexOf('{') + 1); // find
+ // the
+ // second
+ // {
+
+ end = result.lastIndexOf('}', result.lastIndexOf('}') - 1); // find
+ // the
+ // second
+ // }
+ // backwards
+
+ } else {
+ // get real content
+ start = result.indexOf('{', result.indexOf('{', result.indexOf('{') + 1) + 1); // find
+ // the
+ // third
+ // {
+ end = result.lastIndexOf('}', result.lastIndexOf('}', result.lastIndexOf('}') - 1) - 1); // find
+ // the
+ // third
+ // }
+ // backwards
}
- int end = result.lastIndexOf('}', result.lastIndexOf('}')-1); // find the second } backwards
- if ( end < 0 ){
+ if (start < 0 || end < 0) {
throw new CloudRuntimeException("Response format is wrong: " + result);
}
- String content = result.substring(start, end+1);
+ String content = result.substring(start, end + 1);
Gson gson = ApiGsonHelper.getBuilder().create();
return gson.fromJson(content, repCls);
}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/86ada92f/server/test/com/cloud/api/ListPerfTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/api/ListPerfTest.java b/server/test/com/cloud/api/ListPerfTest.java
index c6fda9b..b8cb97e 100644
--- a/server/test/com/cloud/api/ListPerfTest.java
+++ b/server/test/com/cloud/api/ListPerfTest.java
@@ -170,144 +170,4 @@ public class ListPerfTest extends APITest {
}
- @Test
- public void testNoApiLimitOnRootAdmin() throws Exception {
- // issue list Accounts calls
- final HashMap<String, String> params = new HashMap<String, String>();
- params.put("response", "json");
- params.put("listAll", "true");
- params.put("sessionkey", sessionKey);
- // assuming ApiRateLimitService set api.throttling.max = 25
- int clientCount = 26;
- Runnable[] clients = new Runnable[clientCount];
- final boolean[] isUsable = new boolean[clientCount];
-
- final CountDownLatch startGate = new CountDownLatch(1);
-
- final CountDownLatch endGate = new CountDownLatch(clientCount);
-
-
- for (int i = 0; i < isUsable.length; ++i) {
- final int j = i;
- clients[j] = new Runnable() {
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- try {
- startGate.await();
-
- sendRequest("listAccounts", params);
-
- isUsable[j] = true;
-
- } catch (CloudRuntimeException e){
- isUsable[j] = false;
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- endGate.countDown();
- }
- }
- };
- }
-
- ExecutorService executor = Executors.newFixedThreadPool(clientCount);
-
- for (Runnable runnable : clients) {
- executor.execute(runnable);
- }
-
- startGate.countDown();
-
- endGate.await();
-
- int rejectCount = 0;
- for ( int i = 0; i < isUsable.length; ++i){
- if ( !isUsable[i])
- rejectCount++;
- }
-
- assertEquals("No request should be rejected!", 0, rejectCount);
-
- }
-
-
- @Test
- public void testApiLimitOnUser() throws Exception {
- // log in using normal user
- login("demo", "password");
- // issue list Accounts calls
- final HashMap<String, String> params = new HashMap<String, String>();
- params.put("response", "json");
- params.put("listAll", "true");
- params.put("sessionkey", sessionKey);
- // assuming ApiRateLimitService set api.throttling.max = 25
- int clientCount = 26;
- Runnable[] clients = new Runnable[clientCount];
- final boolean[] isUsable = new boolean[clientCount];
-
- final CountDownLatch startGate = new CountDownLatch(1);
-
- final CountDownLatch endGate = new CountDownLatch(clientCount);
-
-
- for (int i = 0; i < isUsable.length; ++i) {
- final int j = i;
- clients[j] = new Runnable() {
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- try {
- startGate.await();
-
- sendRequest("listAccounts", params);
-
- isUsable[j] = true;
-
- } catch (CloudRuntimeException e){
- isUsable[j] = false;
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- endGate.countDown();
- }
- }
- };
- }
-
- ExecutorService executor = Executors.newFixedThreadPool(clientCount);
-
- for (Runnable runnable : clients) {
- executor.execute(runnable);
- }
-
- startGate.countDown();
-
- endGate.await();
-
- int rejectCount = 0;
- for ( int i = 0; i < isUsable.length; ++i){
- if ( !isUsable[i])
- rejectCount++;
- }
-
- assertEquals("Only one request should be rejected!", 1, rejectCount);
-
- // issue get api limit calls
- final HashMap<String, String> params2 = new HashMap<String, String>();
- params2.put("response", "json");
- params2.put("sessionkey", sessionKey);
- String getResult = sendRequest("getApiLimit", params2);
- //ApiLimitResponse loginResp = (ApiLimitResponse)fromSerializedString(getResult, ApiLimitResponse.class);
-
- }
-
}