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 package com.android.car; 18 19 import static org.junit.Assert.assertTrue; 20 21 import android.car.vms.VmsLayer; 22 import android.car.vms.VmsLayerDependency; 23 import android.car.vms.VmsLayersOffering; 24 import android.car.vms.VmsOperationRecorder; 25 import android.util.Log; 26 27 import androidx.test.ext.junit.runners.AndroidJUnit4; 28 import androidx.test.filters.MediumTest; 29 30 import org.json.JSONArray; 31 import org.json.JSONException; 32 import org.json.JSONObject; 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 import java.util.Arrays; 38 import java.util.HashSet; 39 40 @RunWith(AndroidJUnit4.class) 41 @MediumTest 42 public class VmsOperationRecorderTest { 43 44 /** 45 * Capture messages that VmsOperationRecorder.Writer would normally pass to Log.d(...). 46 */ 47 class TestWriter extends VmsOperationRecorder.Writer { 48 public String mMsg; 49 50 @Override isEnabled()51 public boolean isEnabled() { 52 return true; 53 } 54 55 @Override write(String msg)56 public void write(String msg) { 57 super.write(msg); 58 mMsg = msg; 59 } 60 } 61 62 private TestWriter mWriter; 63 private VmsOperationRecorder mRecorder; 64 private static final String TAG = "VmsOperationRecorderTest"; 65 66 private static final VmsLayer layer1 = new VmsLayer(1, 3, 2); 67 private static final VmsLayer layer2 = new VmsLayer(2, 4, 3); 68 private static final VmsLayer layer3 = new VmsLayer(3, 5, 4); 69 70 private static final VmsLayerDependency layerDependency1 = new VmsLayerDependency(layer3); 71 private static final VmsLayerDependency layerDependency2 = new VmsLayerDependency(layer1, 72 new HashSet<VmsLayer>(Arrays.asList(layer2, layer3))); 73 74 private static final VmsLayersOffering layersOffering0 = new VmsLayersOffering( 75 new HashSet<VmsLayerDependency>(), 66); 76 private static final VmsLayersOffering layersOffering1 = new VmsLayersOffering( 77 new HashSet<>(Arrays.asList(layerDependency1)), 66); 78 private static final VmsLayersOffering layersOffering2 = new VmsLayersOffering( 79 new HashSet<>(Arrays.asList(layerDependency1, layerDependency2)), 66); 80 81 @Before setUp()82 public void setUp() { 83 mWriter = new TestWriter(); 84 mRecorder = new VmsOperationRecorder(mWriter); 85 } 86 87 @Test testSubscribe()88 public void testSubscribe() throws Exception { 89 mRecorder.subscribe(layer1); 90 assertJsonMsgEquals("{'subscribe':{'layer':{'subtype':3,'type':1,'version':2}}}"); 91 } 92 93 @Test testUnsubscribe()94 public void testUnsubscribe() throws Exception { 95 mRecorder.unsubscribe(layer1); 96 assertJsonMsgEquals("{'unsubscribe':{'layer':{'type':1,'subtype':3,'version':2}}}"); 97 } 98 99 @Test testStartMonitoring()100 public void testStartMonitoring() throws Exception { 101 mRecorder.startMonitoring(); 102 assertJsonMsgEquals("{'startMonitoring':{}}"); 103 } 104 105 @Test testStopMonitoring()106 public void testStopMonitoring() throws Exception { 107 mRecorder.stopMonitoring(); 108 assertJsonMsgEquals("{'stopMonitoring':{}}"); 109 } 110 111 @Test testSetLayersOffering0()112 public void testSetLayersOffering0() throws Exception { 113 mRecorder.setLayersOffering(layersOffering0); 114 assertJsonMsgEquals("{'setLayersOffering':{'publisherId':66}}"); 115 } 116 117 @Test testSetLayersOffering2()118 public void testSetLayersOffering2() throws Exception { 119 mRecorder.setLayersOffering(layersOffering2); 120 assertJsonMsgEquals("{'setLayersOffering':{'publisherId':66,'layerDependency':[" 121 + "{'layer':{'type':3,'subtype':5,'version':4}}," 122 + "{'layer':{'type':1,'subtype':3,'version':2},'dependency':[" 123 + "{'type':2,'subtype':4,'version':3},{'type':3,'subtype':5,'version':4}]}" 124 + "]}}"); 125 } 126 127 @Test testGetPublisherId()128 public void testGetPublisherId() throws Exception { 129 mRecorder.getPublisherId(9); 130 assertJsonMsgEquals("{'getPublisherId':{'publisherId':9}}"); 131 } 132 133 @Test testAddSubscription()134 public void testAddSubscription() throws Exception { 135 mRecorder.addSubscription(42, layer1); 136 assertJsonMsgEquals( 137 "{'addSubscription':{'sequenceNumber':42,'layer':{'type':1,'subtype':3,'version':2}}}" 138 ); 139 } 140 141 @Test testRemoveSubscription()142 public void testRemoveSubscription() throws Exception { 143 mRecorder.removeSubscription(42, layer1); 144 assertJsonMsgEquals("{'removeSubscription':" 145 + "{'sequenceNumber':42,'layer':{'type':1,'subtype':3,'version':2}}}"); 146 } 147 148 @Test testAddPromiscuousSubscription()149 public void testAddPromiscuousSubscription() throws Exception { 150 mRecorder.addPromiscuousSubscription(42); 151 assertJsonMsgEquals("{'addPromiscuousSubscription':{'sequenceNumber':42}}"); 152 } 153 154 @Test testRemovePromiscuousSubscription()155 public void testRemovePromiscuousSubscription() throws Exception { 156 mRecorder.removePromiscuousSubscription(42); 157 assertJsonMsgEquals("{'removePromiscuousSubscription':{'sequenceNumber':42}}"); 158 } 159 160 @Test testAddHalSubscription()161 public void testAddHalSubscription() throws Exception { 162 mRecorder.addHalSubscription(42, layer1); 163 assertJsonMsgEquals("{'addHalSubscription':" 164 + "{'sequenceNumber':42,'layer':{'type':1,'subtype':3,'version':2}}}"); 165 } 166 167 @Test testRemoveHalSubscription()168 public void testRemoveHalSubscription() throws Exception { 169 mRecorder.removeHalSubscription(42, layer1); 170 assertJsonMsgEquals("{'removeHalSubscription':" 171 + "{'sequenceNumber':42,'layer':{'type':1,'subtype':3,'version':2}}}"); 172 } 173 174 @Test testSetPublisherLayersOffering()175 public void testSetPublisherLayersOffering() throws Exception { 176 mRecorder.setPublisherLayersOffering(layersOffering1); 177 assertJsonMsgEquals("{'setPublisherLayersOffering':{'publisherId':66,'layerDependency':[" 178 + "{'layer':{'type':3,'subtype':5,'version':4}}]}}"); 179 } 180 testSetHalPublisherLayersOffering()181 @Test public void testSetHalPublisherLayersOffering() throws Exception { 182 mRecorder.setHalPublisherLayersOffering(layersOffering1); 183 assertJsonMsgEquals("{'setHalPublisherLayersOffering':{'publisherId':66,'layerDependency':[" 184 + "{'layer':{'type':3,'subtype':5,'version':4}}]}}"); 185 } 186 187 @Test testSubscribeToPublisher()188 public void testSubscribeToPublisher() throws Exception { 189 mRecorder.subscribe(layer1, 99); 190 assertJsonMsgEquals( 191 "{'subscribe':{'publisherId':99, 'layer':{'type':1,'subtype':3,'version':2}}}"); 192 } 193 194 @Test testUnsubscribeToPublisher()195 public void testUnsubscribeToPublisher() throws Exception { 196 mRecorder.unsubscribe(layer1, 99); 197 assertJsonMsgEquals( 198 "{'unsubscribe':{'publisherId':99, 'layer':{'type':1,'subtype':3,'version':2}}}}"); 199 } 200 assertJsonMsgEquals(String expectJson)201 private void assertJsonMsgEquals(String expectJson) throws Exception { 202 // Escaping double quotes in a JSON string is really noisy. The test data uses single 203 // quotes instead, which gets replaced here. 204 JSONObject expect = new JSONObject(expectJson.replace("'", "\"")); 205 JSONObject got = new JSONObject(mWriter.mMsg); 206 assertTrue(similar(expect, got)); 207 } 208 209 /* 210 * Determine if two JSONObjects are similar. 211 * They must contain the same set of names which must be associated with 212 * similar values. 213 */ similar(JSONObject expect, JSONObject got)214 private boolean similar(JSONObject expect, JSONObject got) { 215 try { 216 if (!expect.keySet().equals(got.keySet())) { 217 return false; 218 } 219 220 for (String key : expect.keySet()) { 221 Object valueExpect = expect.get(key); 222 Object valueGot = got.get(key); 223 224 if (valueExpect == valueGot) { 225 continue; 226 } 227 228 if (valueExpect == null) { 229 return false; 230 } 231 232 if (valueExpect instanceof JSONObject) { 233 return similar((JSONObject) valueExpect, (JSONObject) valueGot); 234 } else if (valueExpect instanceof JSONArray) { 235 // Equal JSONArray have the same length and one contains the other. 236 JSONArray expectArray = (JSONArray) valueExpect; 237 JSONArray gotArray = (JSONArray) valueGot; 238 239 if (expectArray.length() != gotArray.length()) { 240 return false; 241 } 242 243 for (int i = 0; i < expectArray.length(); i++) { 244 boolean gotContainsSimilar = false; 245 for (int j = 0; j < gotArray.length(); j++) { 246 if (similar((JSONObject) expectArray.get(i), 247 (JSONObject) gotArray.get(j))) { 248 gotContainsSimilar = true; 249 break; 250 } 251 } 252 if (!gotContainsSimilar) { 253 return false; 254 } 255 } 256 } else if (!valueExpect.equals(valueGot)) { 257 return false; 258 } 259 } 260 261 } catch (JSONException e) { 262 Log.d(TAG, "Could not compare JSONObjects: " + e); 263 return false; 264 } 265 return true; 266 } 267 } 268