1 /* 2 * Copyright (C) 2018 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.server.signedconfig; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.fail; 22 23 import static java.util.Collections.emptyMap; 24 import static java.util.Collections.emptySet; 25 26 import android.util.ArrayMap; 27 28 import androidx.test.runner.AndroidJUnit4; 29 30 import com.google.common.collect.Sets; 31 32 import org.json.JSONException; 33 import org.json.JSONObject; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 import java.util.Arrays; 38 import java.util.Collections; 39 import java.util.Map; 40 import java.util.Set; 41 42 43 /** 44 * Tests for {@link SignedConfig} 45 */ 46 @RunWith(AndroidJUnit4.class) 47 public class SignedConfigTest { 48 setOf(String... values)49 private static Set<String> setOf(String... values) { 50 return Sets.newHashSet(values); 51 } 52 mapOf(Object... keyValuePairs)53 private static <K, V> Map<K, V> mapOf(Object... keyValuePairs) { 54 if (keyValuePairs.length % 2 != 0) { 55 throw new IllegalArgumentException(); 56 } 57 final int len = keyValuePairs.length / 2; 58 ArrayMap<K, V> m = new ArrayMap<>(len); 59 for (int i = 0; i < len; ++i) { 60 m.put((K) keyValuePairs[i * 2], (V) keyValuePairs[(i * 2) + 1]); 61 } 62 return Collections.unmodifiableMap(m); 63 64 } 65 66 67 @Test testParsePerSdkConfigSdkMinMax()68 public void testParsePerSdkConfigSdkMinMax() throws JSONException, InvalidConfigException { 69 JSONObject json = new JSONObject("{\"min_sdk\":2, \"max_sdk\": 3, \"values\": {}}"); 70 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, emptySet(), 71 emptyMap()); 72 assertThat(config.minSdk).isEqualTo(2); 73 assertThat(config.maxSdk).isEqualTo(3); 74 } 75 76 @Test testParsePerSdkConfigNoMinSdk()77 public void testParsePerSdkConfigNoMinSdk() throws JSONException { 78 JSONObject json = new JSONObject("{\"max_sdk\": 3, \"values\": {}}"); 79 try { 80 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 81 fail("Expected InvalidConfigException or JSONException"); 82 } catch (JSONException | InvalidConfigException e) { 83 // expected 84 } 85 } 86 87 @Test testParsePerSdkConfigNoMaxSdk()88 public void testParsePerSdkConfigNoMaxSdk() throws JSONException { 89 JSONObject json = new JSONObject("{\"min_sdk\": 1, \"values\": {}}"); 90 try { 91 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 92 fail("Expected InvalidConfigException or JSONException"); 93 } catch (JSONException | InvalidConfigException e) { 94 // expected 95 } 96 } 97 98 @Test testParsePerSdkConfigNoValues()99 public void testParsePerSdkConfigNoValues() throws JSONException { 100 JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 3}"); 101 try { 102 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 103 fail("Expected InvalidConfigException or JSONException"); 104 } catch (JSONException | InvalidConfigException e) { 105 // expected 106 } 107 } 108 109 @Test testParsePerSdkConfigSdkNullMinSdk()110 public void testParsePerSdkConfigSdkNullMinSdk() throws JSONException { 111 JSONObject json = new JSONObject("{\"min_sdk\":null, \"max_sdk\": 3, \"values\": {}}"); 112 try { 113 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 114 fail("Expected InvalidConfigException or JSONException"); 115 } catch (JSONException | InvalidConfigException e) { 116 // expected 117 } 118 } 119 120 @Test testParsePerSdkConfigSdkNullMaxSdk()121 public void testParsePerSdkConfigSdkNullMaxSdk() throws JSONException { 122 JSONObject json = new JSONObject("{\"min_sdk\":1, \"max_sdk\": null, \"values\": {}}"); 123 try { 124 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 125 fail("Expected InvalidConfigException or JSONException"); 126 } catch (JSONException | InvalidConfigException e) { 127 // expected 128 } 129 } 130 131 @Test testParsePerSdkConfigNullValues()132 public void testParsePerSdkConfigNullValues() throws JSONException { 133 JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 3, \"values\": null}"); 134 try { 135 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 136 fail("Expected InvalidConfigException or JSONException"); 137 } catch (JSONException | InvalidConfigException e) { 138 // expected 139 } 140 } 141 142 @Test testParsePerSdkConfigZeroValues()143 public void testParsePerSdkConfigZeroValues() 144 throws JSONException, InvalidConfigException { 145 JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 3, \"values\": {}}"); 146 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), 147 emptyMap()); 148 assertThat(config.values).hasSize(0); 149 } 150 151 @Test testParsePerSdkConfigSingleKey()152 public void testParsePerSdkConfigSingleKey() 153 throws JSONException, InvalidConfigException { 154 JSONObject json = new JSONObject( 155 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); 156 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), 157 emptyMap()); 158 assertThat(config.values).containsExactly("a", "1"); 159 } 160 161 @Test testParsePerSdkConfigSingleKeyNullValue()162 public void testParsePerSdkConfigSingleKeyNullValue() 163 throws JSONException, InvalidConfigException { 164 JSONObject json = new JSONObject( 165 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": null}}"); 166 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), 167 emptyMap()); 168 assertThat(config.values.keySet()).containsExactly("a"); 169 assertThat(config.values.get("a")).isNull(); 170 } 171 172 @Test testParsePerSdkConfigMultiKeys()173 public void testParsePerSdkConfigMultiKeys() 174 throws JSONException, InvalidConfigException { 175 JSONObject json = new JSONObject( 176 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\", \"c\": \"2\"}}"); 177 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig( 178 json, setOf("a", "b", "c"), emptyMap()); 179 assertThat(config.values).containsExactly("a", "1", "c", "2"); 180 } 181 182 @Test testParsePerSdkConfigSingleKeyNotAllowed()183 public void testParsePerSdkConfigSingleKeyNotAllowed() throws JSONException { 184 JSONObject json = new JSONObject( 185 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); 186 try { 187 SignedConfig.parsePerSdkConfig(json, setOf("b"), emptyMap()); 188 fail("Expected InvalidConfigException or JSONException"); 189 } catch (JSONException | InvalidConfigException e) { 190 // expected 191 } 192 } 193 194 @Test testParsePerSdkConfigSingleKeyWithMap()195 public void testParsePerSdkConfigSingleKeyWithMap() 196 throws JSONException, InvalidConfigException { 197 JSONObject json = new JSONObject( 198 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); 199 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a"), 200 mapOf("a", mapOf("1", "one"))); 201 assertThat(config.values).containsExactly("a", "one"); 202 } 203 204 @Test testParsePerSdkConfigSingleKeyWithMapInvalidValue()205 public void testParsePerSdkConfigSingleKeyWithMapInvalidValue() throws JSONException { 206 JSONObject json = new JSONObject( 207 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"2\"}}"); 208 try { 209 SignedConfig.parsePerSdkConfig(json, setOf("b"), mapOf("a", mapOf("1", "one"))); 210 fail("Expected InvalidConfigException"); 211 } catch (InvalidConfigException e) { 212 // expected 213 } 214 } 215 216 @Test testParsePerSdkConfigMultiKeysWithMap()217 public void testParsePerSdkConfigMultiKeysWithMap() 218 throws JSONException, InvalidConfigException { 219 JSONObject json = new JSONObject( 220 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\", \"b\": \"1\"}}"); 221 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"), 222 mapOf("a", mapOf("1", "one"))); 223 assertThat(config.values).containsExactly("a", "one", "b", "1"); 224 } 225 226 @Test testParsePerSdkConfigSingleKeyWithMapToNull()227 public void testParsePerSdkConfigSingleKeyWithMapToNull() 228 throws JSONException, InvalidConfigException { 229 JSONObject json = new JSONObject( 230 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": \"1\"}}"); 231 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a"), 232 mapOf("a", mapOf("1", null))); 233 assertThat(config.values).containsExactly("a", null); 234 } 235 236 @Test testParsePerSdkConfigSingleKeyWithMapFromNull()237 public void testParsePerSdkConfigSingleKeyWithMapFromNull() 238 throws JSONException, InvalidConfigException { 239 assertThat(mapOf(null, "allitnil")).containsExactly(null, "allitnil"); 240 assertThat(mapOf(null, "allitnil").containsKey(null)).isTrue(); 241 JSONObject json = new JSONObject( 242 "{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {\"a\": null}}"); 243 SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a"), 244 mapOf("a", mapOf(null, "allitnil"))); 245 assertThat(config.values).containsExactly("a", "allitnil"); 246 } 247 248 @Test testParsePerSdkConfigValuesInvalid()249 public void testParsePerSdkConfigValuesInvalid() throws JSONException { 250 JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": \"foo\"}"); 251 try { 252 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 253 fail("Expected InvalidConfigException or JSONException"); 254 } catch (JSONException | InvalidConfigException e) { 255 // expected 256 } 257 } 258 259 @Test testParsePerSdkConfigConfigEntryInvalid()260 public void testParsePerSdkConfigConfigEntryInvalid() throws JSONException { 261 JSONObject json = new JSONObject("{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": [1, 2]}"); 262 try { 263 SignedConfig.parsePerSdkConfig(json, emptySet(), emptyMap()); 264 fail("Expected InvalidConfigException or JSONException"); 265 } catch (JSONException | InvalidConfigException e) { 266 // expected 267 } 268 } 269 270 @Test testParseVersion()271 public void testParseVersion() throws InvalidConfigException { 272 SignedConfig config = SignedConfig.parse( 273 "{\"version\": 1, \"config\": []}", emptySet(), emptyMap()); 274 assertThat(config.version).isEqualTo(1); 275 } 276 277 @Test testParseVersionInvalid()278 public void testParseVersionInvalid() { 279 try { 280 SignedConfig.parse("{\"version\": \"notanint\", \"config\": []}", emptySet(), 281 emptyMap()); 282 fail("Expected InvalidConfigException"); 283 } catch (InvalidConfigException e) { 284 //expected 285 } 286 } 287 288 @Test testParseNoVersion()289 public void testParseNoVersion() { 290 try { 291 SignedConfig.parse("{\"config\": []}", emptySet(), emptyMap()); 292 fail("Expected InvalidConfigException"); 293 } catch (InvalidConfigException e) { 294 //expected 295 } 296 } 297 298 @Test testParseNoConfig()299 public void testParseNoConfig() { 300 try { 301 SignedConfig.parse("{\"version\": 1}", emptySet(), emptyMap()); 302 fail("Expected InvalidConfigException"); 303 } catch (InvalidConfigException e) { 304 //expected 305 } 306 } 307 308 @Test testParseConfigNull()309 public void testParseConfigNull() { 310 try { 311 SignedConfig.parse("{\"version\": 1, \"config\": null}", emptySet(), emptyMap()); 312 fail("Expected InvalidConfigException"); 313 } catch (InvalidConfigException e) { 314 //expected 315 } 316 } 317 318 @Test testParseVersionNull()319 public void testParseVersionNull() { 320 try { 321 SignedConfig.parse("{\"version\": null, \"config\": []}", emptySet(), emptyMap()); 322 fail("Expected InvalidConfigException"); 323 } catch (InvalidConfigException e) { 324 //expected 325 } 326 } 327 328 @Test testParseConfigInvalidEntry()329 public void testParseConfigInvalidEntry() { 330 try { 331 SignedConfig.parse("{\"version\": 1, \"config\": [{}]}", emptySet(), emptyMap()); 332 fail("Expected InvalidConfigException"); 333 } catch (InvalidConfigException e) { 334 //expected 335 } 336 } 337 338 @Test testParseSdkConfigSingle()339 public void testParseSdkConfigSingle() throws InvalidConfigException { 340 SignedConfig config = SignedConfig.parse( 341 "{\"version\": 1, \"config\":[{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {}}]}", 342 emptySet(), emptyMap()); 343 assertThat(config.perSdkConfig).hasSize(1); 344 } 345 346 @Test testParseSdkConfigMultiple()347 public void testParseSdkConfigMultiple() throws InvalidConfigException { 348 SignedConfig config = SignedConfig.parse( 349 "{\"version\": 1, \"config\":[{\"min_sdk\": 1, \"max_sdk\": 1, \"values\": {}}, " 350 + "{\"min_sdk\": 2, \"max_sdk\": 2, \"values\": {}}]}", emptySet(), 351 emptyMap()); 352 assertThat(config.perSdkConfig).hasSize(2); 353 } 354 355 @Test testGetMatchingConfigFirst()356 public void testGetMatchingConfigFirst() { 357 SignedConfig.PerSdkConfig sdk1 = new SignedConfig.PerSdkConfig( 358 1, 1, Collections.emptyMap()); 359 SignedConfig.PerSdkConfig sdk2 = new SignedConfig.PerSdkConfig( 360 2, 2, Collections.emptyMap()); 361 SignedConfig config = new SignedConfig(0, Arrays.asList(sdk1, sdk2)); 362 assertThat(config.getMatchingConfig(1)).isEqualTo(sdk1); 363 } 364 365 @Test testGetMatchingConfigSecond()366 public void testGetMatchingConfigSecond() { 367 SignedConfig.PerSdkConfig sdk1 = new SignedConfig.PerSdkConfig( 368 1, 1, Collections.emptyMap()); 369 SignedConfig.PerSdkConfig sdk2 = new SignedConfig.PerSdkConfig( 370 2, 2, Collections.emptyMap()); 371 SignedConfig config = new SignedConfig(0, Arrays.asList(sdk1, sdk2)); 372 assertThat(config.getMatchingConfig(2)).isEqualTo(sdk2); 373 } 374 375 @Test testGetMatchingConfigInRange()376 public void testGetMatchingConfigInRange() { 377 SignedConfig.PerSdkConfig sdk13 = new SignedConfig.PerSdkConfig( 378 1, 3, Collections.emptyMap()); 379 SignedConfig.PerSdkConfig sdk46 = new SignedConfig.PerSdkConfig( 380 4, 6, Collections.emptyMap()); 381 SignedConfig config = new SignedConfig(0, Arrays.asList(sdk13, sdk46)); 382 assertThat(config.getMatchingConfig(2)).isEqualTo(sdk13); 383 } 384 @Test testGetMatchingConfigNoMatch()385 public void testGetMatchingConfigNoMatch() { 386 SignedConfig.PerSdkConfig sdk1 = new SignedConfig.PerSdkConfig( 387 1, 1, Collections.emptyMap()); 388 SignedConfig.PerSdkConfig sdk2 = new SignedConfig.PerSdkConfig( 389 2, 2, Collections.emptyMap()); 390 SignedConfig config = new SignedConfig(0, Arrays.asList(sdk1, sdk2)); 391 assertThat(config.getMatchingConfig(3)).isNull(); 392 } 393 394 } 395