1// Copyright 2019 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "testing" 19 "time" 20) 21 22func TestOncePer_Once(t *testing.T) { 23 once := OncePer{} 24 key := NewOnceKey("key") 25 26 a := once.Once(key, func() interface{} { return "a" }).(string) 27 b := once.Once(key, func() interface{} { return "b" }).(string) 28 29 if a != "a" { 30 t.Errorf(`first call to Once should return "a": %q`, a) 31 } 32 33 if b != "a" { 34 t.Errorf(`second call to Once with the same key should return "a": %q`, b) 35 } 36} 37 38func TestOncePer_Once_wait(t *testing.T) { 39 once := OncePer{} 40 key := NewOnceKey("key") 41 42 ch := make(chan bool) 43 44 go once.Once(key, func() interface{} { close(ch); time.Sleep(100 * time.Millisecond); return "foo" }) 45 <-ch 46 a := once.Once(key, func() interface{} { return "bar" }).(string) 47 48 if a != "foo" { 49 t.Errorf("expect %q, got %q", "foo", a) 50 } 51} 52 53func TestOncePer_Get(t *testing.T) { 54 once := OncePer{} 55 key := NewOnceKey("key") 56 57 a := once.Once(key, func() interface{} { return "a" }).(string) 58 b := once.Get(key).(string) 59 60 if a != "a" { 61 t.Errorf(`first call to Once should return "a": %q`, a) 62 } 63 64 if b != "a" { 65 t.Errorf(`Get with the same key should return "a": %q`, b) 66 } 67} 68 69func TestOncePer_Get_panic(t *testing.T) { 70 once := OncePer{} 71 key := NewOnceKey("key") 72 73 defer func() { 74 p := recover() 75 76 if p == nil { 77 t.Error("call to Get for unused key should panic") 78 } 79 }() 80 81 once.Get(key) 82} 83 84func TestOncePer_Get_wait(t *testing.T) { 85 once := OncePer{} 86 key := NewOnceKey("key") 87 88 ch := make(chan bool) 89 90 go once.Once(key, func() interface{} { close(ch); time.Sleep(100 * time.Millisecond); return "foo" }) 91 <-ch 92 a := once.Get(key).(string) 93 94 if a != "foo" { 95 t.Errorf("expect %q, got %q", "foo", a) 96 } 97} 98 99func TestOncePer_OnceStringSlice(t *testing.T) { 100 once := OncePer{} 101 key := NewOnceKey("key") 102 103 a := once.OnceStringSlice(key, func() []string { return []string{"a"} }) 104 b := once.OnceStringSlice(key, func() []string { return []string{"a"} }) 105 106 if a[0] != "a" { 107 t.Errorf(`first call to OnceStringSlice should return ["a"]: %q`, a) 108 } 109 110 if b[0] != "a" { 111 t.Errorf(`second call to OnceStringSlice with the same key should return ["a"]: %q`, b) 112 } 113} 114 115func TestOncePer_Once2StringSlice(t *testing.T) { 116 once := OncePer{} 117 key := NewOnceKey("key") 118 119 a, b := once.Once2StringSlice(key, func() ([]string, []string) { return []string{"a"}, []string{"b"} }) 120 c, d := once.Once2StringSlice(key, func() ([]string, []string) { return []string{"c"}, []string{"d"} }) 121 122 if a[0] != "a" || b[0] != "b" { 123 t.Errorf(`first call to Once2StringSlice should return ["a"], ["b"]: %q, %q`, a, b) 124 } 125 126 if c[0] != "a" || d[0] != "b" { 127 t.Errorf(`second call to Once2StringSlice with the same key should return ["a"], ["b"]: %q, %q`, c, d) 128 } 129} 130 131func TestNewOnceKey(t *testing.T) { 132 once := OncePer{} 133 key1 := NewOnceKey("key") 134 key2 := NewOnceKey("key") 135 136 a := once.Once(key1, func() interface{} { return "a" }).(string) 137 b := once.Once(key2, func() interface{} { return "b" }).(string) 138 139 if a != "a" { 140 t.Errorf(`first call to Once should return "a": %q`, a) 141 } 142 143 if b != "b" { 144 t.Errorf(`second call to Once with the NewOnceKey from same string should return "b": %q`, b) 145 } 146} 147 148func TestNewCustomOnceKey(t *testing.T) { 149 type key struct { 150 key string 151 } 152 once := OncePer{} 153 key1 := NewCustomOnceKey(key{"key"}) 154 key2 := NewCustomOnceKey(key{"key"}) 155 156 a := once.Once(key1, func() interface{} { return "a" }).(string) 157 b := once.Once(key2, func() interface{} { return "b" }).(string) 158 159 if a != "a" { 160 t.Errorf(`first call to Once should return "a": %q`, a) 161 } 162 163 if b != "a" { 164 t.Errorf(`second call to Once with the NewCustomOnceKey from equal key should return "a": %q`, b) 165 } 166} 167 168func TestOncePerReentrant(t *testing.T) { 169 once := OncePer{} 170 key1 := NewOnceKey("key") 171 key2 := NewOnceKey("key") 172 173 a := once.Once(key1, func() interface{} { return once.Once(key2, func() interface{} { return "a" }) }) 174 if a != "a" { 175 t.Errorf(`reentrant Once should return "a": %q`, a) 176 } 177} 178 179// Test that a recovered panic in a Once function doesn't deadlock 180func TestOncePerPanic(t *testing.T) { 181 once := OncePer{} 182 key := NewOnceKey("key") 183 184 ch := make(chan interface{}) 185 186 var a interface{} 187 188 go func() { 189 defer func() { 190 ch <- recover() 191 }() 192 193 a = once.Once(key, func() interface{} { 194 panic("foo") 195 }) 196 }() 197 198 p := <-ch 199 200 if p.(string) != "foo" { 201 t.Errorf(`expected panic with "foo", got %#v`, p) 202 } 203 204 if a != nil { 205 t.Errorf(`expected a to be nil, got %#v`, a) 206 } 207 208 // If the call to Once that panicked leaves the key in a bad state this will deadlock 209 b := once.Once(key, func() interface{} { 210 return "bar" 211 }) 212 213 // The second call to Once should return nil inserted by the first call that panicked. 214 if b != nil { 215 t.Errorf(`expected b to be nil, got %#v`, b) 216 } 217} 218