15c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez/*
25c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * Copyright (C) 2017 The Android Open Source Project
35c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez *
45c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * Licensed under the Apache License, Version 2.0 (the "License");
55c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * you may not use this file except in compliance with the License.
65c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * You may obtain a copy of the License at
75c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez *
85c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez *      http://www.apache.org/licenses/LICENSE-2.0
95c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez *
105c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * Unless required by applicable law or agreed to in writing, software
115c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * distributed under the License is distributed on an "AS IS" BASIS,
125c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * See the License for the specific language governing permissions and
145c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez * limitations under the License.
155c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez */
165c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
175c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.ide.common.rendering.api.Bridge;
185c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.ide.common.rendering.api.Result;
195c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.ide.common.rendering.api.SessionParams;
205c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.layoutlib.bridge.intensive.RenderResult;
215c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.layoutlib.bridge.intensive.RenderTestBase;
225c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
2362413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perezimport com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
2462413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perezimport com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
255c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.layoutlib.bridge.intensive.util.ImageUtils;
265c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.layoutlib.bridge.remote.client.RemoteBridgeClient;
275c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport com.android.layoutlib.bridge.remote.server.ServerMain;
285c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
295c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport org.junit.After;
305c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport org.junit.Before;
315c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport org.junit.Test;
325c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
335c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport java.io.File;
345c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport java.io.IOException;
355c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport java.rmi.NotBoundException;
365c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
375c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport static org.junit.Assert.assertEquals;
385c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport static org.junit.Assert.assertNotNull;
395c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezimport static org.junit.Assert.fail;
405c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
415c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
425c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perezpublic class RemoteBridgeTest extends RenderTestBase {
435c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    private ServerMain mServerMain;
445c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    private RemoteBridgeClient mClient;
455c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
465c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    /**
475c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez     * Copy of RenderTestBase.renderAndVerify that allows using a different Bridge. TODO: Merge back
485c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez     * into RenderTestBase
495c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez     */
505c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    protected static RenderResult renderAndVerify(Bridge bridge, SessionParams params,
515c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez            String goldenFileName, long frameTimeNanos) throws ClassNotFoundException {
525c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        RenderResult result = RenderTestBase.render(bridge, params, frameTimeNanos);
535c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        try {
545c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez            String goldenImagePath = APP_TEST_DIR + "/golden/" + goldenFileName;
555c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez            assertNotNull(result.getImage());
565c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez            ImageUtils.requireSimilar(goldenImagePath, result.getImage());
575c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        } catch (IOException e) {
585c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez            getLogger().error(e, e.getMessage());
595c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        }
605c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
615c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        return result;
625c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    }
635c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
645c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    @Before
6562413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez    public void setupServer() throws IOException, NotBoundException, InterruptedException {
66ce1a4634e3b96e7e4d043afa4d5cc8ab23ce92dbDiego Perez        mServerMain = ServerMain.forkAndStartServer(ServerMain.REGISTRY_BASE_PORT, 10);
675c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        mClient = RemoteBridgeClient.getRemoteBridge(mServerMain.getPort());
685c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
695c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        File data_dir = new File(PLATFORM_DIR, "data");
705c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        File res = new File(data_dir, "res");
715c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        File fontLocation = new File(data_dir, "fonts");
725c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        File buildProp = new File(PLATFORM_DIR, "build.prop");
735c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        File attrs = new File(res, "values" + File.separator + "attrs.xml");
745c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
755c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        mClient.init(ConfigGenerator.loadProperties(buildProp), fontLocation,
765c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez                ConfigGenerator.getEnumMap(attrs), getLayoutLog());
775c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    }
785c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
795c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    @After
805c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    public void stopServer() {
815c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        mClient.dispose();
825c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        mServerMain.stop();
835c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    }
845c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez
855c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    /**
865c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez     * Same test as RenderTest#testActivity but using the remote bridge
875c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez     */
885c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    @Test
8962413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez    public void testActivity() throws IOException, ClassNotFoundException {
905c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        SessionParams params = createSessionParams("activity.xml", ConfigGenerator.NEXUS_5);
915c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        RenderResult result = renderAndVerify(mClient, params, "activity.png", 250);
925c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        assertEquals(Result.Status.SUCCESS, result.getResult().getStatus());
935c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        if (result.getResult().getException() != null) {
945c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez            result.getResult().getException().printStackTrace();
955c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez            fail("Unexpected exception");
965c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez        }
975c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez    }
9862413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez
9962413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez    /**
10062413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez     * Same test as RenderTest#testActivity but using the remote bridge
10162413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez     */
10262413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez    @Test
10362413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez    public void testCustomClassLoading() throws ClassNotFoundException {
10462413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        LayoutLibTestCallback layoutLibCallback =
10562413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
10662413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        layoutLibCallback.initResources();
10762413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez
10862413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        LayoutPullParser parser = LayoutPullParser.createFromString(
10962413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                "<CustomComponent xmlns:android=\"http://schemas" +
11062413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        ".android.com/apk/res/android\"\n" +
11162413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "                android:layout_width=\"match_parent\"\n" +
11262413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "                android:layout_height=\"match_parent\"\n>" +
11362413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "</CustomComponent>");
11462413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        SessionParams params =
11562413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                getSessionParamsBuilder().setParser(parser).setCallback(layoutLibCallback).setTheme(
11662413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "Theme.NoTitleBar", false).build();
11762413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez
11862413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        RenderResult result = renderAndVerify(mClient, params, "remote_component_load.png", 250);
11962413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        assertEquals(Result.Status.SUCCESS, result.getResult().getStatus());
12062413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        if (result.getResult().getException() != null) {
12162413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez            result.getResult().getException().printStackTrace();
12262413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez            fail("Unexpected exception");
12362413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        }
12462413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez
12562413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        parser = LayoutPullParser.createFromString(
12662413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                "<MissingCustomComponent xmlns:android=\"http://schemas" +
12762413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        ".android.com/apk/res/android\"\n" +
12862413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "                android:layout_width=\"match_parent\"\n" +
12962413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "                android:layout_height=\"match_parent\"\n>" +
13062413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "</MissingCustomComponent>");
13162413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        params =
13262413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                getSessionParamsBuilder().setParser(parser).setCallback(layoutLibCallback).setTheme(
13362413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez                        "Theme.NoTitleBar", false).build();
13462413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        result = renderAndVerify(mClient, params, "remote_component_load_fail.png", 250);
13562413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        assertEquals(Result.Status.SUCCESS, result.getResult().getStatus());
13662413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        if (result.getResult().getException() != null) {
13762413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez            result.getResult().getException().printStackTrace();
13862413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez            fail("Unexpected exception");
13962413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez        }
14062413126b979e60482d6dd7d4ec8ce1412c61da5Diego Perez    }
1415c5efc433eb4cc81f59bcfaf28f5e72b38f7a829Diego Perez}