Package org.auraframework.test

Source Code of org.auraframework.test.AuraHttpTestCase

/*
* Copyright (C) 2013 salesforce.com, inc.
*
* 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 org.auraframework.test;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.CharEncoding;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.auraframework.Aura;
import org.auraframework.def.ActionDef;
import org.auraframework.def.ApplicationDef;
import org.auraframework.def.BaseComponentDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.http.AuraBaseServlet;
import org.auraframework.instance.Action;
import org.auraframework.instance.InstanceStack;
import org.auraframework.system.AuraContext;
import org.auraframework.system.AuraContext.Format;
import org.auraframework.system.AuraContext.Mode;
import org.auraframework.system.LoggingContext.KeyValueLogger;
import org.auraframework.throwable.AuraExecutionException;
import org.auraframework.throwable.quickfix.QuickFixException;
import org.auraframework.util.json.Json;
import org.auraframework.util.json.JsonReader;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
* Base class with some helper methods specific to Aura.
*/
public abstract class AuraHttpTestCase extends IntegrationTestCase {
     
    public AuraHttpTestCase(String name) {
        super(name);
    }

    /**
     * Given a URL to post a GET request, this method compares the actual status code of the response with an expected
     * status code.
     *
     * @param msg Error message that should be displayed if the actual response does not match the expected response
     * @param url URL to be used to execute the GET request
     * @param statusCode expected status code of response
     * @throws Exception
     */
    protected void assertUrlResponse(String msg, String url, int statusCode)
            throws Exception {
        HttpGet get = obtainGetMethod(new URI(null, url, null).toString());
        HttpResponse httpResponse = perform(get);
        EntityUtils.consume(httpResponse.getEntity());
        get.releaseConnection();
        int status = getStatusCode(httpResponse);
        assertEquals(msg, statusCode, status);
    }
   
    /**
     * Helper method to check that a response has the default X-FRAME-OPTIONS and
     * Content-Security-Policy headers.  If your test doesn't use the default security policy,
     * you get to roll your own validation of that, of course.
     *
     * Asserts if anything is wrong.
     *
     * @param response
     * @param guarded  If {@code true}, check that we HAVE headers.  If {@code false}, check that they are absent.
     * @param allowInline Allows inline script-src and style-src
     */
    protected void assertDefaultAntiClickjacking(HttpResponse response, boolean guarded, boolean allowInline) {
        // Check default content security
        Header[] headers = response.getHeaders("X-FRAME-OPTIONS");
        if (guarded) {
            assertEquals("wrong number of X-FRAME-OPTIONS header lines", 1, headers.length);
            assertEquals("SAMEORIGIN", headers[0].getValue());
        } else {
            assertEquals("wrong number of X-FRAME-OPTIONS header lines", 0, headers.length);
        }
        if (guarded) {
            Map<String, String> csp = getCSP(response);
            headers = response.getHeaders("Content-Type");
            assertEquals("frame-ancestors is wrong", "'self'", csp.get("frame-ancestors"));
            if (allowInline) {
                assertEquals("script-src is wrong", "'self' chrome-extension: 'unsafe-eval' 'unsafe-inline'", csp.get("script-src"));
                assertEquals("style-src is wrong", "'self' chrome-extension: 'unsafe-inline'", csp.get("style-src"));
            } else {
                assertEquals("script-src is wrong", "'self' chrome-extension:", csp.get("script-src"));
                assertEquals("style-src is wrong", "'self' chrome-extension:", csp.get("style-src"));
            }
            // These maybe aren't strictly "anti-clickjacking", but since we're testing the rest of the default CSP:
            assertEquals("font-src is wrong", "*", csp.get("font-src"));
            assertEquals("img-src is wrong", "*", csp.get("img-src"));
            assertEquals("media-src is wrong", "*", csp.get("media-src"));
            assertEquals("default-src is wrong", "'self'", csp.get("default-src"));
            assertEquals("object-src is wrong", "'self'", csp.get("object-src"));
            assertEquals("connect-src is wrong", "'self' http://invalid.salesforce.com", csp.get("connect-src"));
        } else {
            headers = response.getHeaders("Content-Security-Policy");
            assertEquals(0, headers.length);
        }
    }

    /**
     * Helper to take the Content-Security-Policy header and break it into its individual components.
     * If the header is missing, this will fail the test with an assertion.  Otherwise, a map keyed by
     * the various CSP directives (script-src, style-src, etc.) with the literal values of each
     * directive is returned.
     *
     * @param response
     * @return a map of directive to value.
     */
    protected Map<String, String> getCSP(HttpResponse response) {
        Header[] headers = response.getHeaders("Content-Security-Policy");
        assertEquals("wrong number of CSP header lines", 1, headers.length);
        String[] split = headers[0].getValue().split(";");
        Map<String, String> csp = new HashMap<String, String>();
        for (String term : split) {
            term = term.trim();
            String word = term.substring(0, term.indexOf(' '));
            csp.put(word, term.substring(word.length() + 1));
        }
        return csp;
    }

    protected String getHost() throws Exception {
        return getTestServletConfig().getBaseUrl().getHost();
    }

    /**
     * Clear cookies from httpclient cookie store
     *
     * @throws Exception
     */
    protected void clearCookies() throws Exception {
        getCookieStore().clear();
    }

    /**
     * Adds cookie with name and value
     *
     * @param name cookie name
     * @param value cookie value
     * @throws Exception
     */
    protected void addCookie(String name, String value) throws Exception {
        BasicClientCookie cookie = makeCookie(name, value);
        addCookie(cookie);
    }

    /**
     * Adds cookie to httpclient cookie store
     *
     * @param domain cookie domain
     * @param name cookie name
     * @param value cookie value
     * @param path cookie path
     * @throws Exception
     */
    protected void addCookie(String domain, String name, String value,
            String path) throws Exception {
        BasicClientCookie cookie = makeCookie(domain, name, value, path);
        addCookie(cookie);
    }

    /**
     * Adds cookie to httpclient cookie store
     *
     * @param cookie cookie
     * @throws Exception
     */
    protected void addCookie(Cookie cookie) throws Exception {
        getCookieStore().addCookie(cookie);
    }

    /**
     * Creates HttpContext with httpclient cookie store. Allows cookies to be part of specific request method.
     *
     * @return http context
     * @throws Exception
     */
    protected HttpContext getHttpCookieContext() throws Exception {
        CookieStore cookieStore = getCookieStore();
        HttpContext localContext = new BasicHttpContext();
        localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
        return localContext;
    }

    /**
     * Checks there is no cookie in httpclient cookie store
     *
     * @param domain cookie domain
     * @param name cookie name
     * @param path cookie path
     * @throws Exception
     */
    protected void assertNoCookie(String domain, String name, String path)
            throws Exception {
        Cookie expected = makeCookie(domain, name, null, path);
        for (Cookie cookie : getCookies()) {
            if (expected.equals(cookie)) {
                fail("Cookie was not deleted: " + cookie);
            }
        }
    }

    /**
     * Checks for cookie
     *
     * @param domain cookie domain
     * @param name cookie name
     * @param value cookie value
     * @param path cookie path
     * @throws Exception
     */
    protected void assertCookie(String domain, String name, String path,
            String value) throws Exception {
        Cookie expected = makeCookie(domain, name, value, path);
        for (Cookie cookie : getCookies()) {
            if (expected.equals(cookie)) {
                assertEquals("Wrong cookie value!", expected.getValue(),
                        cookie.getValue());
                return;
            }
        }
        fail("Missing cookie, expected " + expected);
    }

    /**
     * Creates cookie with only provided name and value
     *
     * @param name cookie name
     * @param value cookie value
     * @return
     */
    protected BasicClientCookie makeCookie(String name, String value)
            throws Exception {
        BasicClientCookie cookie = makeCookie(getHost(), name, value, "/");
        return cookie;
    }

    /**
     * Creates cookie
     *
     * @param domain cookie domain
     * @param name cookie name
     * @param value cookie value
     * @param path cookie path
     * @return
     */
    protected BasicClientCookie makeCookie(String domain, String name,
            String value, String path) {
        BasicClientCookie cookie = new BasicClientCookie(name, value);
        cookie.setDomain(domain);
        cookie.setPath(path);
        return cookie;
    }

    /**
     * Gets all cookies in httpclient cookie store
     *
     * @return cookies
     * @throws Exception
     */
    protected List<Cookie> getCookies() throws Exception {
        return getCookieStore().getCookies();
    }

    /**
     * Gets httpclient cookie store
     *
     * @return cookie store
     * @throws Exception
     */
    protected CookieStore getCookieStore() throws Exception {
        return ((DefaultHttpClient) getHttpClient()).getCookieStore();
    }

    /**
     * This gets a simple context string that uses a single preload.
     */
    protected String getSimpleContext(Format format, boolean modified)
            throws Exception {
        return getAuraTestingUtil().getContext(Mode.DEV, format,
                "auratest:test_SimpleServerRenderedPage", ApplicationDef.class,
                modified);
    }

    /**
     * Given the a path on the api server, return a {@link HttpPost} that has the appropriate headers and server name.
     *
     * @param path the relative path to the server, such as <tt>/services/Soap</tt> or
     *            <tt>/servlet/servlet.SForceMailMerge</tt>.
     * @param params a set of name value string pairs to use as parameters to the post call.
     * @return a {@link HttpPost}
     * @throws MalformedURLException if the path is invalid.
     * @throws URISyntaxException
     */
    protected HttpPost obtainPostMethod(String path, Map<String, String> params)
            throws MalformedURLException, URISyntaxException,
            UnsupportedEncodingException {
     
        HttpPost post = new HttpPost(getTestServletConfig().getBaseUrl()
                .toURI().resolve(path).toString());

        List<NameValuePair> nvps = Lists.newArrayList();
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry
                        .getValue()));
            }
            post.setEntity(new UrlEncodedFormEntity(nvps, CharEncoding.UTF_8));

        }
        return post;
    }

    /**
     * Given a path on the api server, return a {@link HttpGet} that has the appropriate headers and server name.
     *
     * @param path the relative path to the server, such as <tt>/services/Soap</tt> or
     *            <tt>/servlet/servlet.SForceMailMerge</tt> Follows redirects by default.
     * @return a {@link HttpGet}
     * @throws MalformedURLException if the path is invalid.
     * @throws URISyntaxException
     */
    protected HttpGet obtainGetMethod(String path)
            throws MalformedURLException, URISyntaxException {
        return obtainGetMethod(path, true, null);
    }

    protected HttpGet obtainGetMethod(String path, boolean followRedirects)
            throws MalformedURLException, URISyntaxException {
        return obtainGetMethod(path, followRedirects, null);
    }

    protected HttpGet obtainGetMethod(String path, Header[] headers)
            throws MalformedURLException, URISyntaxException {
        return obtainGetMethod(path, true, headers);
    }

    /**
     * Build a URL for a get from the given parameters with all the standard parameters set.
     *
     * This is a convenience function to make gets more consistent. It sets:
     * <ul>
     *   <li>aura.tag: the descriptor to get.</li>
     *   <li>aura.defType: the type of the descriptor.</li>
     *   <li>aura.context: the context, including
     *     <ul>
     *       <li>loaded: the descriptor + type from above.</li>
     *       <li>fwUID: the framework UID</li>
     *       <li>mode: from the parameters</li>
     *       <li>format: from the parameters</li>
     *     </ul>
     *   </li>
     * </ul>
     *
     * @param mode the Aura mode to use.
     * @param format the format (HTML vs JSON) to use
     * @param desc the name of the descriptor to set as the primary object.
     * @param type the type of descriptor.
     * @param params extra parameters to set.
     * @param headers extra headers.
     */
    protected HttpGet obtainAuraGetMethod(Mode mode, Format format,
            String desc, Class<? extends BaseComponentDef> type,
            Map<String, String> params, Header[] headers)
            throws QuickFixException, MalformedURLException, URISyntaxException {
        return obtainAuraGetMethod(mode, format, Aura.getDefinitionService()
                .getDefDescriptor(desc, type), params, headers);
    }

    /**
     * Build a URL for a get from the given parameters with all the standard parameters set from a descriptor.
     *
     * This is a convenience function to make gets more consistent. It sets:
     * <ul>
     *   <li>aura.tag: the name of the descriptor to get.</li>
     *   <li>aura.defType: the type of the descriptor.</li>
     *   <li>aura.context: the context, including
     *     <ul>
     *       <li>loaded: the descriptor + type from above.</li>
     *       <li>fwUID: the framework UID</li>
     *       <li>mode: from the parameters</li>
     *       <li>format: from the parameters</li>
     *     </ul>
     *   </li>
     * </ul>
     *
     * @param mode the Aura mode to use.
     * @param format the format (HTML vs JSON) to use
     * @param desc the descriptor to set as the primary object.
     * @param params extra parameters to set.
     * @param headers extra headers.
     */
    protected HttpGet obtainAuraGetMethod(Mode mode, Format format,
            DefDescriptor<? extends BaseComponentDef> desc,
            Map<String, String> params, Header[] headers)
            throws QuickFixException, MalformedURLException, URISyntaxException {
        List<NameValuePair> urlparams = Lists.newArrayList();
        urlparams.add(new BasicNameValuePair("aura.tag", String.format("%s:%s",
                desc.getNamespace(), desc.getName())));
        urlparams.add(new BasicNameValuePair("aura.defType", desc.getDefType()
                .toString()));

        for (Map.Entry<String, String> entry : params.entrySet()) {
            urlparams.add(new BasicNameValuePair(entry.getKey(), entry
                    .getValue()));
        }
        urlparams.add(new BasicNameValuePair("aura.context",
                getAuraTestingUtil().getContext(mode, format, desc, false)));
        String query = URLEncodedUtils.format(urlparams, "UTF-8");

        // final url Request to be send to server
        return obtainGetMethod("aura?" + query, true, headers);
    }

    public class ServerAction implements Action {

        private final ArrayList<String> qualifiedName;
        private ArrayList<Map<String, Object>> actionParams;
        private State state = State.NEW;
        private Object returnValue;
        private List<Object> errors;
        private HttpPost post;
        private String rawResponse;
        private String contextValue;
        private ArrayList<State> stateList = new ArrayList<>();
        private ArrayList<List<Object>> errorsList = new ArrayList<>();
        private ArrayList<Object> returnValueList = new ArrayList<>();
       

        public ServerAction(String qualifiedName, Map<String, Object> actionParams) {
          this.qualifiedName = new ArrayList<>();
          this.qualifiedName.add(qualifiedName);
          this.actionParams = new ArrayList<>();
            if(actionParams != null) {
              this.actionParams.add(actionParams);
            } else {
              this.actionParams.add(null);
            }
           
           
        }
        /**
         * Constructor for Server action using two array lists
         * Note that each list must be of equal length or will throw an IllegalArgumentException
         * @param qualifiedName
         * @param actionParams
         */
       
        public ServerAction(ArrayList<String> qualifiedName, ArrayList<Map<String,Object>> actionParams) {
         
          this.qualifiedName = qualifiedName;
          this.actionParams = actionParams;
          if(qualifiedName == null || actionParams == null) {
            throw new IllegalArgumentException("Cannot pass in a null list. You can pass in a list of null parameters if parameters are not yet known");
          }
          //Now will verify that we have actions and params
          if(this.qualifiedName.toArray().length != this.actionParams.toArray().length) {
            throw new IllegalArgumentException("Number of action names does not match number of action parameters");
          }
        }
        /**
         * Will insert the given key-value pair as a parameter in the first entry of the action parameters list.
         * Corresponds with the first entry in the qualified names list.
         * @param name Description of parameter
         * @param value Object of action parameter
         * @return Returns instance of Server Action
         */

        public ServerAction putParam(String name, Object value) {
            if (actionParams.get(0) == null) {
                actionParams.add(0,Maps.newHashMap(new HashMap<String,Object>()));
            }
            actionParams.get(0).put(name, value);
            return this;
        }
        /**
         * Will insert the given key-value pair as a parameter for the given qualified name.
         * Throws IllegalArguementException if qualified name is not found.
         * Cannot distinguish between multiple qualified names with the same name.
         * @param qualifiedName The name of the qualified Name you are adding a parameter for.
         * @param name Description of the parameter
         * @param value Object of the action parameter
         * @return Returns instance of Server Action
         */
       
        public ServerAction putParamUsingQName(String qualifiedName, String name, Object value) {
          int index = this.qualifiedName.indexOf(qualifiedName);
          if(index<0){
            throw new IllegalArgumentException("Qualified name does not exist.");
          }
          if(actionParams.get(index)==null) {
            actionParams.add(index,Maps.newHashMap(new HashMap<String,Object>()));
          }
          actionParams.get(index).put(name, value);
          return this;
        }

        public ServerAction setContext(String value) {
            contextValue = value;
            return this;
        }

        public HttpPost getPostMethod() throws Exception {
            if (post == null) {
             
                Map<String, Object> message = Maps.newHashMap();
                ArrayList<Map<String,Object>> actionInstanceArray = new ArrayList<>();
                for(int i = 0;i<qualifiedName.size();i++){
                  Map<String, Object> actionInstance = Maps.newHashMap();
                  actionInstance.put("descriptor", qualifiedName.get(i));
                  if(actionParams.get(i) != null) {
                    actionInstance.put("params", actionParams.get(i));
                  }
                  actionInstanceArray.add(actionInstance);
                }
                message.put("actions", actionInstanceArray.toArray());
                String jsonMessage = Json.serialize(message);
                Map<String, String> params = Maps.newHashMap();
                params.put("message", jsonMessage);
                params.put("aura.token", getTestServletConfig().getCsrfToken());

                if (contextValue != null) {
                    params.put("aura.context", contextValue);
                } else {
                    AuraContext context = Aura.getContextService().getCurrentContext();
                    if (context != null) {
                        StringBuilder sb = new StringBuilder();
                        context.setFrameworkUID(Aura.getConfigAdapter().getAuraFrameworkNonce());
                        Aura.getSerializationService().write(context, null, AuraContext.class, sb, "HTML");
                        params.put("aura.context", sb.toString());
                    } else {
                        params.put("aura.context", getSimpleContext(Format.JSON, false));
                    }
                }
                post = obtainPostMethod("/aura", params);
            }
            return post;
        }

        @Override
        public DefDescriptor<ActionDef> getDescriptor() {
            return Aura.getDefinitionService().getDefDescriptor(qualifiedName.get(0),
                    ActionDef.class);
        }
       
        public ArrayList<String> getQualifiedName() {
          return qualifiedName;
        }
       
        public DefDescriptor<ActionDef> getDescriptor(String qualifiedName) {
          return Aura.getDefinitionService().getDefDescriptor(qualifiedName,ActionDef.class);
        }

        @Override
        public void serialize(Json json) throws IOException {
            // Nothing for now
        }

        @Override
        public String getId() {
            return null;
        }

        @Override
        public void setId(String id) {
        }

        @SuppressWarnings("unchecked")
        @Override
        public void run() throws AuraExecutionException {
            try {
                HttpPost post = getPostMethod();
                HttpResponse response = getHttpClient().execute(post);
                assertEquals(HttpStatus.SC_OK, getStatusCode(response));
                rawResponse = getResponseBody(response);
                assertEquals(
                        AuraBaseServlet.CSRF_PROTECT,
                        rawResponse.substring(0,
                                AuraBaseServlet.CSRF_PROTECT.length()));
                Map<String, Object> json = (Map<String, Object>) new JsonReader()
                        .read(rawResponse
                                .substring(AuraBaseServlet.CSRF_PROTECT
                                        .length()));
                ArrayList<Map<String,Object>> actions = (ArrayList<Map<String, Object>>) json.get("actions");
                for(Map<String,Object> action: actions) {
               
                  this.stateList.add(State.valueOf(action.get("state").toString()));
                  this.returnValueList.add(action.get("returnValue"));
                  this.errorsList.add((List<Object>) action.get("error"));
                }
                //for legacy uses
                Map<String, Object> action = (Map<String, Object>) ((List<Object>) json
                        .get("actions")).get(0);
                this.state = State.valueOf(action.get("state").toString());
                this.returnValue = action.get("returnValue");
                this.errors = (List<Object>) action.get("error");
               
            } catch (Exception e) {
                throw new AuraExecutionException(e, null);
            }
        }
       
        public String getrawResponse() {
          return this.rawResponse;
        }
       
        @Override
        public void add(List<Action> actions) {
            // Only 1 action supported for now
        }

        @Override
        public List<Action> getActions() {
            return ImmutableList.of((Action) this);
        }

        @Override
        public Object getReturnValue() {
            return returnValue;
        }
       
        public ArrayList<Object> getReturnValueList() {
          return returnValueList;
        }

        @Override
        public State getState() {
            return state;
        }
       
        public ArrayList<State> getStateList() {
          return stateList;
        }

        @Override
        public List<Object> getErrors() {
            return errors;
        }
       
        public ArrayList<List<Object>> getErrorsList() {
          return errorsList;
        }

        @Override
        public void logParams(KeyValueLogger paramLogger) {
            // not implemented
        }

        @Override
        public boolean isStorable() {
            return false;
        }

        @Override
        public void setStorable() {
        }

        @Override
        public Map<String, Object> getParams() {
            return null;
        }

        private final InstanceStack instanceStack = new InstanceStack();

        @Override
        public InstanceStack getInstanceStack() {
            return instanceStack;
        }

        @Override
        public String getPath() {
            return getId();
        }
    }
}
TOP

Related Classes of org.auraframework.test.AuraHttpTestCase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.