1// Copyright 2017, OpenCensus Authors 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// 15 16package tag 17 18import ( 19 "context" 20 "fmt" 21 "reflect" 22 "strings" 23 "testing" 24) 25 26var ( 27 ttlUnlimitedPropMd = createMetadatas(WithTTL(TTLUnlimitedPropagation)) 28 ttlNoPropMd = createMetadatas(WithTTL(TTLNoPropagation)) 29) 30 31func TestContext(t *testing.T) { 32 k1, _ := NewKey("k1") 33 k2, _ := NewKey("k2") 34 35 ctx := context.Background() 36 ctx, _ = New(ctx, 37 Insert(k1, "v1"), 38 Insert(k2, "v2"), 39 ) 40 got := FromContext(ctx) 41 want := newMap() 42 want.insert(k1, "v1", ttlUnlimitedPropMd) 43 want.insert(k2, "v2", ttlUnlimitedPropMd) 44 45 if !reflect.DeepEqual(got, want) { 46 t.Errorf("Map = %#v; want %#v", got, want) 47 } 48} 49 50func TestDo(t *testing.T) { 51 k1, _ := NewKey("k1") 52 k2, _ := NewKey("k2") 53 ctx := context.Background() 54 ctx, _ = New(ctx, 55 Insert(k1, "v1"), 56 Insert(k2, "v2"), 57 ) 58 got := FromContext(ctx) 59 want := newMap() 60 want.insert(k1, "v1", ttlUnlimitedPropMd) 61 want.insert(k2, "v2", ttlUnlimitedPropMd) 62 Do(ctx, func(ctx context.Context) { 63 got = FromContext(ctx) 64 }) 65 if !reflect.DeepEqual(got, want) { 66 t.Errorf("Map = %#v; want %#v", got, want) 67 } 68} 69 70func TestNewMap(t *testing.T) { 71 k1, _ := NewKey("k1") 72 k2, _ := NewKey("k2") 73 k3, _ := NewKey("k3") 74 k4, _ := NewKey("k4") 75 k5, _ := NewKey("k5") 76 77 initial := makeTestTagMap(5) 78 79 tests := []struct { 80 name string 81 initial *Map 82 mods []Mutator 83 want *Map 84 }{ 85 { 86 name: "from empty; insert", 87 initial: nil, 88 mods: []Mutator{ 89 Insert(k5, "v5"), 90 }, 91 want: makeTestTagMap(2, 4, 5), 92 }, 93 { 94 name: "from empty; insert existing", 95 initial: nil, 96 mods: []Mutator{ 97 Insert(k1, "v1"), 98 }, 99 want: makeTestTagMap(1, 2, 4), 100 }, 101 { 102 name: "from empty; update", 103 initial: nil, 104 mods: []Mutator{ 105 Update(k1, "v1"), 106 }, 107 want: makeTestTagMap(2, 4), 108 }, 109 { 110 name: "from empty; update unexisting", 111 initial: nil, 112 mods: []Mutator{ 113 Update(k5, "v5"), 114 }, 115 want: makeTestTagMap(2, 4), 116 }, 117 { 118 name: "from existing; upsert", 119 initial: initial, 120 mods: []Mutator{ 121 Upsert(k5, "v5"), 122 }, 123 want: makeTestTagMap(2, 4, 5), 124 }, 125 { 126 name: "from existing; delete", 127 initial: initial, 128 mods: []Mutator{ 129 Delete(k2), 130 }, 131 want: makeTestTagMap(4, 5), 132 }, 133 { 134 name: "from empty; invalid", 135 initial: nil, 136 mods: []Mutator{ 137 Insert(k5, "v\x19"), 138 Upsert(k5, "v\x19"), 139 Update(k5, "v\x19"), 140 }, 141 want: nil, 142 }, 143 { 144 name: "from empty; no partial", 145 initial: nil, 146 mods: []Mutator{ 147 Insert(k5, "v1"), 148 Update(k5, "v\x19"), 149 }, 150 want: nil, 151 }, 152 } 153 154 for _, tt := range tests { 155 mods := []Mutator{ 156 Insert(k1, "v1"), 157 Insert(k2, "v2"), 158 Update(k3, "v3"), 159 Upsert(k4, "v4"), 160 Insert(k2, "v2"), 161 Delete(k1), 162 } 163 mods = append(mods, tt.mods...) 164 ctx := NewContext(context.Background(), tt.initial) 165 ctx, err := New(ctx, mods...) 166 if tt.want != nil && err != nil { 167 t.Errorf("%v: New = %v", tt.name, err) 168 } 169 170 if got, want := FromContext(ctx), tt.want; !reflect.DeepEqual(got, want) { 171 t.Errorf("%v: got %v; want %v", tt.name, got, want) 172 } 173 } 174} 175 176func TestNewMapWithMetadata(t *testing.T) { 177 k3, _ := NewKey("k3") 178 k4, _ := NewKey("k4") 179 k5, _ := NewKey("k5") 180 181 tests := []struct { 182 name string 183 initial *Map 184 mods []Mutator 185 want *Map 186 }{ 187 { 188 name: "from empty; insert", 189 initial: nil, 190 mods: []Mutator{ 191 Insert(k5, "5", WithTTL(TTLNoPropagation)), 192 Insert(k4, "4"), 193 }, 194 want: makeTestTagMapWithMetadata( 195 tagContent{"5", ttlNoPropMd}, 196 tagContent{"4", ttlUnlimitedPropMd}), 197 }, 198 { 199 name: "from existing; insert existing", 200 initial: makeTestTagMapWithMetadata(tagContent{"5", ttlNoPropMd}), 201 mods: []Mutator{ 202 Insert(k5, "5", WithTTL(TTLUnlimitedPropagation)), 203 }, 204 want: makeTestTagMapWithMetadata(tagContent{"5", ttlNoPropMd}), 205 }, 206 { 207 name: "from existing; update non-existing", 208 initial: makeTestTagMapWithMetadata(tagContent{"5", ttlNoPropMd}), 209 mods: []Mutator{ 210 Update(k4, "4", WithTTL(TTLUnlimitedPropagation)), 211 }, 212 want: makeTestTagMapWithMetadata(tagContent{"5", ttlNoPropMd}), 213 }, 214 { 215 name: "from existing; update existing", 216 initial: makeTestTagMapWithMetadata( 217 tagContent{"5", ttlUnlimitedPropMd}, 218 tagContent{"4", ttlNoPropMd}), 219 mods: []Mutator{ 220 Update(k5, "5"), 221 Update(k4, "4", WithTTL(TTLUnlimitedPropagation)), 222 }, 223 want: makeTestTagMapWithMetadata( 224 tagContent{"5", ttlUnlimitedPropMd}, 225 tagContent{"4", ttlUnlimitedPropMd}), 226 }, 227 { 228 name: "from existing; upsert existing", 229 initial: makeTestTagMapWithMetadata( 230 tagContent{"5", ttlNoPropMd}, 231 tagContent{"4", ttlNoPropMd}), 232 mods: []Mutator{ 233 Upsert(k4, "4", WithTTL(TTLUnlimitedPropagation)), 234 }, 235 want: makeTestTagMapWithMetadata( 236 tagContent{"5", ttlNoPropMd}, 237 tagContent{"4", ttlUnlimitedPropMd}), 238 }, 239 { 240 name: "from existing; upsert non-existing", 241 initial: makeTestTagMapWithMetadata( 242 tagContent{"5", ttlNoPropMd}), 243 mods: []Mutator{ 244 Upsert(k4, "4", WithTTL(TTLUnlimitedPropagation)), 245 Upsert(k3, "3"), 246 }, 247 want: makeTestTagMapWithMetadata( 248 tagContent{"5", ttlNoPropMd}, 249 tagContent{"4", ttlUnlimitedPropMd}, 250 tagContent{"3", ttlUnlimitedPropMd}), 251 }, 252 { 253 name: "from existing; delete", 254 initial: makeTestTagMapWithMetadata( 255 tagContent{"5", ttlNoPropMd}, 256 tagContent{"4", ttlNoPropMd}), 257 mods: []Mutator{ 258 Delete(k5), 259 }, 260 want: makeTestTagMapWithMetadata( 261 tagContent{"4", ttlNoPropMd}), 262 }, 263 { 264 name: "from non-existing; upsert with multiple-metadata", 265 initial: nil, 266 mods: []Mutator{ 267 Upsert(k4, "4", WithTTL(TTLUnlimitedPropagation), WithTTL(TTLNoPropagation)), 268 Upsert(k5, "5", WithTTL(TTLNoPropagation), WithTTL(TTLUnlimitedPropagation)), 269 }, 270 want: makeTestTagMapWithMetadata( 271 tagContent{"4", ttlNoPropMd}, 272 tagContent{"5", ttlUnlimitedPropMd}), 273 }, 274 { 275 name: "from non-existing; insert with multiple-metadata", 276 initial: nil, 277 mods: []Mutator{ 278 Insert(k5, "5", WithTTL(TTLNoPropagation), WithTTL(TTLUnlimitedPropagation)), 279 }, 280 want: makeTestTagMapWithMetadata( 281 tagContent{"5", ttlUnlimitedPropMd}), 282 }, 283 { 284 name: "from existing; update with multiple-metadata", 285 initial: makeTestTagMapWithMetadata( 286 tagContent{"5", ttlNoPropMd}), 287 mods: []Mutator{ 288 Update(k5, "5", WithTTL(TTLNoPropagation), WithTTL(TTLUnlimitedPropagation)), 289 }, 290 want: makeTestTagMapWithMetadata( 291 tagContent{"5", ttlUnlimitedPropMd}), 292 }, 293 { 294 name: "from empty; update invalid", 295 initial: nil, 296 mods: []Mutator{ 297 Insert(k4, "4\x19", WithTTL(TTLUnlimitedPropagation)), 298 Upsert(k4, "4\x19", WithTTL(TTLUnlimitedPropagation)), 299 Update(k4, "4\x19", WithTTL(TTLUnlimitedPropagation)), 300 }, 301 want: nil, 302 }, 303 { 304 name: "from empty; insert partial", 305 initial: nil, 306 mods: []Mutator{ 307 Upsert(k3, "3", WithTTL(TTLUnlimitedPropagation)), 308 Upsert(k4, "4\x19", WithTTL(TTLUnlimitedPropagation)), 309 }, 310 want: nil, 311 }, 312 } 313 314 // Test api for insert, update, and upsert using metadata. 315 for _, tt := range tests { 316 ctx := NewContext(context.Background(), tt.initial) 317 ctx, err := New(ctx, tt.mods...) 318 if tt.want != nil && err != nil { 319 t.Errorf("%v: New = %v", tt.name, err) 320 } 321 322 if got, want := FromContext(ctx), tt.want; !reflect.DeepEqual(got, want) { 323 t.Errorf("%v: got %v; want %v", tt.name, got, want) 324 } 325 } 326} 327 328func TestNewValidation(t *testing.T) { 329 tests := []struct { 330 err string 331 seed *Map 332 }{ 333 // Key name validation in seed 334 {err: "invalid key", seed: &Map{m: map[Key]tagContent{{name: ""}: {"foo", ttlNoPropMd}}}}, 335 {err: "", seed: &Map{m: map[Key]tagContent{{name: "key"}: {"foo", ttlNoPropMd}}}}, 336 {err: "", seed: &Map{m: map[Key]tagContent{{name: strings.Repeat("a", 255)}: {"census", ttlNoPropMd}}}}, 337 {err: "invalid key", seed: &Map{m: map[Key]tagContent{{name: strings.Repeat("a", 256)}: {"census", ttlNoPropMd}}}}, 338 {err: "invalid key", seed: &Map{m: map[Key]tagContent{{name: "Приве́т"}: {"census", ttlNoPropMd}}}}, 339 340 // Value validation 341 {err: "", seed: &Map{m: map[Key]tagContent{{name: "key"}: {"", ttlNoPropMd}}}}, 342 {err: "", seed: &Map{m: map[Key]tagContent{{name: "key"}: {strings.Repeat("a", 255), ttlNoPropMd}}}}, 343 {err: "invalid value", seed: &Map{m: map[Key]tagContent{{name: "key"}: {"Приве́т", ttlNoPropMd}}}}, 344 {err: "invalid value", seed: &Map{m: map[Key]tagContent{{name: "key"}: {strings.Repeat("a", 256), ttlNoPropMd}}}}, 345 } 346 347 for i, tt := range tests { 348 ctx := NewContext(context.Background(), tt.seed) 349 ctx, err := New(ctx) 350 351 if tt.err != "" { 352 if err == nil { 353 t.Errorf("#%d: got nil error; want %q", i, tt.err) 354 continue 355 } else if s, substr := err.Error(), tt.err; !strings.Contains(s, substr) { 356 t.Errorf("#%d:\ngot %q\nwant %q", i, s, substr) 357 } 358 continue 359 } 360 if err != nil { 361 t.Errorf("#%d: got %q want nil", i, err) 362 continue 363 } 364 m := FromContext(ctx) 365 if m == nil { 366 t.Errorf("#%d: got nil map", i) 367 continue 368 } 369 } 370} 371 372func makeTestTagMap(ids ...int) *Map { 373 m := newMap() 374 for _, v := range ids { 375 k, _ := NewKey(fmt.Sprintf("k%d", v)) 376 m.m[k] = tagContent{fmt.Sprintf("v%d", v), ttlUnlimitedPropMd} 377 } 378 return m 379} 380 381func makeTestTagMapWithMetadata(tcs ...tagContent) *Map { 382 m := newMap() 383 for _, tc := range tcs { 384 k, _ := NewKey(fmt.Sprintf("k%s", tc.value)) 385 m.m[k] = tc 386 } 387 return m 388} 389