{"action":"created","comment":{"url":"https://api.github.com/repos/wso2/product-as/pulls/comments/28663777","id":28663777,"diff_hunk":"@@ -0,0 +1,516 @@\n+/*\n+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.\n+ *\n+ * WSO2 Inc. licenses this file to you under the Apache License,\n+ * Version 2.0 (the \"License\"); you may not use this file except\n+ * in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing,\n+ * software distributed under the License is distributed on an\n+ * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n+ * KIND, either express or implied.  See the License for the\n+ * specific language governing permissions and limitations\n+ * under the License.\n+ */\n+\n+package org.wso2.appserver.integration.lazy.loading;\n+\n+import org.apache.axis2.AxisFault;\n+import org.apache.commons.logging.Log;\n+import org.apache.commons.logging.LogFactory;\n+import org.json.JSONException;\n+import org.json.JSONObject;\n+import org.wso2.appserver.integration.common.clients.WebAppAdminClient;\n+import org.wso2.appserver.integration.common.utils.ASIntegrationTest;\n+import org.wso2.appserver.integration.lazy.loading.util.LazyLoadingTestException;\n+import org.wso2.appserver.integration.lazy.loading.util.TenantStatus;\n+import org.wso2.appserver.integration.lazy.loading.util.WebAppStatus;\n+import org.wso2.carbon.application.mgt.stub.ApplicationAdminExceptionException;\n+import org.wso2.carbon.authenticator.stub.LoginAuthenticationExceptionException;\n+import org.wso2.carbon.automation.engine.context.AutomationContext;\n+import org.wso2.carbon.automation.test.utils.common.TestConfigurationProvider;\n+import org.wso2.carbon.automation.test.utils.http.client.HttpResponse;\n+import org.wso2.carbon.automation.test.utils.http.client.HttpURLConnectionClient;\n+import org.wso2.carbon.integration.common.admin.client.ApplicationAdminClient;\n+import org.wso2.carbon.integration.common.utils.LoginLogoutClient;\n+import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager;\n+import org.wso2.carbon.utils.ServerConstants;\n+import org.xml.sax.SAXException;\n+\n+import javax.xml.stream.XMLStreamException;\n+import javax.xml.xpath.XPathExpressionException;\n+import java.io.File;\n+import java.io.IOException;\n+import java.net.URISyntaxException;\n+import java.rmi.RemoteException;\n+import java.util.Arrays;\n+import java.util.List;\n+\n+/**\n+ * Base class to hold the common variables and utility methods of Lazy Loading (Ghost deployment) Test cases.\n+ * All Lazy Loading (Ghost deployment)  Test  Classes must inherit from this.\n+ * Replacing the carbon.xml with Ghost deployment configuration and deployment of the\n+ * tenant-info-service web application is implemented in side init() method.\n+ */\n+public abstract class LazyLoadingBaseTest extends ASIntegrationTest {\n+\n+\n+    protected static final String TENANT_DOMAIN_1_kEY = \"tenant1\";\n+    protected static final String TENANT_DOMAIN_2_KEY = \"tenant2\";\n+    protected static final String SUPER_TENANT_DOMAIN_KEY = \"superTenant\";\n+\n+    protected String SUPER_TENANT_DOMAIN;\n+    protected String TENANT_DOMAIN_1;\n+    protected String TENANT_DOMAIN_2;\n+\n+    protected WebAppAdminClient webAppAdminClient;\n+    protected ServerConfigurationManager serverManager;\n+    protected String hostURL;\n+    protected static final String CARBON_HOME = System.getProperty(ServerConstants.CARBON_HOME);\n+    protected static String ARTIFACTS_LOCATION;\n+\n+    private static final Log log = LogFactory.getLog(LazyLoadingBaseTest.class);\n+    private long TENANT_IDLE_TIME;\n+    private long WEB_APP_IDLE_TIME;\n+    private static final long MAX_THRESHOLD_TIME = 2 * 60 * 1000;\n+\n+\n+    private static final String PRODUCT_GROUP_NAME = \"AS\";\n+    private static final String INSTANCE_NAME = \"appServerInstance0001\";\n+    private static final String USER_KEY = \"admin\";\n+\n+    private static final String TENANT_INFO_SERVICE = \"lazy-loading-info\";\n+    private static final String TENANT_INFO_SERVICE_FILE_NAME = TENANT_INFO_SERVICE + \".war\";\n+    private static final String IS_TENANT_LOADED_METHOD_URL = TENANT_INFO_SERVICE + \"/tenant-status\";\n+    private static final String IS_WEB_APP_LOADED_METHOD_URL = TENANT_INFO_SERVICE + \"/webapp-status\";\n+\n+\n+    private static final String TENANT_IDLE_XPATH = \"//listenerExtensions/platformExecutionManager/extentionClasses/\" +\n+            \"*[name()='class']/*[name()='parameter'][@name='-Dtenant.idle.time']/@value\";\n+    private static final String WEB_APP_IDLE_XPATH = \"//listenerExtensions/platformExecutionManager/extentionClasses/\" +\n+            \"*[name()='class']/*[name()='parameter'][@name='-Dwebapp.idle.time']/@value\";\n+\n+    private static final String CARBON_XML = \"carbon.xml\";\n+\n+\n+    private static final String CARBON_REPOSITORY_LOCATION =\n+            CARBON_HOME + File.separator + \"repository\" + File.separator + \"conf\" + File.separator + CARBON_XML;\n+    protected static final int CONCURRENT_THREAD_COUNT = 40;\n+\n+    @Override\n+    /**\n+     * Login as super admin and do the replacement of carbon.xml with Ghost deployment\n+     * configuration and deployment of the tenant-info-service web application.\n+     * At the end it will restart the server gracefully.\n+     * @throws Exception\n+     */\n+    public void init() throws Exception {\n+        super.init();\n+\n+        serverManager = new ServerConfigurationManager(asServer);\n+        webAppAdminClient = new WebAppAdminClient(backendURL, sessionCookie);\n+        TENANT_IDLE_TIME =\n+                Long.parseLong(asServer.getConfigurationNode(TENANT_IDLE_XPATH).getNodeValue()) * 60 * 1000;\n+        WEB_APP_IDLE_TIME =\n+                Long.parseLong(asServer.getConfigurationNode(WEB_APP_IDLE_XPATH).getNodeValue()) * 60 * 1000;\n+\n+        ARTIFACTS_LOCATION =\n+                TestConfigurationProvider.getResourceLocation() + File.separator + \"artifacts\" + File.separator +\n+                        \"AS\" + File.separator + \"ghost\" + File.separator;\n+\n+\n+        String tenantInfoServiceArtifactLocation =\n+                ARTIFACTS_LOCATION + TENANT_INFO_SERVICE_FILE_NAME;\n+\n+\n+        String carbonArtifactLocation = ARTIFACTS_LOCATION + CARBON_XML;\n+\n+        File sourceFile = new File(carbonArtifactLocation);\n+        File targetFile = new File(CARBON_REPOSITORY_LOCATION);\n+\n+        SUPER_TENANT_DOMAIN =\n+                new AutomationContext(PRODUCT_GROUP_NAME, INSTANCE_NAME, SUPER_TENANT_DOMAIN_KEY, USER_KEY).getSuperTenant().getDomain();\n+\n+        TENANT_DOMAIN_1 =\n+                new AutomationContext(PRODUCT_GROUP_NAME, INSTANCE_NAME, TENANT_DOMAIN_1_kEY, USER_KEY).getContextTenant().getDomain();\n+\n+        TENANT_DOMAIN_2 =\n+                new AutomationContext(PRODUCT_GROUP_NAME, INSTANCE_NAME, TENANT_DOMAIN_2_KEY, USER_KEY).getContextTenant().getDomain();\n+\n+\n+        serverManager.applyConfigurationWithoutRestart(sourceFile, targetFile, true);\n+        log.info(\"carbon.xml replaced with :\" + carbonArtifactLocation);\n+\n+        webAppAdminClient.warFileUplaoder(tenantInfoServiceArtifactLocation);\n+        serverManager.restartGracefully();\n+        log.info(\"Server Restarted after applying carbon.xml and tenant information utility web application\");\n+\n+    }\n+\n+\n+    /**\n+     * This method will do a REST  GET call to the tenant-info-service (deployed by init() method) to get the tenant\n+     * status information\n+     *\n+     * @param tenantDomain -  Domain Name of the tenant.\n+     * @return TenantStatus - a JSON object that contains whether the configuration context is loaded or not.\n+     * @throws LazyLoadingTestException - Exception throws when send the Get request and retrieve the JSON data from response.\n+     */\n+    protected TenantStatus getTenantStatus(String tenantDomain) throws LazyLoadingTestException {\n+\n+        TenantStatus tenantStatus;\n+        String requestUrl = webAppURL + \"/\" + IS_TENANT_LOADED_METHOD_URL + \"/\" + tenantDomain;\n+        try {\n+            HttpResponse response = HttpURLConnectionClient.sendGetRequest(requestUrl, null);\n+            JSONObject tenantStatusJSON = new JSONObject(response.getData());\n+            tenantStatus =\n+                    new TenantStatus(tenantStatusJSON.getJSONObject(\"TenantStatus\").getBoolean(\"tenantContextLoaded\"));\n+        } catch (IOException ioException) {\n+            String customErrorMessage = \"IOException when sending the Get request to:\" + requestUrl;\n+            log.error(customErrorMessage, ioException);\n+            throw new LazyLoadingTestException(customErrorMessage, ioException);\n+        } catch (JSONException jsonException) {\n+            String customErrorMessage = \"JSONException when retrieving the values from json object TenantStatus\" + requestUrl;\n+            log.error(customErrorMessage, jsonException);\n+            throw new LazyLoadingTestException(customErrorMessage, jsonException);\n+        }\n+\n+        return tenantStatus;\n+    }\n+\n+    /**\n+     * This method will do a REST  GET call to the tenant-info-service (deployed by init() method) to get the web-app\n+     * status information.\n+     * IT will return the  the deployment status of given web application of given tenant is loaded in Ghost form.\n+     *\n+     * @param tenantDomain -  Domain Name of the tenant.\n+     * @param webAppName   -  Name of the Web Application\n+     * @return WebAppStatus -  which include Tenant status, whether the web-app is started or not, whether the web-app is in\n+     * ghost mode or not.\n+     * @throws LazyLoadingTestException - Exception throws when send the Get request and retrieve the JSON data from response.\n+     */\n+    protected WebAppStatus getWebAppStatus(String tenantDomain, String webAppName) throws LazyLoadingTestException {\n+        String requestUrl = webAppURL + \"/\" + IS_WEB_APP_LOADED_METHOD_URL + \"/\" + tenantDomain + \"/\" + webAppName;\n+        WebAppStatus webAppStatus;\n+        try {\n+\n+            HttpResponse response = HttpURLConnectionClient.sendGetRequest(requestUrl, null);\n+            JSONObject webAppStatusJSON = new JSONObject(response.getData()).getJSONObject(\"WebAppStatus\");\n+            boolean isTenantLoaded = webAppStatusJSON.getJSONObject(\"tenantStatus\").getBoolean(\"tenantContextLoaded\");\n+            boolean isWebAppStarted = webAppStatusJSON.getBoolean(\"webAppStarted\");\n+            boolean isWebAppGhost = webAppStatusJSON.getBoolean(\"webAppGhost\");\n+            webAppStatus = new WebAppStatus(new TenantStatus(isTenantLoaded), isWebAppStarted, isWebAppGhost);\n+        } catch (IOException ioException) {\n+            String customErrorMessage =\n+                    \"IOException when sending the Get request to:\" + requestUrl;\n+            log.error(customErrorMessage, ioException);\n+            throw new LazyLoadingTestException(customErrorMessage, ioException);\n+        } catch (JSONException jsonException) {\n+            String customErrorMessage = \"JSONException when retrieving the values from json object WebAppStatus\" + requestUrl;\n+            log.error(customErrorMessage, jsonException);\n+            throw new LazyLoadingTestException(customErrorMessage, jsonException);\n+        }\n+\n+        return webAppStatus;\n+\n+    }\n+\n+\n+    /**\n+     * Check the given Jaggery application is deployed correctly. This method is wait for 90 seconds\n+     * for deployment of jaggery application and each 500 milliseconds  of wait it will check the\n+     * deployment status.\n+     *\n+     * @param appName - Name of the application.\n+     * @return boolean - true if the application is get deployed before the maximum wait time of 90 seconds.\n+     * @throws LazyLoadingTestException - Exception throws when creating WebAppAdminClient.\n+     */\n+    protected boolean isJaggeryAppDeployed(String appName) throws LazyLoadingTestException {\n+        int deploymentDelayInMilliseconds = 90 * 1000;\n+        log.info(\"waiting \" + deploymentDelayInMilliseconds + \" millis for Service deployment \" + appName);\n+        WebAppAdminClient webAppAdminClient;\n+        List<String> webAppList;\n+        List<String> faultyWebAppList;\n+        long startTime;\n+        long time;\n+        boolean isWebAppDeployed = false;\n+        boolean doLoop = true;\n+\n+        try {\n+            webAppAdminClient = new WebAppAdminClient(backendURL, sessionCookie);\n+        } catch (AxisFault axisFault) {\n+            String customErrorMessage =\n+                    \"AxisFault Exception  when creating WebAppAdminClient object. backend URL:\" + backendURL +\n+                            \" Session Cookie: \" + sessionCookie;\n+            log.error(customErrorMessage, axisFault);\n+            throw new LazyLoadingTestException(customErrorMessage, axisFault);\n+        }\n+\n+        startTime = System.currentTimeMillis();\n+\n+        while (((time = (System.currentTimeMillis() - startTime)) < deploymentDelayInMilliseconds) && doLoop) {\n+            //Get the web app list\n+            try {\n+                webAppList = webAppAdminClient.getWebApplist(appName);\n+                faultyWebAppList = webAppAdminClient.getFaultyWebAppList(appName);\n+            } catch (RemoteException remoteException) {\n+                String customErrorMessage = \"remoteException Exception when calling methods in WebAppAdminClient\";\n+                log.error(customErrorMessage, remoteException);\n+                throw new LazyLoadingTestException(customErrorMessage, remoteException);\n+            }\n+            // Find given app in faulty app list. If found return the loop with isWebAppDeployed=false\n+            for (String faultWebAppName : faultyWebAppList) {\n+                if (faultWebAppName.equalsIgnoreCase(appName)) {\n+                    isWebAppDeployed = false;\n+                    log.info(appName + \"- Jaggery Application is faulty\");\n+                    doLoop = false;\n+                }\n+            }\n+            // Find the given app in web app list. If found return the loop with isWebAppDeployed=true\n+            for (String webAppName : webAppList) {\n+                if (webAppName.equalsIgnoreCase(appName)) {\n+                    isWebAppDeployed = true;\n+                    log.info(appName + \" Jaggery Application deployed in \" + time + \" millis\");\n+                    doLoop = false;\n+                }\n+            }\n+            try {\n+                Thread.sleep(500);\n+            } catch (InterruptedException interruptedException) {\n+                String customErrorMessage = \"InterruptedException occurs when sleeping 1000 milliseconds and while\" +\n+                        \" waiting for Jaggery Application to get deployed \";\n+                log.warn(customErrorMessage, interruptedException);\n+            }\n+        }\n+        return isWebAppDeployed;\n+    }\n+\n+    /**\n+     * Check the given Carbon application is deployed correctly. This method is wait for 90 seconds\n+     * for deployment of Carbon application and each 500 milliseconds  of wait it will check the\n+     * deployment status.\n+     *\n+     * @param appName - Name of the application.\n+     * @return boolean - true if the application is listed.\n+     * @throws LazyLoadingTestException - Exception throws when creating WebAppAdminClient.\n+     */\n+    protected boolean isCarbonAppListed(String appName) throws LazyLoadingTestException {\n+        int deploymentDelayInMilliseconds = 90 * 1000;\n+        log.info(\"waiting \" + deploymentDelayInMilliseconds + \" millis for Carbon Application to list\" + appName);\n+        ApplicationAdminClient appAdminClient;\n+        String[] appList;\n+        boolean doLoop = true;\n+        boolean isAppListed = false;\n+        long time;\n+        long startTime;\n+\n+        try {\n+            appAdminClient = new ApplicationAdminClient(backendURL, sessionCookie);\n+        } catch (AxisFault axisFault) {\n+            String customErrorMessage = \"AxisFault Exception  when creating WebAppAdminClient object. backend URL:\" +\n+                    backendURL + \" Session Cookie: \" + sessionCookie;\n+            log.error(customErrorMessage, axisFault);\n+            throw new LazyLoadingTestException(customErrorMessage, axisFault);\n+        }\n+\n+        startTime = System.currentTimeMillis();\n+        while (((time = (System.currentTimeMillis() - startTime)) < deploymentDelayInMilliseconds) && doLoop) {\n+            //List all applications\n+            try {\n+                appList = appAdminClient.listAllApplications();\n+            } catch (ApplicationAdminExceptionException applicationAdminExceptionException) {\n+                String customErrorMessage = \"ApplicationAdminExceptionException Exception when when calling \" +\n+                        \"listAllApplications() methods in WebAppAdminClient\";\n+                log.error(customErrorMessage, applicationAdminExceptionException);\n+                throw new LazyLoadingTestException(customErrorMessage, applicationAdminExceptionException);\n+            } catch (RemoteException remoteException) {\n+                String customErrorMessage =\n+                        \"RemoteException Exception when calling listAllApplications() methods in WebAppAdminClient\";\n+                log.error(customErrorMessage, remoteException);\n+                throw new LazyLoadingTestException(customErrorMessage, remoteException);\n+            }\n+            //Find given application is available in app list. if found  return isAppListed = true or else with false\n+            if (Arrays.asList(appList).contains(appName)) {\n+                isAppListed = true;\n+                log.info(appName + \" Carbon Application is listed in\" + time + \" millis\");\n+                doLoop = false;\n+            }\n+\n+            try {\n+                Thread.sleep(500);\n+            } catch (InterruptedException interruptedException) {\n+                String customErrorMessage = \"InterruptedException occurs when sleeping 500 milliseconds and while\" +\n+                        \" waiting for Carbon Application to  listed in ApplicationAdminClient.\";\n+                log.warn(customErrorMessage, interruptedException);\n+            }\n+        }\n+        return isAppListed;\n+    }\n+\n+\n+    /**\n+     * Tenant admin user login functionality.\n+     *\n+     * @param domainKey -  Domain key of the tenant.\n+     * @throws LazyLoadingTestException - Exception throws when  creating the AutomationContext and login() method of LoginLogoutClient.java\n+     */\n+    protected void loginAsTenantAdmin(String domainKey) throws LazyLoadingTestException {\n+        try {\n+            AutomationContext automationContext = new AutomationContext(PRODUCT_GROUP_NAME, INSTANCE_NAME, domainKey,\n+                    \"admin\");\n+            hostURL = automationContext.getInstance().getHosts().get(\"default\");\n+            LoginLogoutClient loginLogoutClient1 = new LoginLogoutClient(automationContext);\n+            sessionCookie = loginLogoutClient1.login();\n+        } catch (XPathExpressionException xPathExpressionException) {\n+            String customErrorMessage = \"XPathExpressionException exception  when login as tenant admin.\";\n+            log.error(customErrorMessage, xPathExpressionException);\n+            throw new LazyLoadingTestException(customErrorMessage, xPathExpressionException);\n+\n+        } catch (IOException ioException) {\n+            String customErrorMessage = \"IOException exception  when login as tenant admin.\";\n+            log.error(customErrorMessage, ioException);\n+            throw new LazyLoadingTestException(customErrorMessage, ioException);\n+\n+        } catch (SAXException saxException) {\n+            String customErrorMessage = \"SAXException exception  when login as tenant admin.\";\n+            log.error(customErrorMessage, saxException);\n+            throw new LazyLoadingTestException(customErrorMessage, saxException);\n+\n+        } catch (XMLStreamException xmlStreamException) {\n+            String customErrorMessage = \"XMLStreamException exception  when login as tenant admin.\";\n+            log.error(customErrorMessage, xmlStreamException);\n+            throw new LazyLoadingTestException(customErrorMessage, xmlStreamException);\n+\n+        } catch (LoginAuthenticationExceptionException loginAuthenticationExceptionException) {\n+            String customErrorMessage = \"LoginAuthenticationExceptionException exception  when login as tenant admin.\";\n+            log.error(customErrorMessage, loginAuthenticationExceptionException);\n+            throw new LazyLoadingTestException(customErrorMessage, loginAuthenticationExceptionException);\n+\n+        } catch (URISyntaxException uriSyntaxException) {\n+            String customErrorMessage = \"URISyntaxException exception  when login as tenant admin.\";\n+            log.error(customErrorMessage, uriSyntaxException);\n+            throw new LazyLoadingTestException(customErrorMessage, uriSyntaxException);\n+\n+        }\n+\n+\n+    }\n+\n+    /**\n+     * check the tenant is unloading functionality when tenant is idle more than configured tenant idle time.\n+     * This method will wait additional MAX_THRESHOLD_TIME milliseconds to  system to unload the tenant. it will log\n+     * total idle time taken to unload.\n+     *\n+     * @param tenantDomain - Tenant domain that need to check for unloading.\n+     * @return boolean - true if tenant is unload after tenant idle time + additional MAX_THRESHOLD_TIME milliseconds if not return\n+     * false\n+     * @throws LazyLoadingTestException - Exception throws when  calling th REST call to get tenant in formation.\n+     */\n+    protected boolean checkTenantAutoUnloading(String tenantDomain) throws LazyLoadingTestException {\n+        boolean isTenantUnloaded = false;\n+        long totalSleepTime = 0;\n+        log.info(\"Sleeping  for \" + TENANT_IDLE_TIME + \" milliseconds (Tenant idle tome).\");\n+\n+        try {\n+            Thread.sleep(TENANT_IDLE_TIME);\n+        } catch (InterruptedException interruptedException) {\n+            String customErrorMessage = \"InterruptedException occurs when sleeping for TENANT_IDLE_TIME\" +","path":"modules/integration/tests-integration/lazy-loading-test/src/test/java/org/wso2/appserver/integration/lazy/loading/LazyLoadingBaseTest.java","position":420,"original_position":420,"commit_id":"413fec4cfdd48be3529ef7b59a984535ea489f8c","original_commit_id":"413fec4cfdd48be3529ef7b59a984535ea489f8c","user":{"login":"warunap","id":7383632,"avatar_url":"https://avatars.githubusercontent.com/u/7383632?v=3","gravatar_id":"","url":"https://api.github.com/users/warunap","html_url":"https://github.com/warunap","followers_url":"https://api.github.com/users/warunap/followers","following_url":"https://api.github.com/users/warunap/following{/other_user}","gists_url":"https://api.github.com/users/warunap/gists{/gist_id}","starred_url":"https://api.github.com/users/warunap/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/warunap/subscriptions","organizations_url":"https://api.github.com/users/warunap/orgs","repos_url":"https://api.github.com/users/warunap/repos","events_url":"https://api.github.com/users/warunap/events{/privacy}","received_events_url":"https://api.github.com/users/warunap/received_events","type":"User","site_admin":false},"body":"explain why we dont throw the exception here","created_at":"2015-04-20T04:39:45Z","updated_at":"2015-04-20T04:39:45Z","html_url":"https://github.com/wso2/product-as/pull/48#discussion_r28663777","pull_request_url":"https://api.github.com/repos/wso2/product-as/pulls/48","_links":{"self":{"href":"https://api.github.com/repos/wso2/product-as/pulls/comments/28663777"},"html":{"href":"https://github.com/wso2/product-as/pull/48#discussion_r28663777"},"pull_request":{"href":"https://api.github.com/repos/wso2/product-as/pulls/48"}}},"pull_request":{"url":"https://api.github.com/repos/wso2/product-as/pulls/48","id":30141258,"html_url":"https://github.com/wso2/product-as/pull/48","diff_url":"https://github.com/wso2/product-as/pull/48.diff","patch_url":"https://github.com/wso2/product-as/pull/48.patch","issue_url":"https://api.github.com/repos/wso2/product-as/issues/48","number":48,"state":"open","locked":false,"title":"Implementation of  Ghost deployment(Lazy Loading) test cases for WSO2 AS (JIRI TA-591)","user":{"login":"sanethd","id":9712144,"avatar_url":"https://avatars.githubusercontent.com/u/9712144?v=3","gravatar_id":"","url":"https://api.github.com/users/sanethd","html_url":"https://github.com/sanethd","followers_url":"https://api.github.com/users/sanethd/followers","following_url":"https://api.github.com/users/sanethd/following{/other_user}","gists_url":"https://api.github.com/users/sanethd/gists{/gist_id}","starred_url":"https://api.github.com/users/sanethd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sanethd/subscriptions","organizations_url":"https://api.github.com/users/sanethd/orgs","repos_url":"https://api.github.com/users/sanethd/repos","events_url":"https://api.github.com/users/sanethd/events{/privacy}","received_events_url":"https://api.github.com/users/sanethd/received_events","type":"User","site_admin":false},"body":"Implementation of  Ghost deployment(Lazy Loading) test cases for WSO2 AS (JIRI TA-591)\r\nthis includes\r\n1) Ghost deployment (Lazy Loading) test caes for WSO2 AS.\r\n2) Rest web service artefact  to retrieve the web-app/tenant lazy loading information.\r\n3) add new  \"tests-common\" module in between  \"modules/integration\" and  other common sub modules like \"tests-common/admin-client\",\"tests-common/ui-pages\",\"tests-common/integration-test-utils\". \r\n ","created_at":"2015-02-27T04:34:54Z","updated_at":"2015-04-20T04:39:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7406aa8f7535d2daff089ede4b9bbe3d5b8276c7","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/wso2/product-as/pulls/48/commits","review_comments_url":"https://api.github.com/repos/wso2/product-as/pulls/48/comments","review_comment_url":"https://api.github.com/repos/wso2/product-as/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wso2/product-as/issues/48/comments","statuses_url":"https://api.github.com/repos/wso2/product-as/statuses/413fec4cfdd48be3529ef7b59a984535ea489f8c","head":{"label":"sanethd:master","ref":"master","sha":"413fec4cfdd48be3529ef7b59a984535ea489f8c","user":{"login":"sanethd","id":9712144,"avatar_url":"https://avatars.githubusercontent.com/u/9712144?v=3","gravatar_id":"","url":"https://api.github.com/users/sanethd","html_url":"https://github.com/sanethd","followers_url":"https://api.github.com/users/sanethd/followers","following_url":"https://api.github.com/users/sanethd/following{/other_user}","gists_url":"https://api.github.com/users/sanethd/gists{/gist_id}","starred_url":"https://api.github.com/users/sanethd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sanethd/subscriptions","organizations_url":"https://api.github.com/users/sanethd/orgs","repos_url":"https://api.github.com/users/sanethd/repos","events_url":"https://api.github.com/users/sanethd/events{/privacy}","received_events_url":"https://api.github.com/users/sanethd/received_events","type":"User","site_admin":false},"repo":{"id":30750976,"name":"product-as","full_name":"sanethd/product-as","owner":{"login":"sanethd","id":9712144,"avatar_url":"https://avatars.githubusercontent.com/u/9712144?v=3","gravatar_id":"","url":"https://api.github.com/users/sanethd","html_url":"https://github.com/sanethd","followers_url":"https://api.github.com/users/sanethd/followers","following_url":"https://api.github.com/users/sanethd/following{/other_user}","gists_url":"https://api.github.com/users/sanethd/gists{/gist_id}","starred_url":"https://api.github.com/users/sanethd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sanethd/subscriptions","organizations_url":"https://api.github.com/users/sanethd/orgs","repos_url":"https://api.github.com/users/sanethd/repos","events_url":"https://api.github.com/users/sanethd/events{/privacy}","received_events_url":"https://api.github.com/users/sanethd/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sanethd/product-as","description":"","fork":true,"url":"https://api.github.com/repos/sanethd/product-as","forks_url":"https://api.github.com/repos/sanethd/product-as/forks","keys_url":"https://api.github.com/repos/sanethd/product-as/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sanethd/product-as/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sanethd/product-as/teams","hooks_url":"https://api.github.com/repos/sanethd/product-as/hooks","issue_events_url":"https://api.github.com/repos/sanethd/product-as/issues/events{/number}","events_url":"https://api.github.com/repos/sanethd/product-as/events","assignees_url":"https://api.github.com/repos/sanethd/product-as/assignees{/user}","branches_url":"https://api.github.com/repos/sanethd/product-as/branches{/branch}","tags_url":"https://api.github.com/repos/sanethd/product-as/tags","blobs_url":"https://api.github.com/repos/sanethd/product-as/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sanethd/product-as/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sanethd/product-as/git/refs{/sha}","trees_url":"https://api.github.com/repos/sanethd/product-as/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sanethd/product-as/statuses/{sha}","languages_url":"https://api.github.com/repos/sanethd/product-as/languages","stargazers_url":"https://api.github.com/repos/sanethd/product-as/stargazers","contributors_url":"https://api.github.com/repos/sanethd/product-as/contributors","subscribers_url":"https://api.github.com/repos/sanethd/product-as/subscribers","subscription_url":"https://api.github.com/repos/sanethd/product-as/subscription","commits_url":"https://api.github.com/repos/sanethd/product-as/commits{/sha}","git_commits_url":"https://api.github.com/repos/sanethd/product-as/git/commits{/sha}","comments_url":"https://api.github.com/repos/sanethd/product-as/comments{/number}","issue_comment_url":"https://api.github.com/repos/sanethd/product-as/issues/comments{/number}","contents_url":"https://api.github.com/repos/sanethd/product-as/contents/{+path}","compare_url":"https://api.github.com/repos/sanethd/product-as/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sanethd/product-as/merges","archive_url":"https://api.github.com/repos/sanethd/product-as/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sanethd/product-as/downloads","issues_url":"https://api.github.com/repos/sanethd/product-as/issues{/number}","pulls_url":"https://api.github.com/repos/sanethd/product-as/pulls{/number}","milestones_url":"https://api.github.com/repos/sanethd/product-as/milestones{/number}","notifications_url":"https://api.github.com/repos/sanethd/product-as/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sanethd/product-as/labels{/name}","releases_url":"https://api.github.com/repos/sanethd/product-as/releases{/id}","created_at":"2015-02-13T10:06:11Z","updated_at":"2015-03-14T04:48:40Z","pushed_at":"2015-03-14T04:48:38Z","git_url":"git://github.com/sanethd/product-as.git","ssh_url":"git@github.com:sanethd/product-as.git","clone_url":"https://github.com/sanethd/product-as.git","svn_url":"https://github.com/sanethd/product-as","homepage":null,"size":42079,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"wso2:master","ref":"master","sha":"fa3b7e20eecdc754549a4b4211e84ac76ae93385","user":{"login":"wso2","id":533043,"avatar_url":"https://avatars.githubusercontent.com/u/533043?v=3","gravatar_id":"","url":"https://api.github.com/users/wso2","html_url":"https://github.com/wso2","followers_url":"https://api.github.com/users/wso2/followers","following_url":"https://api.github.com/users/wso2/following{/other_user}","gists_url":"https://api.github.com/users/wso2/gists{/gist_id}","starred_url":"https://api.github.com/users/wso2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wso2/subscriptions","organizations_url":"https://api.github.com/users/wso2/orgs","repos_url":"https://api.github.com/users/wso2/repos","events_url":"https://api.github.com/users/wso2/events{/privacy}","received_events_url":"https://api.github.com/users/wso2/received_events","type":"Organization","site_admin":false},"repo":{"id":16947368,"name":"product-as","full_name":"wso2/product-as","owner":{"login":"wso2","id":533043,"avatar_url":"https://avatars.githubusercontent.com/u/533043?v=3","gravatar_id":"","url":"https://api.github.com/users/wso2","html_url":"https://github.com/wso2","followers_url":"https://api.github.com/users/wso2/followers","following_url":"https://api.github.com/users/wso2/following{/other_user}","gists_url":"https://api.github.com/users/wso2/gists{/gist_id}","starred_url":"https://api.github.com/users/wso2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wso2/subscriptions","organizations_url":"https://api.github.com/users/wso2/orgs","repos_url":"https://api.github.com/users/wso2/repos","events_url":"https://api.github.com/users/wso2/events{/privacy}","received_events_url":"https://api.github.com/users/wso2/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wso2/product-as","description":"","fork":false,"url":"https://api.github.com/repos/wso2/product-as","forks_url":"https://api.github.com/repos/wso2/product-as/forks","keys_url":"https://api.github.com/repos/wso2/product-as/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wso2/product-as/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wso2/product-as/teams","hooks_url":"https://api.github.com/repos/wso2/product-as/hooks","issue_events_url":"https://api.github.com/repos/wso2/product-as/issues/events{/number}","events_url":"https://api.github.com/repos/wso2/product-as/events","assignees_url":"https://api.github.com/repos/wso2/product-as/assignees{/user}","branches_url":"https://api.github.com/repos/wso2/product-as/branches{/branch}","tags_url":"https://api.github.com/repos/wso2/product-as/tags","blobs_url":"https://api.github.com/repos/wso2/product-as/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wso2/product-as/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wso2/product-as/git/refs{/sha}","trees_url":"https://api.github.com/repos/wso2/product-as/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wso2/product-as/statuses/{sha}","languages_url":"https://api.github.com/repos/wso2/product-as/languages","stargazers_url":"https://api.github.com/repos/wso2/product-as/stargazers","contributors_url":"https://api.github.com/repos/wso2/product-as/contributors","subscribers_url":"https://api.github.com/repos/wso2/product-as/subscribers","subscription_url":"https://api.github.com/repos/wso2/product-as/subscription","commits_url":"https://api.github.com/repos/wso2/product-as/commits{/sha}","git_commits_url":"https://api.github.com/repos/wso2/product-as/git/commits{/sha}","comments_url":"https://api.github.com/repos/wso2/product-as/comments{/number}","issue_comment_url":"https://api.github.com/repos/wso2/product-as/issues/comments{/number}","contents_url":"https://api.github.com/repos/wso2/product-as/contents/{+path}","compare_url":"https://api.github.com/repos/wso2/product-as/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wso2/product-as/merges","archive_url":"https://api.github.com/repos/wso2/product-as/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wso2/product-as/downloads","issues_url":"https://api.github.com/repos/wso2/product-as/issues{/number}","pulls_url":"https://api.github.com/repos/wso2/product-as/pulls{/number}","milestones_url":"https://api.github.com/repos/wso2/product-as/milestones{/number}","notifications_url":"https://api.github.com/repos/wso2/product-as/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wso2/product-as/labels{/name}","releases_url":"https://api.github.com/repos/wso2/product-as/releases{/id}","created_at":"2014-02-18T11:57:09Z","updated_at":"2015-03-05T11:09:15Z","pushed_at":"2015-04-10T16:25:11Z","git_url":"git://github.com/wso2/product-as.git","ssh_url":"git@github.com:wso2/product-as.git","clone_url":"https://github.com/wso2/product-as.git","svn_url":"https://github.com/wso2/product-as","homepage":null,"size":45474,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":36,"mirror_url":null,"open_issues_count":16,"forks":36,"open_issues":16,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wso2/product-as/pulls/48"},"html":{"href":"https://github.com/wso2/product-as/pull/48"},"issue":{"href":"https://api.github.com/repos/wso2/product-as/issues/48"},"comments":{"href":"https://api.github.com/repos/wso2/product-as/issues/48/comments"},"review_comments":{"href":"https://api.github.com/repos/wso2/product-as/pulls/48/comments"},"review_comment":{"href":"https://api.github.com/repos/wso2/product-as/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wso2/product-as/pulls/48/commits"},"statuses":{"href":"https://api.github.com/repos/wso2/product-as/statuses/413fec4cfdd48be3529ef7b59a984535ea489f8c"}}}}