1 /* 2 * Copyright (C) 2022 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.systemui.flags 18 19 import android.testing.AndroidTestingRunner 20 import androidx.test.filters.SmallTest 21 import com.android.systemui.SysuiTestCase 22 import com.google.common.truth.Truth.assertThat 23 import org.junit.Assert.fail 24 import org.junit.Test 25 import org.junit.runner.RunWith 26 27 @SmallTest 28 @RunWith(AndroidTestingRunner::class) 29 class FakeFeatureFlagsTest : SysuiTestCase() { 30 31 private val unreleasedFlag = UnreleasedFlag("-1000", "test") 32 private val releasedFlag = ReleasedFlag("-1001", "test") 33 private val stringFlag = StringFlag("-1002", "test") 34 private val resourceBooleanFlag = ResourceBooleanFlag("-1003", "test", resourceId = -1) 35 private val resourceStringFlag = ResourceStringFlag("-1004", "test", resourceId = -1) 36 private val sysPropBooleanFlag = SysPropBooleanFlag("test", "test") 37 38 /** 39 * FakeFeatureFlags does not honor any default values. All flags which are accessed must be 40 * specified. If not, an exception is thrown. 41 */ 42 @Test 43 fun accessingUnspecifiedFlags_throwsException() { 44 val flags: FeatureFlags = FakeFeatureFlags() 45 try { 46 assertThat(flags.isEnabled(Flags.TEAMFOOD)).isFalse() 47 fail("Expected an exception when accessing an unspecified flag.") 48 } catch (ex: IllegalStateException) { 49 assertThat(ex.message).contains("UNKNOWN(teamfood)") 50 } 51 try { 52 assertThat(flags.isEnabled(unreleasedFlag)).isFalse() 53 fail("Expected an exception when accessing an unspecified flag.") 54 } catch (ex: IllegalStateException) { 55 assertThat(ex.message).contains("UNKNOWN(-1000)") 56 } 57 try { 58 assertThat(flags.isEnabled(releasedFlag)).isFalse() 59 fail("Expected an exception when accessing an unspecified flag.") 60 } catch (ex: IllegalStateException) { 61 assertThat(ex.message).contains("UNKNOWN(-1001)") 62 } 63 try { 64 assertThat(flags.isEnabled(resourceBooleanFlag)).isFalse() 65 fail("Expected an exception when accessing an unspecified flag.") 66 } catch (ex: IllegalStateException) { 67 assertThat(ex.message).contains("UNKNOWN(-1003)") 68 } 69 try { 70 assertThat(flags.isEnabled(sysPropBooleanFlag)).isFalse() 71 fail("Expected an exception when accessing an unspecified flag.") 72 } catch (ex: IllegalStateException) { 73 assertThat(ex.message).contains("UNKNOWN(test)") 74 } 75 try { 76 assertThat(flags.getString(stringFlag)).isEmpty() 77 fail("Expected an exception when accessing an unspecified flag.") 78 } catch (ex: IllegalStateException) { 79 assertThat(ex.message).contains("UNKNOWN(-1002)") 80 } 81 try { 82 assertThat(flags.getString(resourceStringFlag)).isEmpty() 83 fail("Expected an exception when accessing an unspecified flag.") 84 } catch (ex: IllegalStateException) { 85 assertThat(ex.message).contains("UNKNOWN(-1004)") 86 } 87 } 88 89 @Test 90 fun specifiedFlags_returnCorrectValues() { 91 val flags = FakeFeatureFlags() 92 flags.set(unreleasedFlag, false) 93 flags.set(releasedFlag, false) 94 flags.set(resourceBooleanFlag, false) 95 flags.set(sysPropBooleanFlag, false) 96 flags.set(resourceStringFlag, "") 97 98 assertThat(flags.isEnabled(unreleasedFlag)).isFalse() 99 assertThat(flags.isEnabled(releasedFlag)).isFalse() 100 assertThat(flags.isEnabled(resourceBooleanFlag)).isFalse() 101 assertThat(flags.isEnabled(sysPropBooleanFlag)).isFalse() 102 assertThat(flags.getString(resourceStringFlag)).isEmpty() 103 104 flags.set(unreleasedFlag, true) 105 flags.set(releasedFlag, true) 106 flags.set(resourceBooleanFlag, true) 107 flags.set(sysPropBooleanFlag, true) 108 flags.set(resourceStringFlag, "Android") 109 110 assertThat(flags.isEnabled(unreleasedFlag)).isTrue() 111 assertThat(flags.isEnabled(releasedFlag)).isTrue() 112 assertThat(flags.isEnabled(resourceBooleanFlag)).isTrue() 113 assertThat(flags.isEnabled(sysPropBooleanFlag)).isTrue() 114 assertThat(flags.getString(resourceStringFlag)).isEqualTo("Android") 115 } 116 117 @Test 118 fun listenerForBooleanFlag_calledOnlyWhenFlagChanged() { 119 val flags = FakeFeatureFlags() 120 val listener = VerifyingListener() 121 flags.addListener(unreleasedFlag, listener) 122 123 flags.set(unreleasedFlag, true) 124 flags.set(unreleasedFlag, true) 125 flags.set(unreleasedFlag, false) 126 flags.set(unreleasedFlag, false) 127 128 listener.verifyInOrder(unreleasedFlag.name, unreleasedFlag.name) 129 } 130 131 @Test 132 fun listenerForStringFlag_calledOnlyWhenFlagChanged() { 133 val flags = FakeFeatureFlags() 134 val listener = VerifyingListener() 135 flags.addListener(stringFlag, listener) 136 137 flags.set(stringFlag, "Test") 138 flags.set(stringFlag, "Test") 139 140 listener.verifyInOrder(stringFlag.name) 141 } 142 143 @Test 144 fun listenerForBooleanFlag_notCalledAfterRemoved() { 145 val flags = FakeFeatureFlags() 146 val listener = VerifyingListener() 147 flags.addListener(unreleasedFlag, listener) 148 flags.set(unreleasedFlag, true) 149 flags.removeListener(listener) 150 flags.set(unreleasedFlag, false) 151 152 listener.verifyInOrder(unreleasedFlag.name) 153 } 154 155 @Test 156 fun listenerForStringFlag_notCalledAfterRemoved() { 157 val flags = FakeFeatureFlags() 158 val listener = VerifyingListener() 159 160 flags.addListener(stringFlag, listener) 161 flags.set(stringFlag, "Test") 162 flags.removeListener(listener) 163 flags.set(stringFlag, "Other") 164 165 listener.verifyInOrder(stringFlag.name) 166 } 167 168 @Test 169 fun listenerForMultipleFlags_calledWhenFlagsChange() { 170 val flags = FakeFeatureFlags() 171 val listener = VerifyingListener() 172 flags.addListener(unreleasedFlag, listener) 173 flags.addListener(releasedFlag, listener) 174 175 flags.set(releasedFlag, true) 176 flags.set(unreleasedFlag, true) 177 178 listener.verifyInOrder(releasedFlag.name, unreleasedFlag.name) 179 } 180 181 @Test 182 fun listenerForMultipleFlags_notCalledAfterRemoved() { 183 val flags = FakeFeatureFlags() 184 val listener = VerifyingListener() 185 186 flags.addListener(unreleasedFlag, listener) 187 flags.addListener(releasedFlag, listener) 188 flags.set(releasedFlag, true) 189 flags.set(unreleasedFlag, true) 190 flags.removeListener(listener) 191 flags.set(releasedFlag, false) 192 flags.set(unreleasedFlag, false) 193 194 listener.verifyInOrder(releasedFlag.name, unreleasedFlag.name) 195 } 196 197 @Test 198 fun multipleListenersForSingleFlag_allAreCalledWhenChanged() { 199 val flags = FakeFeatureFlags() 200 val listener1 = VerifyingListener() 201 val listener2 = VerifyingListener() 202 flags.addListener(releasedFlag, listener1) 203 flags.addListener(releasedFlag, listener2) 204 205 flags.set(releasedFlag, true) 206 207 listener1.verifyInOrder(releasedFlag.name) 208 listener2.verifyInOrder(releasedFlag.name) 209 } 210 211 @Test 212 fun multipleListenersForSingleFlag_removedListenerNotCalledAfterRemoval() { 213 val flags = FakeFeatureFlags() 214 val listener1 = VerifyingListener() 215 val listener2 = VerifyingListener() 216 flags.addListener(releasedFlag, listener1) 217 flags.addListener(releasedFlag, listener2) 218 219 flags.set(releasedFlag, true) 220 flags.removeListener(listener2) 221 flags.set(releasedFlag, false) 222 223 listener1.verifyInOrder(releasedFlag.name, releasedFlag.name) 224 listener2.verifyInOrder(releasedFlag.name) 225 } 226 227 class VerifyingListener : FlagListenable.Listener { 228 var flagEventNames = mutableListOf<String>() 229 override fun onFlagChanged(event: FlagListenable.FlagEvent) { 230 flagEventNames.add(event.flagName) 231 } 232 233 fun verifyInOrder(vararg eventNames: String) { 234 assertThat(flagEventNames).containsExactlyElementsIn(eventNames.asList()) 235 } 236 } 237 } 238