Package org.auraframework.impl

Source Code of org.auraframework.impl.ServerServiceImplTest$EmptyAction

/*
* 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.impl;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.auraframework.Aura;
import org.auraframework.def.ActionDef;
import org.auraframework.def.ApplicationDef;
import org.auraframework.def.ComponentDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.def.Definition;
import org.auraframework.def.DefinitionAccess;
import org.auraframework.def.TypeDef;
import org.auraframework.def.ValueDef;
import org.auraframework.instance.AbstractActionImpl;
import org.auraframework.instance.Action;
import org.auraframework.instance.ActionDelegate;
import org.auraframework.instance.Component;
import org.auraframework.service.ServerService;
import org.auraframework.system.AuraContext;
import org.auraframework.system.AuraContext.Authentication;
import org.auraframework.system.AuraContext.Format;
import org.auraframework.system.AuraContext.Mode;
import org.auraframework.system.Location;
import org.auraframework.system.Message;
import org.auraframework.system.SubDefDescriptor;
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.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

public class ServerServiceImplTest extends AuraImplTestCase {
    public ServerServiceImplTest(String name) {
        super(name, false);
    }

    private static final Set<String> GLOBAL_IGNORE = Sets.newHashSet("context", "actions");
   
    // Do not test for null message, it cannot legally be null.
    private static class EmptyActionDef implements ActionDef {
    private static final long serialVersionUID = 1L;
    StringWriter sw;
    String name;
   
    protected EmptyActionDef(StringWriter sw,String name) {
      this.sw = sw;
      this.name = name;
    }

    @Override
        public void validateDefinition() throws QuickFixException {
        }

        @Override
        public void appendDependencies(Set<DefDescriptor<?>> dependencies) {
        }

        @Override
        public void validateReferences() throws QuickFixException {
        }

        @Override
        public void markValid() {
        }

        @Override
        public boolean isValid() {
            return true;
        }

        @Override
        public Location getLocation() {
            return null;
        }

        @Override
        public Visibility getVisibility() {
            return null;
        }

        @Override
        public DefinitionAccess getAccess() {
            return null;
        }

        @Override
        public <D extends Definition> D getSubDefinition(SubDefDescriptor<D, ?> descriptor) {
            return null;
        }

        @Override
        public void retrieveLabels() throws QuickFixException {
        }

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

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

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

        @Override
        public void appendSupers(Set<DefDescriptor<?>> supers) throws QuickFixException {
        }

        @Override
        public void serialize(Json json) throws IOException {
        }

        @Override
        public DefDescriptor<ActionDef> getDescriptor() {
            return null;
        }

        @Override
        public ActionType getActionType() {
            return null;
        }

        @Override
        public String getName() {
            return this.name;
        }

        @Override
        public DefDescriptor<TypeDef> getReturnType() {
            return null;
        }

        @Override
        public List<ValueDef> getParameters() {
            return null;
        }

        @Override
        public List<String> getLoggableParams() {
            return Lists.newArrayList();
        }
    }
   
  

    private static class EmptyAction extends AbstractActionImpl<EmptyActionDef> {
        private String returnValue="";
        private Integer count=0;
        private String parameter="";
       
        public EmptyAction(StringWriter sw, String name) {
            super(null, new EmptyActionDef(sw,name), null);
        }
   
    public EmptyAction() {
            super(null, new EmptyActionDef(null,"simpleaction"), null);
        }
   
    public Integer getCount() {
      return this.count;
    }

    public String getName() {
      return this.actionDef.getName();
    }
   
        @Override
        public DefDescriptor<ActionDef> getDescriptor() {
            return Aura.getDefinitionService().getDefDescriptor("java://aura.empty/ACTION$emptyAction", ActionDef.class);
        }

        @Override
        public void run() throws AuraExecutionException {
          this.count++;
          if(this.actionDef.sw!=null) {
            this.returnValue = this.actionDef.sw.toString();
          } else {
            //do nothing
          }
          if(this.count>1) {
            setParameter("#"+this.count);
          }
        }

        @Override
        public Object getReturnValue() {
            return this.returnValue;
        }
       
        private void setParameter(String parameter) {
          this.parameter = parameter;
        }

        @Override
        public List<Object> getErrors() {
            return null;
        }

        @Override
        public void serialize(Json json) throws IOException {
            Map<String,String> value = Maps.newHashMap();
            String res=this.getName();
            if(this.parameter!="") { res=res.concat("{"+this.parameter+"}"); }
            value.put("action", res);
            json.writeValue(value);
        }
    };

    private static class ShareCmpAction extends ActionDelegate {

      private Map<String,Object> componentAttributes = null;
      private Component sharedCmp = null;
      private Object returnValue = null;
      private String name="ShareCmpAction";
     
      public ShareCmpAction(String name, Action originalAction, Component sharedCmp, Map<String,Object> componentAttributes) {
            super(originalAction);
            this.sharedCmp = sharedCmp;
            this.componentAttributes = componentAttributes;
            this.name = name;
        }
     
    @Override
    public void run() throws AuraExecutionException {
      try {
        sharedCmp.getAttributes().set(componentAttributes);
      } catch (QuickFixException e) {
        throw new AuraExecutionException(e.getMessage(), e.getLocation());
      }
      super.run();
      String whatIsInResponse = (String) super.getReturnValue();
      int startPos = whatIsInResponse.lastIndexOf("shared_component");
      if(startPos >=0 ) {
        this.returnValue = whatIsInResponse.substring(startPos);
      }
    }

    @Override
    public Object getReturnValue() {
      return this.returnValue;
    }
   
    @Override
    public void serialize(Json json) throws IOException {
      Map<String,Object> value = Maps.newHashMap();
      value.put("shared_component", this.sharedCmp);
      value.put("action", this.name);
            json.writeValue(value);
    }
    }

    /**
     * Test for W-2085617
     * This test is to verify when we have shared component between actions, they get serialized into response correctly.
     *
     * Test Setup:
     * EmptyAction a,b,c : when it run, it put whatever response has into their return value
     * ShareCmpAction d,e,f: when it run, it update the attribute of shared component, run its delegate action(a,b orc),
     * then get the latest shared_component(in Json format) from its delegate action's return value as its return value.
     *
     * when b runs, a has finish running, so b will have shared_component of a
     * e will have shared_component of a in its return value (with attrA)
     * when c runs, b has finish running, so c will have shared_components of a & b
     * e will have shared_component of b in its return value (with attrB)
     * @throws Exception
     */
    public void testSharedCmp() throws Exception {
      Aura.getContextService().startContext(Mode.UTEST, Format.JSON, Authentication.AUTHENTICATED);
      Map<String, Object> attributes = Maps.newHashMap();
      Map<String, Object> attributesA = Maps.newHashMap();
      attributesA.put("attr", "attrA");
      Map<String, Object> attributesB = Maps.newHashMap();
      attributesB.put("attr", "attrB");
      Map<String, Object> attributesC = Maps.newHashMap();
      attributesC.put("attr", "attrC");
    Component sharedCmp = Aura.getInstanceService().getInstance("ifTest:testIfWithModel", ComponentDef.class,
                attributes);
      StringWriter sw = new StringWriter();
        ServerService ss = Aura.getServerService();
        Action a = new EmptyAction(sw,"first action");
        Action b = new EmptyAction(sw,"second action");
        Action c = new EmptyAction(sw,"third action");
        Action d = new ShareCmpAction("d",a,sharedCmp,attributesA);
        Action e = new ShareCmpAction("e",b,sharedCmp,attributesB);
        Action f = new ShareCmpAction("f",c,sharedCmp,attributesC);
        List<Action> actions = Lists.newArrayList(d,e,f);
        Message message = new Message(actions);
        //run the list of actions.
        ss.run(message, Aura.getContextService().getCurrentContext(), sw, null);
       
        //sanity check, sharedCmp should have the latest attribute value.
        //this has nothing to do with the fix though
        assertEquals("attrC",sharedCmp.getAttributes().getValue("attr"));
        //Here are the checks for fix
        //returnValue of action e is going to have shared component from action d in Json format
        String returne = (String) e.getReturnValue();
        assertTrue(returne.contains("markup://ifTest:testIfWithModel"));
        assertTrue(returne.contains("\"attr\":\"attrA\""));
        //returnValue of action f is going to have shared component from action e in Json format
        String returnf = (String) f.getReturnValue();
        assertTrue(returnf.contains("markup://ifTest:testIfWithModel"));
        assertTrue(returnf.contains("\"attr\":\"attrB\""));
       
    }

    /**
     * Check that our EmptyAction is properly serialized.
     *
     * This does a positive and negative test, ensuring that we only serialize what we should.
     */
    @SuppressWarnings("unchecked")
    private Map<String,Object> validateEmptyActionSerialization(String serialized, Set<String> ignore,
        List<String> actionNameList) {
      int actionNumber = actionNameList.size();
        Set<String> extras = Sets.newHashSet();
        Map<String, Object> json = (Map<String, Object>) new JsonReader().read(serialized);
        List<Object> actions = (List<Object>) json.get("actions");
        assertTrue(actions != null);
        assertTrue("expected "+actionNumber+" action, but get "+actions.size(), actions.size() == actionNumber);
        for(int i=0;i<actionNumber;i++) {
            Map<String, Object> action = (Map<String, Object>) actions.get(i);
          assertEquals("didn't get expecting action on i:"+i,
              actionNameList.get(i), action.get("action"));
        }
        for (String key : json.keySet()) {
            if (!GLOBAL_IGNORE.contains(key) && (ignore == null || !ignore.contains(key))) {
                extras.add(key);
            }
        }
        assertTrue("Expected no extra keys, found: "+extras+", in: "+json, extras.isEmpty());
        return json;
    }
   
    /**
     * This test is for W-2063110
     * Test a list of actions.
     * New Way : in ServerService, we serialize each action and write it into response (via a string writer)
     * right after it finish running.
     * in the SimpleAction above, we put whatever we have in the string writer as returnValue of the current action
     * so when Action2 is running, we should have Action1 in string writer,
     * when Action3 is running, we should have both Action1 and Action2, ....
     * Old Way: We used to run all actions, store the result in Message, then write them into response at once,
     * in the old way we won't have anything in string writer/response until Action3 is finished.
     */
    public void testMultipleActions() throws Exception {
      Aura.getContextService().startContext(Mode.UTEST, Format.JSON, Authentication.AUTHENTICATED);
      StringWriter sw = new StringWriter();
        ServerService ss = Aura.getServerService();
        Action a = new EmptyAction(sw,"first action");
        Action b = new EmptyAction(sw,"second action");
        Action c = new EmptyAction(sw,"third action");
        List<Action> actions = Lists.newArrayList(a,b,c);
        Message message = new Message(actions);
        //run the list of actions.
        ss.run(message, Aura.getContextService().getCurrentContext(), sw, null);
        String returnValuea = "{\"actions\":[";
        String returnValueb = returnValuea+"{\"action\":\"firstaction\"}";
        String returnValuec = returnValueb+",{\"action\":\"secondaction\"}";
       
        List<String> returnValueList = Arrays.asList(returnValuea,returnValueb,returnValuec);
        for(int i=0;i<actions.size();i++) {
          Action act = actions.get(i);
          assertEquals("get different action return on i:"+i,
              returnValueList.get(i),((String)act.getReturnValue()).replaceAll("\\s+", ""));
        }
       
        validateEmptyActionSerialization(sw.toString(), null, Arrays.asList("first action","second action","third action"));
    }
   
   
    /**
     * This test is for W-2063110
     * Running the same action twice in a list
     * since we output right after the run, we can reuse the action.
     * the second run will over-write the previous run's returnValue(unless we change the run()),
     * but response keep the info from previous run, so we are good
     */
    public void testSameActionTwice() throws Exception {
      Aura.getContextService().startContext(Mode.UTEST, Format.JSON, Authentication.AUTHENTICATED);
      StringWriter sw = new StringWriter();
        ServerService ss = Aura.getServerService();
        Action a = new EmptyAction(sw,"first action");
        Action b = new EmptyAction(sw,"second action");
        List<Action> actions = Lists.newArrayList(a,b,a,b);
        Message message = new Message(actions);
        ss.run(message, Aura.getContextService().getCurrentContext(), sw, null);
        assertTrue(((EmptyAction)a).getCount()==2);
        assertTrue(((EmptyAction)b).getCount()==2);
        //in the old way since we output action info into response after all actions finish running, the previous run's info will get overwrited
        //but this is not the case now
        //we need to verify when same action run twice, and something about the action changed between the two runs --like the parameter,
        //the response has the action info for both times.
        validateEmptyActionSerialization(sw.toString(), null,
            Arrays.asList("first action","second action","first action{#2}","second action{#2}"));
 
    }

    /**
     * Test a simple action that serializes a specific value.
     *
     * We carefully test only the parts that we care about for ServerService.
     */
    public void testSimpleAction() throws Exception {
        Aura.getContextService().startContext(Mode.UTEST, Format.JSON, Authentication.AUTHENTICATED);

        ServerService ss = Aura.getServerService();
        Action a = new EmptyAction();
        List<Action> actions = Lists.newArrayList(a);
        Message message = new Message(actions);
        StringWriter sw = new StringWriter();
        ss.run(message, Aura.getContextService().getCurrentContext(), sw, null);
        validateEmptyActionSerialization(sw.toString(), null, Arrays.asList("simpleaction"));
    }

    /**
     * Test a simple action that serializes a specific value.
     *
     * We carefully test only the parts that we care about for ServerService.
     */
    public void testSimpleActionWithExtras() throws Exception {
        Aura.getContextService().startContext(Mode.UTEST, Format.JSON, Authentication.AUTHENTICATED);
     
        ServerService ss = Aura.getServerService();
        Action a = new EmptyAction();
        List<Action> actions = Lists.newArrayList(a);
        Map<String,String> extras = Maps.newHashMap();
        Message message = new Message(actions);
        StringWriter sw = new StringWriter();
        extras.put("this", "that");
        ss.run(message, Aura.getContextService().getCurrentContext(), sw, extras);

        Map<String, Object> json = validateEmptyActionSerialization(sw.toString(), Sets.newHashSet("this"),Arrays.asList("simpleaction"));
        assertEquals("Expected extras to be in "+json, "that", json.get("this"));
    }
    /**
     * Sanity check to make sure that app.css does not have duplicate copy of component CSS. Component CSS was being
     * added twice, once because they were part of preload namespace and a second time because of component dependency.
     * This test mocks such duplication. W-1588568
     */
    public void testWriteCssWithoutDupes() throws Exception {
        ServerService ss = Aura.getServerService();
        DefDescriptor<ApplicationDef> appDesc = Aura.getDefinitionService()
                .getDefDescriptor("preloadTest:test_SimpleApplication", ApplicationDef.class);
        AuraContext context = Aura.getContextService()
                .startContext(Mode.DEV, AuraContext.Format.CSS, AuraContext.Authentication.AUTHENTICATED, appDesc);
        final String uid = context.getDefRegistry().getUid(null, appDesc);
        context.addLoaded(appDesc, uid);

        Set<DefDescriptor<?>> dependencies = context.getDefRegistry().getDependencies(uid);
       
        StringWriter output = new StringWriter();
        ss.writeAppCss(dependencies, output);

        // A snippet of component css
        String cssPiece = "AuraResourceServletTest-testWriteCssWithoutDupes";
        Pattern pattern = Pattern.compile(cssPiece);
        Matcher matcher = pattern.matcher(output.toString());
        int count = 0;
        while (matcher.find() && count < 3) {
            count++;
        }
        assertEquals("Component CSS repeated", 1, count);
    }

    /**
     * Verify that the css writer writes in the order given.
     */
    public void testCSSOrder() throws Exception {
        ServerService ss = Aura.getServerService();
        DefDescriptor<ApplicationDef> appDesc = Aura.getDefinitionService()
                .getDefDescriptor("auratest:test_SimpleServerRenderedPage", ApplicationDef.class);
        DefDescriptor<ComponentDef> grandparent = Aura.getDefinitionService()
                .getDefDescriptor("setAttributesTest:grandparent", ComponentDef.class);
        DefDescriptor<ComponentDef> parent = Aura.getDefinitionService()
                .getDefDescriptor("setAttributesTest:parent", ComponentDef.class);
        DefDescriptor<ComponentDef> child1 = Aura.getDefinitionService()
                .getDefDescriptor("setAttributesTest:child", ComponentDef.class);
        DefDescriptor<ComponentDef> child2 = Aura.getDefinitionService()
                .getDefDescriptor("setAttributesTest:anotherChild", ComponentDef.class);
        Aura.getContextService().startContext(AuraContext.Mode.DEV, AuraContext.Format.CSS,
                AuraContext.Authentication.AUTHENTICATED, appDesc);

        Set<DefDescriptor<?>> writable = Sets.newLinkedHashSet();

        writable.add(child1.getDef().getStyleDescriptor());
        writable.add(grandparent.getDef().getStyleDescriptor());
        writable.add(parent.getDef().getStyleDescriptor());
        writable.add(child2.getDef().getStyleDescriptor());

        StringWriter output = new StringWriter();
        ss.writeAppCss(writable, output);
        String css = output.toString();

        //
        // order should be exactly that above.
        // child1, grandparent, parent, child2
        //
        assertTrue("parent CSS should be written before child CSS in: "+css,
                css.indexOf(".setAttributesTestChild") < css.indexOf(".setAttributesTestGrandparent"));
        assertTrue("grandparent CSS should be written before parent CSS in: "+css,
                css.indexOf(".setAttributesTestGrandparent") < css.indexOf(".setAttributesTestParent"));
        assertTrue("parent CSS should be written before another child CSS in: "+css,
                css.indexOf(".setAttributesTestParent") < css.indexOf(".setAttributesTestAnotherChild"));
    }

    public void testPreloadCSSDependencies() throws Exception {
        ServerService ss = Aura.getServerService();
        DefDescriptor<ComponentDef> appDesc = Aura.getDefinitionService()
                .getDefDescriptor("clientApiTest:cssStyleTest", ComponentDef.class);
        AuraContext context = Aura.getContextService().startContext(AuraContext.Mode.DEV, AuraContext.Format.CSS,
                AuraContext.Authentication.AUTHENTICATED, appDesc);
        final String uid = context.getDefRegistry().getUid(null, appDesc);
        context.addLoaded(appDesc, uid);

        Set<DefDescriptor<?>> dependencies = context.getDefRegistry().getDependencies(uid);

        StringWriter output = new StringWriter();
        ss.writeAppCss(dependencies, output);

        String sourceNoWhitespace = output.toString().replaceAll("\\s", "");
        String preloaded1 = ".clientApiTestCssStyleTest{background-color:#eee}";
        String preloaded2 = ".testTestValidCSS{color:#1797c0";
        assertTrue("Does not have preloaded css (1) in "+output, sourceNoWhitespace.contains(preloaded1));
        assertTrue("Does not have preloaded css (2) in "+output, sourceNoWhitespace.contains(preloaded2));
    }

    /**
     * Sanity check to make sure that app.js doesn't blow up
     */
    public void testWriteDefinitionsWithoutDupes() throws Exception {
        ServerService ss = Aura.getServerService();
        DefDescriptor<ApplicationDef> appDesc = Aura.getDefinitionService()
                .getDefDescriptor("appCache:withpreload", ApplicationDef.class);
        AuraContext context = Aura.getContextService()
                .startContext(Mode.DEV, AuraContext.Format.JS, AuraContext.Authentication.AUTHENTICATED, appDesc);
        final String uid = context.getDefRegistry().getUid(null, appDesc);
        context.addLoaded(appDesc, uid);

        Set<DefDescriptor<?>> dependencies = context.getDefRegistry().getDependencies(uid);

        // prime def cache
        StringWriter output = new StringWriter();
        ss.writeDefinitions(dependencies, output);
        String text = output.toString();
        final String dupeCheck = "$A.clientService.initDefs(";
        if (text.indexOf(dupeCheck) != text.lastIndexOf(dupeCheck)) {
            fail("found duplicated code in: " + text);
        }

        // now check that defs not re-written with unempty cache
        output = new StringWriter();
        ss.writeDefinitions(dependencies, output);
        text = output.toString();
        if (text.indexOf(dupeCheck) != text.lastIndexOf(dupeCheck)) {
            fail("found duplicated code in: " + text);
        }
    }

    public void testPreloadJSDependencies() throws Exception {
        ServerService ss = Aura.getServerService();
        DefDescriptor<ComponentDef> appDesc = Aura.getDefinitionService()
                .getDefDescriptor("clientApiTest:cssStyleTest", ComponentDef.class);
        AuraContext context = Aura.getContextService().startContext(AuraContext.Mode.DEV, AuraContext.Format.JS,
                AuraContext.Authentication.AUTHENTICATED, appDesc);
        final String uid = context.getDefRegistry().getUid(null, appDesc);
        context.addLoaded(appDesc, uid);

        Set<DefDescriptor<?>> dependencies = context.getDefRegistry().getDependencies(uid);

        StringWriter output = new StringWriter();
        ss.writeDefinitions(dependencies, output);

        String sourceNoWhitespace = output.toString().replaceAll("\\s", "");

        String[] preloads = new String[]{
                "\"descriptor\":\"markup://aura:placeholder\"",
                "\"descriptor\":\"markup://ui:input\"",
                "\"descriptor\":\"markup://ui:inputText\"",
                "\"descriptor\":\"markup://ui:output\"",
                "\"descriptor\":\"markup://ui:outputText\"",
                "\"descriptor\":\"markup://test:testValidCSS\""
        };

        for (String preload : preloads) {
            assertTrue("Does not have preloaded component: (" + preload + ")" , sourceNoWhitespace.contains(preload));
        }
    }

    /**
     * Tests aura definitions has no syntax errors and can be compressed
     */
    public void testNoAppJSCompressionErrors() throws Exception {

        // check js compression on main aura namespaces
        String[] namespaces = new String[] {
            "aura", "ui", "auraadmin", "auradev", "auradocs", "auraStorage"
        };

        StringBuilder source = new StringBuilder();
        source.append("<aura:application>");
        for (String ns : namespaces) {
            source.append(String.format("<aura:dependency resource=\"%s:*\" type=\"*\" />", ns));
        }
        source.append("</aura:application>");

        DefDescriptor<ApplicationDef> appDesc = addSourceAutoCleanup(ApplicationDef.class, source.toString());
        AuraContext context = Aura.getContextService().startContext(AuraContext.Mode.PROD, AuraContext.Format.JS,
                AuraContext.Authentication.AUTHENTICATED, appDesc);
        final String uid = context.getDefRegistry().getUid(null, appDesc);
        context.addLoaded(appDesc, uid);
        Set<DefDescriptor<?>> dependencies = context.getDefRegistry().getDependencies(uid);

        ServerService ss = Aura.getServerService();
        StringWriter output = new StringWriter();
        ss.writeDefinitions(dependencies, output);

        String js = output.toString();
        assertFalse("There are syntax errors preventing compression of application javascript",
            js.contains("There are errors preventing this file from being minimized!"));
    }
}
TOP

Related Classes of org.auraframework.impl.ServerServiceImplTest$EmptyAction

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.