1 /* 2 * Copyright 2016-17, OpenCensus Authors 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 io.opencensus.implcore.tags.propagation; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import com.google.common.base.Charsets; 22 import com.google.common.collect.Collections2; 23 import io.opencensus.implcore.internal.VarInt; 24 import io.opencensus.implcore.tags.TagsComponentImplBase; 25 import io.opencensus.tags.Tag; 26 import io.opencensus.tags.TagContext; 27 import io.opencensus.tags.TagContextBuilder; 28 import io.opencensus.tags.TagKey; 29 import io.opencensus.tags.TagValue; 30 import io.opencensus.tags.Tagger; 31 import io.opencensus.tags.TagsComponent; 32 import io.opencensus.tags.propagation.TagContextBinarySerializer; 33 import io.opencensus.tags.propagation.TagContextSerializationException; 34 import java.io.ByteArrayOutputStream; 35 import java.io.IOException; 36 import java.util.Arrays; 37 import java.util.Collection; 38 import java.util.HashSet; 39 import java.util.List; 40 import java.util.Set; 41 import org.junit.Rule; 42 import org.junit.Test; 43 import org.junit.rules.ExpectedException; 44 import org.junit.runner.RunWith; 45 import org.junit.runners.JUnit4; 46 47 /** 48 * Tests for serializing tags with {@link BinarySerializationUtils} and {@link 49 * TagContextBinarySerializerImpl}. 50 */ 51 @RunWith(JUnit4.class) 52 public class TagContextSerializationTest { 53 54 @Rule public final ExpectedException thrown = ExpectedException.none(); 55 56 private static final TagKey K1 = TagKey.create("k1"); 57 private static final TagKey K2 = TagKey.create("k2"); 58 private static final TagKey K3 = TagKey.create("k3"); 59 private static final TagKey K4 = TagKey.create("k4"); 60 61 private static final TagValue V1 = TagValue.create("v1"); 62 private static final TagValue V2 = TagValue.create("v2"); 63 private static final TagValue V3 = TagValue.create("v3"); 64 private static final TagValue V4 = TagValue.create("v4"); 65 66 private static final Tag T1 = Tag.create(K1, V1); 67 private static final Tag T2 = Tag.create(K2, V2); 68 private static final Tag T3 = Tag.create(K3, V3); 69 private static final Tag T4 = Tag.create(K4, V4); 70 71 private final TagsComponent tagsComponent = new TagsComponentImplBase(); 72 private final TagContextBinarySerializer serializer = 73 tagsComponent.getTagPropagationComponent().getBinarySerializer(); 74 private final Tagger tagger = tagsComponent.getTagger(); 75 76 @Test testSerializeDefault()77 public void testSerializeDefault() throws Exception { 78 testSerialize(); 79 } 80 81 @Test testSerializeWithOneTag()82 public void testSerializeWithOneTag() throws Exception { 83 testSerialize(T1); 84 } 85 86 @Test testSerializeWithMultipleTags()87 public void testSerializeWithMultipleTags() throws Exception { 88 testSerialize(T1, T2, T3, T4); 89 } 90 91 @Test testSerializeTooLargeTagContext()92 public void testSerializeTooLargeTagContext() throws TagContextSerializationException { 93 TagContextBuilder builder = tagger.emptyBuilder(); 94 for (int i = 0; i < BinarySerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8 - 1; i++) { 95 // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. 96 String str; 97 if (i < 10) { 98 str = "000" + i; 99 } else if (i < 100) { 100 str = "00" + i; 101 } else if (i < 1000) { 102 str = "0" + i; 103 } else { 104 str = String.valueOf(i); 105 } 106 builder.put(TagKey.create(str), TagValue.create(str)); 107 } 108 // The last tag will be of size 9, so the total size of the TagContext (8193) will be one byte 109 // more than limit. 110 builder.put(TagKey.create("last"), TagValue.create("last1")); 111 112 TagContext tagContext = builder.build(); 113 thrown.expect(TagContextSerializationException.class); 114 thrown.expectMessage("Size of TagContext exceeds the maximum serialized size "); 115 serializer.toByteArray(tagContext); 116 } 117 testSerialize(Tag... tags)118 private void testSerialize(Tag... tags) throws IOException, TagContextSerializationException { 119 TagContextBuilder builder = tagger.emptyBuilder(); 120 for (Tag tag : tags) { 121 builder.put(tag.getKey(), tag.getValue()); 122 } 123 124 byte[] actual = serializer.toByteArray(builder.build()); 125 126 Collection<List<Tag>> tagPermutation = Collections2.permutations(Arrays.asList(tags)); 127 Set<String> possibleOutputs = new HashSet<String>(); 128 for (List<Tag> list : tagPermutation) { 129 ByteArrayOutputStream expected = new ByteArrayOutputStream(); 130 expected.write(BinarySerializationUtils.VERSION_ID); 131 for (Tag tag : list) { 132 expected.write(BinarySerializationUtils.TAG_FIELD_ID); 133 encodeString(tag.getKey().getName(), expected); 134 encodeString(tag.getValue().asString(), expected); 135 } 136 possibleOutputs.add(new String(expected.toByteArray(), Charsets.UTF_8)); 137 } 138 139 assertThat(possibleOutputs).contains(new String(actual, Charsets.UTF_8)); 140 } 141 encodeString(String input, ByteArrayOutputStream byteArrayOutputStream)142 private static void encodeString(String input, ByteArrayOutputStream byteArrayOutputStream) 143 throws IOException { 144 VarInt.putVarInt(input.length(), byteArrayOutputStream); 145 byteArrayOutputStream.write(input.getBytes(Charsets.UTF_8)); 146 } 147 } 148