1 /*
2  * Copyright (C) 2023 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.wm;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.mockito.ArgumentMatchers.any;
26 
27 import android.app.ActivityThread;
28 import android.platform.test.annotations.Presubmit;
29 import android.provider.DeviceConfig;
30 
31 import androidx.test.filters.SmallTest;
32 
33 import com.android.modules.utils.testing.TestableDeviceConfig;
34 
35 import org.junit.After;
36 import org.junit.Assert;
37 import org.junit.Before;
38 import org.junit.Rule;
39 import org.junit.Test;
40 
41 import java.util.Objects;
42 import java.util.concurrent.CountDownLatch;
43 import java.util.concurrent.Executor;
44 import java.util.concurrent.TimeUnit;
45 
46 /**
47  * Test class for {@link SynchedDeviceConfig}.
48  *
49  * atest WmTests:SynchedDeviceConfigTests
50  */
51 @SmallTest
52 @Presubmit
53 public class SynchedDeviceConfigTests {
54 
55     private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
56     private static final String NAMESPACE_FOR_TEST = "TestingNameSpace";
57 
58     private SynchedDeviceConfig mDeviceConfig;
59 
60     private Executor mExecutor;
61 
62     @Rule
63     public final TestableDeviceConfig.TestableDeviceConfigRule
64             mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
65 
66     @Before
setUp()67     public void setUp() {
68         mExecutor = Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor();
69         mDeviceConfig = SynchedDeviceConfig
70                 .builder(/* nameSpace */ NAMESPACE_FOR_TEST, /* executor */ mExecutor)
71                 .addDeviceConfigEntry(/* key */ "key1", /* default */ true, /* enabled */ true)
72                 .addDeviceConfigEntry(/* key */ "key2", /* default */ false, /* enabled */ true)
73                 .addDeviceConfigEntry(/* key */ "key3",  /* default */ true, /* enabled */ false)
74                 .addDeviceConfigEntry(/* key */ "key4",  /* default */ false, /* enabled */ false)
75                 .build();
76     }
77 
78     @After
tearDown()79     public void tearDown() {
80         DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfig);
81     }
82 
83     @Test
testWhenStarted_initialValuesAreDefaultOrFalseIfDisabled()84     public void testWhenStarted_initialValuesAreDefaultOrFalseIfDisabled() {
85         assertFlagValue(/* key */ "key1", /* expected */ true); // enabled
86         assertFlagValue(/* key */ "key2", /* expected */ false); // enabled
87         assertFlagValue(/* key */ "key3", /* expected */ false); // disabled
88         assertFlagValue(/* key */ "key4", /* expected */ false); // disabled
89     }
90 
91     @Test
testIsEnabled()92     public void testIsEnabled() {
93         assertFlagEnabled(/* key */ "key1", /* expected */ true);
94         assertFlagEnabled(/* key */ "key2", /* expected */ true);
95         assertFlagEnabled(/* key */ "key3", /* expected */ false);
96         assertFlagEnabled(/* key */ "key4", /* expected */ false);
97     }
98 
99     @Test
testWhenUpdated_onlyEnabledChanges()100     public void testWhenUpdated_onlyEnabledChanges() {
101         final CountDownLatch countDownLatch = new CountDownLatch(4);
102         spyOn(mDeviceConfig);
103         doAnswer(invocation -> {
104             invocation.callRealMethod();
105             countDownLatch.countDown();
106             return null;
107         }).when(mDeviceConfig).onPropertiesChanged(any());
108         try {
109             // We update all the keys
110             updateProperty(/* key */ "key1", /* value */ false);
111             updateProperty(/* key */ "key2", /* value */ true);
112             updateProperty(/* key */ "key3", /* value */ false);
113             updateProperty(/* key */ "key4", /* value */ true);
114 
115             assertThat(countDownLatch.await(
116                     WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
117 
118             // We update all the flags but only the enabled ones change
119             assertFlagValue(/* key */ "key1", /* expected */ false); // changes
120             assertFlagValue(/* key */ "key2", /* expected */ true); // changes
121             assertFlagValue(/* key */ "key3", /* expected */ false); // disabled
122             assertFlagValue(/* key */ "key4", /* expected */ false); // disabled
123         } catch (InterruptedException e) {
124             Assert.fail(e.getMessage());
125         }
126     }
127 
assertFlagValue(String key, boolean expectedValue)128     private void assertFlagValue(String key, boolean expectedValue) {
129         assertEquals(/* message */"Flag " + key + " value is not " + expectedValue, /* expected */
130                 expectedValue, /* actual */ mDeviceConfig.getFlagValue(key));
131     }
132 
133 
assertFlagEnabled(String key, boolean expectedValue)134     private void assertFlagEnabled(String key, boolean expectedValue) {
135         assertEquals(/* message */
136                 "Flag " + key + " enabled is not " + expectedValue, /* expected */
137                 expectedValue, /* actual */ mDeviceConfig.isBuildTimeFlagEnabled(key));
138     }
139 
updateProperty(String key, Boolean value)140     private void updateProperty(String key, Boolean value) {
141         DeviceConfig.setProperty(NAMESPACE_FOR_TEST, key, /* value */
142                 value.toString(), /* makeDefault */ false);
143     }
144 }
145