1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.mojo.bindings; 6 7 import android.annotation.SuppressLint; 8 import android.support.test.filters.SmallTest; 9 10 import org.junit.Assert; 11 import org.junit.Rule; 12 import org.junit.Test; 13 import org.junit.runner.RunWith; 14 15 import org.chromium.base.test.BaseJUnit4ClassRunner; 16 import org.chromium.base.test.util.UrlUtils; 17 import org.chromium.mojo.HandleMock; 18 import org.chromium.mojo.MojoTestRule; 19 import org.chromium.mojo.bindings.test.mojom.mojo.ConformanceTestInterface; 20 import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface; 21 import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterfaceTestHelper; 22 import org.chromium.mojo.system.Handle; 23 import org.chromium.mojo.system.impl.CoreImpl; 24 25 import java.io.File; 26 import java.io.FileFilter; 27 import java.io.FileNotFoundException; 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Scanner; 31 32 /** 33 * Testing validation upon deserialization using the interfaces defined in the 34 * mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom file. 35 * <p> 36 * One needs to pass '--test_data=bindings:{path to mojo/public/interfaces/bindings/tests/data}' to 37 * the test_runner script for this test to find the validation data it needs. 38 */ 39 @RunWith(BaseJUnit4ClassRunner.class) 40 public class ValidationTest { 41 @Rule 42 public MojoTestRule mTestRule = new MojoTestRule(); 43 44 /** 45 * The path where validation test data is. 46 */ 47 private static final File VALIDATION_TEST_DATA_PATH = new File(UrlUtils.getIsolatedTestFilePath( 48 "mojo/public/interfaces/bindings/tests/data/validation")); 49 50 /** 51 * The data needed for a validation test. 52 */ 53 private static class TestData { 54 public File dataFile; 55 public ValidationTestUtil.Data inputData; 56 public String expectedResult; 57 } 58 59 private static class DataFileFilter implements FileFilter { 60 private final String mPrefix; 61 DataFileFilter(String prefix)62 public DataFileFilter(String prefix) { 63 this.mPrefix = prefix; 64 } 65 66 @Override accept(File pathname)67 public boolean accept(File pathname) { 68 // TODO(yzshen, qsr): skip some interface versioning tests. 69 if (pathname.getName().startsWith("conformance_mthd13_good_2")) { 70 return false; 71 } 72 return pathname.isFile() && pathname.getName().startsWith(mPrefix) 73 && pathname.getName().endsWith(".data"); 74 } 75 } 76 77 @SuppressLint("NewApi") getStringContent(File f)78 private static String getStringContent(File f) throws FileNotFoundException { 79 // TODO(crbug.com/635567): Fix this properly. 80 try (Scanner scanner = new Scanner(f)) { 81 scanner.useDelimiter("\\Z"); 82 StringBuilder result = new StringBuilder(); 83 while (scanner.hasNext()) { 84 result.append(scanner.next()); 85 } 86 return result.toString().trim(); 87 } 88 } 89 getTestData(String prefix)90 private static List<TestData> getTestData(String prefix) throws FileNotFoundException { 91 List<TestData> results = new ArrayList<TestData>(); 92 93 // Fail if the test data is not present. 94 if (!VALIDATION_TEST_DATA_PATH.isDirectory()) { 95 Assert.fail("No test data directory found. " 96 + "Expected directory at: " + VALIDATION_TEST_DATA_PATH); 97 } 98 99 File[] files = VALIDATION_TEST_DATA_PATH.listFiles(new DataFileFilter(prefix)); 100 if (files != null) { 101 for (File dataFile : files) { 102 File resultFile = new File(dataFile.getParent(), 103 dataFile.getName().replaceFirst("\\.data$", ".expected")); 104 TestData testData = new TestData(); 105 testData.dataFile = dataFile; 106 testData.inputData = ValidationTestUtil.parseData(getStringContent(dataFile)); 107 testData.expectedResult = getStringContent(resultFile); 108 results.add(testData); 109 } 110 } 111 return results; 112 } 113 114 /** 115 * Runs all the test with the given prefix on the given {@link MessageReceiver}. 116 */ runTest(String prefix, MessageReceiver messageReceiver)117 private static void runTest(String prefix, MessageReceiver messageReceiver) 118 throws FileNotFoundException { 119 List<TestData> testData = getTestData(prefix); 120 for (TestData test : testData) { 121 Assert.assertNull("Unable to read: " + test.dataFile.getName() + ": " 122 + test.inputData.getErrorMessage(), 123 test.inputData.getErrorMessage()); 124 List<Handle> handles = new ArrayList<Handle>(); 125 for (int i = 0; i < test.inputData.getHandlesCount(); ++i) { 126 handles.add(new HandleMock()); 127 } 128 Message message = new Message(test.inputData.getData(), handles); 129 boolean passed = messageReceiver.accept(message); 130 if (passed && !test.expectedResult.equals("PASS")) { 131 Assert.fail("Input: " + test.dataFile.getName() 132 + ": The message should have been refused. Expected error: " 133 + test.expectedResult); 134 } 135 if (!passed && test.expectedResult.equals("PASS")) { 136 Assert.fail("Input: " + test.dataFile.getName() 137 + ": The message should have been accepted."); 138 } 139 } 140 } 141 142 private static class RoutingMessageReceiver implements MessageReceiver { 143 private final MessageReceiverWithResponder mRequest; 144 private final MessageReceiver mResponse; 145 RoutingMessageReceiver( MessageReceiverWithResponder request, MessageReceiver response)146 private RoutingMessageReceiver( 147 MessageReceiverWithResponder request, MessageReceiver response) { 148 this.mRequest = request; 149 this.mResponse = response; 150 } 151 152 /** 153 * @see MessageReceiver#accept(Message) 154 */ 155 @Override accept(Message message)156 public boolean accept(Message message) { 157 try { 158 MessageHeader header = message.asServiceMessage().getHeader(); 159 if (header.hasFlag(MessageHeader.MESSAGE_IS_RESPONSE_FLAG)) { 160 return mResponse.accept(message); 161 } else { 162 return mRequest.acceptWithResponder(message, new SinkMessageReceiver()); 163 } 164 } catch (DeserializationException e) { 165 return false; 166 } 167 } 168 169 /** 170 * @see MessageReceiver#close() 171 */ 172 @Override close()173 public void close() {} 174 } 175 176 /** 177 * A trivial message receiver that refuses all messages it receives. 178 */ 179 private static class SinkMessageReceiver implements MessageReceiverWithResponder { 180 @Override accept(Message message)181 public boolean accept(Message message) { 182 return true; 183 } 184 185 @Override close()186 public void close() {} 187 188 @Override acceptWithResponder(Message message, MessageReceiver responder)189 public boolean acceptWithResponder(Message message, MessageReceiver responder) { 190 return true; 191 } 192 } 193 194 /** 195 * Testing the conformance suite. 196 */ 197 @Test 198 @SmallTest testConformance()199 public void testConformance() throws FileNotFoundException { 200 runTest("conformance_", 201 ConformanceTestInterface.MANAGER.buildStub(CoreImpl.getInstance(), 202 ConformanceTestInterface.MANAGER.buildProxy( 203 CoreImpl.getInstance(), new SinkMessageReceiver()))); 204 } 205 206 /** 207 * Testing the integration suite for message headers. 208 */ 209 @Test 210 @SmallTest testIntegrationMessageHeader()211 public void testIntegrationMessageHeader() throws FileNotFoundException { 212 runTest("integration_msghdr_", 213 new RoutingMessageReceiver(IntegrationTestInterface.MANAGER.buildStub(null, 214 IntegrationTestInterface.MANAGER.buildProxy( 215 null, new SinkMessageReceiver())), 216 IntegrationTestInterfaceTestHelper 217 .newIntegrationTestInterfaceMethodCallback())); 218 } 219 220 /** 221 * Testing the integration suite for request messages. 222 */ 223 @Test 224 @SmallTest testIntegrationRequestMessage()225 public void testIntegrationRequestMessage() throws FileNotFoundException { 226 runTest("integration_intf_rqst_", 227 new RoutingMessageReceiver(IntegrationTestInterface.MANAGER.buildStub(null, 228 IntegrationTestInterface.MANAGER.buildProxy( 229 null, new SinkMessageReceiver())), 230 IntegrationTestInterfaceTestHelper 231 .newIntegrationTestInterfaceMethodCallback())); 232 } 233 234 /** 235 * Testing the integration suite for response messages. 236 */ 237 @Test 238 @SmallTest testIntegrationResponseMessage()239 public void testIntegrationResponseMessage() throws FileNotFoundException { 240 runTest("integration_intf_resp_", 241 new RoutingMessageReceiver(IntegrationTestInterface.MANAGER.buildStub(null, 242 IntegrationTestInterface.MANAGER.buildProxy( 243 null, new SinkMessageReceiver())), 244 IntegrationTestInterfaceTestHelper 245 .newIntegrationTestInterfaceMethodCallback())); 246 } 247 } 248