1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import com.android.ide.common.rendering.api.Bridge; 18 import com.android.ide.common.rendering.api.Result; 19 import com.android.ide.common.rendering.api.SessionParams; 20 import com.android.layoutlib.bridge.intensive.RenderResult; 21 import com.android.layoutlib.bridge.intensive.RenderTestBase; 22 import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; 23 import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback; 24 import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; 25 import com.android.layoutlib.bridge.intensive.util.ImageUtils; 26 import com.android.layoutlib.bridge.remote.client.RemoteBridgeClient; 27 import com.android.layoutlib.bridge.remote.server.ServerMain; 28 29 import org.junit.After; 30 import org.junit.Before; 31 import org.junit.Test; 32 33 import java.io.File; 34 import java.io.IOException; 35 import java.rmi.NotBoundException; 36 37 import static org.junit.Assert.assertEquals; 38 import static org.junit.Assert.assertNotNull; 39 import static org.junit.Assert.fail; 40 41 42 public class RemoteBridgeTest extends RenderTestBase { 43 private ServerMain mServerMain; 44 private RemoteBridgeClient mClient; 45 46 /** 47 * Copy of RenderTestBase.renderAndVerify that allows using a different Bridge. TODO: Merge back 48 * into RenderTestBase 49 */ renderAndVerify(Bridge bridge, SessionParams params, String goldenFileName, long frameTimeNanos)50 protected static RenderResult renderAndVerify(Bridge bridge, SessionParams params, 51 String goldenFileName, long frameTimeNanos) throws ClassNotFoundException { 52 RenderResult result = RenderTestBase.render(bridge, params, frameTimeNanos); 53 try { 54 String goldenImagePath = APP_TEST_DIR + "/golden/" + goldenFileName; 55 assertNotNull(result.getImage()); 56 ImageUtils.requireSimilar(goldenImagePath, result.getImage()); 57 } catch (IOException e) { 58 getLogger().error(e, e.getMessage()); 59 } 60 61 return result; 62 } 63 64 @Before setupServer()65 public void setupServer() throws IOException, NotBoundException, InterruptedException { 66 long startTime = System.currentTimeMillis(); 67 mServerMain = ServerMain.forkAndStartServer(ServerMain.REGISTRY_BASE_PORT, 10); 68 mClient = RemoteBridgeClient.getRemoteBridge(mServerMain.getPort()); 69 System.out.printf("Server started in %dms\n", System.currentTimeMillis() - startTime); 70 startTime = System.currentTimeMillis(); 71 72 File data_dir = new File(PLATFORM_DIR, "data"); 73 File res = new File(data_dir, "res"); 74 File fontLocation = new File(data_dir, "fonts"); 75 File buildProp = new File(PLATFORM_DIR, "build.prop"); 76 File attrs = new File(res, "values" + File.separator + "attrs.xml"); 77 78 mClient.init(ConfigGenerator.loadProperties(buildProp), fontLocation, null, 79 ConfigGenerator.getEnumMap(attrs), getLayoutLog()); 80 System.out.printf("Remote client init took %dms\n", 81 System.currentTimeMillis() - startTime); 82 } 83 84 @After stopServer()85 public void stopServer() { 86 mClient.dispose(); 87 mServerMain.stop(); 88 } 89 90 /** 91 * Same test as RenderTest#testActivity but using the remote bridge 92 */ 93 @Test testActivity()94 public void testActivity() throws IOException, ClassNotFoundException { 95 SessionParams params = createSessionParams("activity.xml", ConfigGenerator.NEXUS_5); 96 RenderResult result = renderAndVerify(mClient, params, "activity.png", 250); 97 assertEquals(Result.Status.SUCCESS, result.getResult().getStatus()); 98 if (result.getResult().getException() != null) { 99 result.getResult().getException().printStackTrace(); 100 fail("Unexpected exception"); 101 } 102 } 103 104 /** 105 * Same test as RenderTest#testActivity but using the remote bridge 106 */ 107 @Test testCustomClassLoading()108 public void testCustomClassLoading() throws ClassNotFoundException { 109 LayoutLibTestCallback layoutLibCallback = 110 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 111 layoutLibCallback.initResources(); 112 113 LayoutPullParser parser = LayoutPullParser.createFromString( 114 "<CustomComponent xmlns:android=\"http://schemas" + 115 ".android.com/apk/res/android\"\n" + 116 " android:layout_width=\"match_parent\"\n" + 117 " android:layout_height=\"match_parent\"\n>" + 118 "</CustomComponent>"); 119 SessionParams params = 120 getSessionParamsBuilder().setParser(parser).setCallback(layoutLibCallback).setTheme( 121 "Theme.NoTitleBar", false).build(); 122 123 RenderResult result = renderAndVerify(mClient, params, "remote_component_load.png", 250); 124 assertEquals(Result.Status.SUCCESS, result.getResult().getStatus()); 125 if (result.getResult().getException() != null) { 126 result.getResult().getException().printStackTrace(); 127 fail("Unexpected exception"); 128 } 129 130 parser = LayoutPullParser.createFromString( 131 "<MissingCustomComponent xmlns:android=\"http://schemas" + 132 ".android.com/apk/res/android\"\n" + 133 " android:layout_width=\"match_parent\"\n" + 134 " android:layout_height=\"match_parent\"\n>" + 135 "</MissingCustomComponent>"); 136 params = 137 getSessionParamsBuilder().setParser(parser).setCallback(layoutLibCallback).setTheme( 138 "Theme.NoTitleBar", false).build(); 139 result = renderAndVerify(mClient, params, "remote_component_load_fail.png", 250); 140 assertEquals(Result.Status.SUCCESS, result.getResult().getStatus()); 141 if (result.getResult().getException() != null) { 142 result.getResult().getException().printStackTrace(); 143 fail("Unexpected exception"); 144 } 145 } 146 }