content: // 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.assertEquals;
  import static org.junit.Assert.assertNotNull;
  
  import java.util.HashMap;
  import java.util.concurrent.CountDownLatch;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  
  import org.junit.Before;
  import org.junit.Test;
  
  import org.apache.cloudstack.api.response.ApiLimitResponse;
  import org.apache.cloudstack.api.response.SuccessResponse;
  
  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.
   */
  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());
      }
  }
  