aboutsummaryrefslogtreecommitdiff
path: root/impl_core/src/test/java/io/opencensus/implcore/tags
diff options
context:
space:
mode:
Diffstat (limited to 'impl_core/src/test/java/io/opencensus/implcore/tags')
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java103
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java43
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java110
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java112
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java318
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java49
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java32
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java91
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java199
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java63
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java118
11 files changed, 1238 insertions, 0 deletions
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java
new file mode 100644
index 00000000..1a14ac6e
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList;
+
+import com.google.common.collect.ImmutableSet;
+import io.grpc.Context;
+import io.opencensus.common.Scope;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.unsafe.ContextUtils;
+import java.util.Iterator;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link CurrentTagContextUtils}. */
+@RunWith(JUnit4.class)
+public class CurrentTagContextUtilsTest {
+ private static final Tag TAG = Tag.create(TagKey.create("key"), TagValue.create("value"));
+
+ private final TagContext tagContext =
+ new TagContext() {
+
+ @Override
+ protected Iterator<Tag> getIterator() {
+ return ImmutableSet.<Tag>of(TAG).iterator();
+ }
+ };
+
+ @Test
+ public void testGetCurrentTagContext_DefaultContext() {
+ TagContext tags = CurrentTagContextUtils.getCurrentTagContext();
+ assertThat(tags).isNotNull();
+ assertThat(tagContextToList(tags)).isEmpty();
+ }
+
+ @Test
+ public void testGetCurrentTagContext_ContextSetToNull() {
+ Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, null).attach();
+ try {
+ TagContext tags = CurrentTagContextUtils.getCurrentTagContext();
+ assertThat(tags).isNotNull();
+ assertThat(tagContextToList(tags)).isEmpty();
+ } finally {
+ Context.current().detach(orig);
+ }
+ }
+
+ @Test
+ public void testWithTagContext() {
+ assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty();
+ Scope scopedTags = CurrentTagContextUtils.withTagContext(tagContext);
+ try {
+ assertThat(CurrentTagContextUtils.getCurrentTagContext()).isSameAs(tagContext);
+ } finally {
+ scopedTags.close();
+ }
+ assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty();
+ }
+
+ @Test
+ public void testWithTagContextUsingWrap() {
+ Runnable runnable;
+ Scope scopedTags = CurrentTagContextUtils.withTagContext(tagContext);
+ try {
+ assertThat(CurrentTagContextUtils.getCurrentTagContext()).isSameAs(tagContext);
+ runnable =
+ Context.current()
+ .wrap(
+ new Runnable() {
+ @Override
+ public void run() {
+ assertThat(CurrentTagContextUtils.getCurrentTagContext())
+ .isSameAs(tagContext);
+ }
+ });
+ } finally {
+ scopedTags.close();
+ }
+ assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty();
+ // When we run the runnable we will have the TagContext in the current Context.
+ runnable.run();
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java
new file mode 100644
index 00000000..244b6711
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.tags.TaggingState;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link CurrentTaggingState}. */
+@RunWith(JUnit4.class)
+public final class CurrentTaggingStateTest {
+
+ @Test
+ public void defaultState() {
+ assertThat(new CurrentTaggingState().get()).isEqualTo(TaggingState.ENABLED);
+ }
+
+ @Test
+ public void setState() {
+ CurrentTaggingState state = new CurrentTaggingState();
+ state.set(TaggingState.DISABLED);
+ assertThat(state.get()).isEqualTo(TaggingState.DISABLED);
+ state.set(TaggingState.ENABLED);
+ assertThat(state.get()).isEqualTo(TaggingState.ENABLED);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java
new file mode 100644
index 00000000..c24cccb9
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList;
+
+import io.opencensus.common.Scope;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.Tagger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for the methods in {@link TaggerImpl} and {@link TagContextBuilderImpl} that interact
+ * with the current {@link TagContext}.
+ */
+@RunWith(JUnit4.class)
+public class ScopedTagContextsTest {
+ private static final TagKey KEY_1 = TagKey.create("key 1");
+ private static final TagKey KEY_2 = TagKey.create("key 2");
+
+ private static final TagValue VALUE_1 = TagValue.create("value 1");
+ private static final TagValue VALUE_2 = TagValue.create("value 2");
+
+ private final Tagger tagger = new TaggerImpl(new CurrentTaggingState());
+
+ @Test
+ public void defaultTagContext() {
+ TagContext defaultTagContext = tagger.getCurrentTagContext();
+ assertThat(tagContextToList(defaultTagContext)).isEmpty();
+ assertThat(defaultTagContext).isInstanceOf(TagContextImpl.class);
+ }
+
+ @Test
+ public void withTagContext() {
+ assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty();
+ TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build();
+ Scope scope = tagger.withTagContext(scopedTags);
+ try {
+ assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags);
+ } finally {
+ scope.close();
+ }
+ assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty();
+ }
+
+ @Test
+ public void createBuilderFromCurrentTags() {
+ TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build();
+ Scope scope = tagger.withTagContext(scopedTags);
+ try {
+ TagContext newTags = tagger.currentBuilder().put(KEY_2, VALUE_2).build();
+ assertThat(tagContextToList(newTags))
+ .containsExactly(Tag.create(KEY_1, VALUE_1), Tag.create(KEY_2, VALUE_2));
+ assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags);
+ } finally {
+ scope.close();
+ }
+ }
+
+ @Test
+ public void setCurrentTagsWithBuilder() {
+ assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty();
+ Scope scope = tagger.emptyBuilder().put(KEY_1, VALUE_1).buildScoped();
+ try {
+ assertThat(tagContextToList(tagger.getCurrentTagContext()))
+ .containsExactly(Tag.create(KEY_1, VALUE_1));
+ } finally {
+ scope.close();
+ }
+ assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty();
+ }
+
+ @Test
+ public void addToCurrentTagsWithBuilder() {
+ TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build();
+ Scope scope1 = tagger.withTagContext(scopedTags);
+ try {
+ Scope scope2 = tagger.currentBuilder().put(KEY_2, VALUE_2).buildScoped();
+ try {
+ assertThat(tagContextToList(tagger.getCurrentTagContext()))
+ .containsExactly(Tag.create(KEY_1, VALUE_1), Tag.create(KEY_2, VALUE_2));
+ } finally {
+ scope2.close();
+ }
+ assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags);
+ } finally {
+ scope1.close();
+ }
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java
new file mode 100644
index 00000000..b70d8b4e
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Lists;
+import com.google.common.testing.EqualsTester;
+import io.opencensus.tags.InternalUtils;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.Tagger;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link TagContextImpl} and {@link TagContextBuilderImpl}. */
+// TODO(sebright): Add more tests once the API is finalized.
+@RunWith(JUnit4.class)
+public class TagContextImplTest {
+ private final Tagger tagger = new TaggerImpl(new CurrentTaggingState());
+
+ private static final TagKey KS1 = TagKey.create("k1");
+ private static final TagKey KS2 = TagKey.create("k2");
+
+ private static final TagValue V1 = TagValue.create("v1");
+ private static final TagValue V2 = TagValue.create("v2");
+
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testSet() {
+ TagContext tags = tagger.emptyBuilder().put(KS1, V1).build();
+ assertThat(tagContextToList(tagger.toBuilder(tags).put(KS1, V2).build()))
+ .containsExactly(Tag.create(KS1, V2));
+ assertThat(tagContextToList(tagger.toBuilder(tags).put(KS2, V2).build()))
+ .containsExactly(Tag.create(KS1, V1), Tag.create(KS2, V2));
+ }
+
+ @Test
+ public void testClear() {
+ TagContext tags = tagger.emptyBuilder().put(KS1, V1).build();
+ assertThat(tagContextToList(tagger.toBuilder(tags).remove(KS1).build())).isEmpty();
+ assertThat(tagContextToList(tagger.toBuilder(tags).remove(KS2).build()))
+ .containsExactly(Tag.create(KS1, V1));
+ }
+
+ @Test
+ public void testIterator() {
+ TagContext tags = tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build();
+ Iterator<Tag> i = InternalUtils.getTags(tags);
+ assertTrue(i.hasNext());
+ Tag tag1 = i.next();
+ assertTrue(i.hasNext());
+ Tag tag2 = i.next();
+ assertFalse(i.hasNext());
+ assertThat(Arrays.asList(tag1, tag2)).containsExactly(Tag.create(KS1, V1), Tag.create(KS2, V2));
+ thrown.expect(NoSuchElementException.class);
+ i.next();
+ }
+
+ @Test
+ public void disallowCallingRemoveOnIterator() {
+ TagContext tags = tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build();
+ Iterator<Tag> i = InternalUtils.getTags(tags);
+ i.next();
+ thrown.expect(UnsupportedOperationException.class);
+ i.remove();
+ }
+
+ @Test
+ public void testEquals() {
+ new EqualsTester()
+ .addEqualityGroup(
+ tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(),
+ tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(),
+ tagger.emptyBuilder().put(KS2, V2).put(KS1, V1).build(),
+ new TagContext() {
+ @Override
+ protected Iterator<Tag> getIterator() {
+ return Lists.<Tag>newArrayList(Tag.create(KS1, V1), Tag.create(KS2, V2)).iterator();
+ }
+ })
+ .addEqualityGroup(tagger.emptyBuilder().put(KS1, V1).put(KS2, V1).build())
+ .addEqualityGroup(tagger.emptyBuilder().put(KS1, V2).put(KS2, V1).build())
+ .testEquals();
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java
new file mode 100644
index 00000000..4ca2ae76
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList;
+
+import com.google.common.collect.Lists;
+import io.grpc.Context;
+import io.opencensus.common.Scope;
+import io.opencensus.implcore.internal.NoopScope;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagContextBuilder;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.Tagger;
+import io.opencensus.tags.TaggingState;
+import io.opencensus.tags.TagsComponent;
+import io.opencensus.tags.unsafe.ContextUtils;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link TaggerImpl}. */
+@RunWith(JUnit4.class)
+public class TaggerImplTest {
+ private final TagsComponent tagsComponent = new TagsComponentImplBase();
+ private final Tagger tagger = tagsComponent.getTagger();
+
+ private static final TagKey K1 = TagKey.create("k1");
+ private static final TagKey K2 = TagKey.create("k2");
+ private static final TagKey K3 = TagKey.create("k3");
+
+ private static final TagValue V1 = TagValue.create("v1");
+ private static final TagValue V2 = TagValue.create("v2");
+ private static final TagValue V3 = TagValue.create("v3");
+
+ private static final Tag TAG1 = Tag.create(K1, V1);
+ private static final Tag TAG2 = Tag.create(K2, V2);
+ private static final Tag TAG3 = Tag.create(K3, V3);
+
+ @Test
+ public void empty() {
+ assertThat(tagContextToList(tagger.empty())).isEmpty();
+ assertThat(tagger.empty()).isInstanceOf(TagContextImpl.class);
+ }
+
+ @Test
+ public void empty_TaggingDisabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagContextToList(tagger.empty())).isEmpty();
+ assertThat(tagger.empty()).isInstanceOf(TagContextImpl.class);
+ }
+
+ @Test
+ public void emptyBuilder() {
+ TagContextBuilder builder = tagger.emptyBuilder();
+ assertThat(builder).isInstanceOf(TagContextBuilderImpl.class);
+ assertThat(tagContextToList(builder.build())).isEmpty();
+ }
+
+ @Test
+ public void emptyBuilder_TaggingDisabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagger.emptyBuilder()).isSameAs(NoopTagContextBuilder.INSTANCE);
+ }
+
+ @Test
+ public void emptyBuilder_TaggingReenabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagger.emptyBuilder()).isSameAs(NoopTagContextBuilder.INSTANCE);
+ tagsComponent.setState(TaggingState.ENABLED);
+ TagContextBuilder builder = tagger.emptyBuilder();
+ assertThat(builder).isInstanceOf(TagContextBuilderImpl.class);
+ assertThat(tagContextToList(builder.put(K1, V1).build())).containsExactly(Tag.create(K1, V1));
+ }
+
+ @Test
+ public void currentBuilder() {
+ TagContext tags = new SimpleTagContext(TAG1, TAG2, TAG3);
+ TagContextBuilder result = getResultOfCurrentBuilder(tags);
+ assertThat(result).isInstanceOf(TagContextBuilderImpl.class);
+ assertThat(tagContextToList(result.build())).containsExactly(TAG1, TAG2, TAG3);
+ }
+
+ @Test
+ public void currentBuilder_DefaultIsEmpty() {
+ TagContextBuilder currentBuilder = tagger.currentBuilder();
+ assertThat(currentBuilder).isInstanceOf(TagContextBuilderImpl.class);
+ assertThat(tagContextToList(currentBuilder.build())).isEmpty();
+ }
+
+ @Test
+ public void currentBuilder_RemoveDuplicateTags() {
+ Tag tag1 = Tag.create(K1, V1);
+ Tag tag2 = Tag.create(K1, V2);
+ TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2);
+ TagContextBuilder result = getResultOfCurrentBuilder(tagContextWithDuplicateTags);
+ assertThat(tagContextToList(result.build())).containsExactly(tag2);
+ }
+
+ @Test
+ public void currentBuilder_SkipNullTag() {
+ TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2);
+ TagContextBuilder result = getResultOfCurrentBuilder(tagContextWithNullTag);
+ assertThat(tagContextToList(result.build())).containsExactly(TAG1, TAG2);
+ }
+
+ @Test
+ public void currentBuilder_TaggingDisabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(getResultOfCurrentBuilder(new SimpleTagContext(TAG1)))
+ .isSameAs(NoopTagContextBuilder.INSTANCE);
+ }
+
+ @Test
+ public void currentBuilder_TaggingReenabled() {
+ TagContext tags = new SimpleTagContext(TAG1);
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(getResultOfCurrentBuilder(tags)).isSameAs(NoopTagContextBuilder.INSTANCE);
+ tagsComponent.setState(TaggingState.ENABLED);
+ TagContextBuilder builder = getResultOfCurrentBuilder(tags);
+ assertThat(builder).isInstanceOf(TagContextBuilderImpl.class);
+ assertThat(tagContextToList(builder.build())).containsExactly(TAG1);
+ }
+
+ private TagContextBuilder getResultOfCurrentBuilder(TagContext tagsToSet) {
+ Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tagsToSet).attach();
+ try {
+ return tagger.currentBuilder();
+ } finally {
+ Context.current().detach(orig);
+ }
+ }
+
+ @Test
+ public void toBuilder_ConvertUnknownTagContextToTagContextImpl() {
+ TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3);
+ TagContext newTagContext = tagger.toBuilder(unknownTagContext).build();
+ assertThat(tagContextToList(newTagContext)).containsExactly(TAG1, TAG2, TAG3);
+ assertThat(newTagContext).isInstanceOf(TagContextImpl.class);
+ }
+
+ @Test
+ public void toBuilder_RemoveDuplicatesFromUnknownTagContext() {
+ Tag tag1 = Tag.create(K1, V1);
+ Tag tag2 = Tag.create(K1, V2);
+ TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2);
+ TagContext newTagContext = tagger.toBuilder(tagContextWithDuplicateTags).build();
+ assertThat(tagContextToList(newTagContext)).containsExactly(tag2);
+ }
+
+ @Test
+ public void toBuilder_SkipNullTag() {
+ TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2);
+ TagContext newTagContext = tagger.toBuilder(tagContextWithNullTag).build();
+ assertThat(tagContextToList(newTagContext)).containsExactly(TAG1, TAG2);
+ }
+
+ @Test
+ public void toBuilder_TaggingDisabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagger.toBuilder(new SimpleTagContext(TAG1)))
+ .isSameAs(NoopTagContextBuilder.INSTANCE);
+ }
+
+ @Test
+ public void toBuilder_TaggingReenabled() {
+ TagContext tags = new SimpleTagContext(TAG1);
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagger.toBuilder(tags)).isSameAs(NoopTagContextBuilder.INSTANCE);
+ tagsComponent.setState(TaggingState.ENABLED);
+ TagContextBuilder builder = tagger.toBuilder(tags);
+ assertThat(builder).isInstanceOf(TagContextBuilderImpl.class);
+ assertThat(tagContextToList(builder.build())).containsExactly(TAG1);
+ }
+
+ @Test
+ public void getCurrentTagContext_DefaultIsEmptyTagContextImpl() {
+ TagContext currentTagContext = tagger.getCurrentTagContext();
+ assertThat(tagContextToList(currentTagContext)).isEmpty();
+ assertThat(currentTagContext).isInstanceOf(TagContextImpl.class);
+ }
+
+ @Test
+ public void getCurrentTagContext_ConvertUnknownTagContextToTagContextImpl() {
+ TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3);
+ TagContext result = getResultOfGetCurrentTagContext(unknownTagContext);
+ assertThat(result).isInstanceOf(TagContextImpl.class);
+ assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2, TAG3);
+ }
+
+ @Test
+ public void getCurrentTagContext_RemoveDuplicatesFromUnknownTagContext() {
+ Tag tag1 = Tag.create(K1, V1);
+ Tag tag2 = Tag.create(K1, V2);
+ TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2);
+ TagContext result = getResultOfGetCurrentTagContext(tagContextWithDuplicateTags);
+ assertThat(tagContextToList(result)).containsExactly(tag2);
+ }
+
+ @Test
+ public void getCurrentTagContext_SkipNullTag() {
+ TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2);
+ TagContext result = getResultOfGetCurrentTagContext(tagContextWithNullTag);
+ assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2);
+ }
+
+ @Test
+ public void getCurrentTagContext_TaggingDisabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagContextToList(getResultOfGetCurrentTagContext(new SimpleTagContext(TAG1))))
+ .isEmpty();
+ }
+
+ @Test
+ public void getCurrentTagContext_TaggingReenabled() {
+ TagContext tags = new SimpleTagContext(TAG1);
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagContextToList(getResultOfGetCurrentTagContext(tags))).isEmpty();
+ tagsComponent.setState(TaggingState.ENABLED);
+ assertThat(tagContextToList(getResultOfGetCurrentTagContext(tags))).containsExactly(TAG1);
+ }
+
+ private TagContext getResultOfGetCurrentTagContext(TagContext tagsToSet) {
+ Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tagsToSet).attach();
+ try {
+ return tagger.getCurrentTagContext();
+ } finally {
+ Context.current().detach(orig);
+ }
+ }
+
+ @Test
+ public void withTagContext_ConvertUnknownTagContextToTagContextImpl() {
+ TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3);
+ TagContext result = getResultOfWithTagContext(unknownTagContext);
+ assertThat(result).isInstanceOf(TagContextImpl.class);
+ assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2, TAG3);
+ }
+
+ @Test
+ public void withTagContext_RemoveDuplicatesFromUnknownTagContext() {
+ Tag tag1 = Tag.create(K1, V1);
+ Tag tag2 = Tag.create(K1, V2);
+ TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2);
+ TagContext result = getResultOfWithTagContext(tagContextWithDuplicateTags);
+ assertThat(tagContextToList(result)).containsExactly(tag2);
+ }
+
+ @Test
+ public void withTagContext_SkipNullTag() {
+ TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2);
+ TagContext result = getResultOfWithTagContext(tagContextWithNullTag);
+ assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2);
+ }
+
+ @Test
+ public void withTagContext_ReturnsNoopScopeWhenTaggingIsDisabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagger.withTagContext(new SimpleTagContext(TAG1))).isSameAs(NoopScope.getInstance());
+ }
+
+ @Test
+ public void withTagContext_TaggingDisabled() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagContextToList(getResultOfWithTagContext(new SimpleTagContext(TAG1)))).isEmpty();
+ }
+
+ @Test
+ public void withTagContext_TaggingReenabled() {
+ TagContext tags = new SimpleTagContext(TAG1);
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagContextToList(getResultOfWithTagContext(tags))).isEmpty();
+ tagsComponent.setState(TaggingState.ENABLED);
+ assertThat(tagContextToList(getResultOfWithTagContext(tags))).containsExactly(TAG1);
+ }
+
+ private TagContext getResultOfWithTagContext(TagContext tagsToSet) {
+ Scope scope = tagger.withTagContext(tagsToSet);
+ try {
+ return ContextUtils.TAG_CONTEXT_KEY.get();
+ } finally {
+ scope.close();
+ }
+ }
+
+ private static final class SimpleTagContext extends TagContext {
+ private final List<Tag> tags;
+
+ SimpleTagContext(Tag... tags) {
+ this.tags = Collections.unmodifiableList(Lists.newArrayList(tags));
+ }
+
+ @Override
+ protected Iterator<Tag> getIterator() {
+ return tags.iterator();
+ }
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java
new file mode 100644
index 00000000..e75a86d0
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.tags.TaggingState;
+import io.opencensus.tags.TagsComponent;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link TagsComponentImplBase}. */
+@RunWith(JUnit4.class)
+public class TagsComponentImplBaseTest {
+ private final TagsComponent tagsComponent = new TagsComponentImplBase();
+
+ @Test
+ public void defaultState() {
+ assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED);
+ }
+
+ @Test
+ public void setState() {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(tagsComponent.getState()).isEqualTo(TaggingState.DISABLED);
+ tagsComponent.setState(TaggingState.ENABLED);
+ assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void setState_DisallowsNull() {
+ tagsComponent.setState(null);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java
new file mode 100644
index 00000000..c64eced1
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags;
+
+import com.google.common.collect.Lists;
+import io.opencensus.tags.InternalUtils;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import java.util.Collection;
+
+/** Test utilities for tagging. */
+public class TagsTestUtil {
+
+ /** Returns a collection of all tags in a {@link TagContext}. */
+ public static Collection<Tag> tagContextToList(TagContext tags) {
+ return Lists.newArrayList(InternalUtils.getTags(tags));
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java
new file mode 100644
index 00000000..7e9bead1
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags.propagation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableSet;
+import io.opencensus.implcore.tags.TagsComponentImplBase;
+import io.opencensus.implcore.tags.TagsTestUtil;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.TaggingState;
+import io.opencensus.tags.TagsComponent;
+import io.opencensus.tags.propagation.TagContextBinarySerializer;
+import io.opencensus.tags.propagation.TagContextDeserializationException;
+import io.opencensus.tags.propagation.TagContextSerializationException;
+import java.util.Iterator;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link TagContextBinarySerializerImpl}.
+ *
+ * <p>Thorough serialization/deserialization tests are in {@link TagContextSerializationTest},
+ * {@link TagContextDeserializationTest}, and {@link TagContextRoundtripTest}.
+ */
+@RunWith(JUnit4.class)
+public final class TagContextBinarySerializerImplTest {
+ private final TagsComponent tagsComponent = new TagsComponentImplBase();
+ private final TagContextBinarySerializer serializer =
+ tagsComponent.getTagPropagationComponent().getBinarySerializer();
+
+ private final TagContext tagContext =
+ new TagContext() {
+ @Override
+ public Iterator<Tag> getIterator() {
+ return ImmutableSet.<Tag>of(Tag.create(TagKey.create("key"), TagValue.create("value")))
+ .iterator();
+ }
+ };
+
+ @Test
+ public void toByteArray_TaggingDisabled() throws TagContextSerializationException {
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(serializer.toByteArray(tagContext)).isEmpty();
+ }
+
+ @Test
+ public void toByteArray_TaggingReenabled() throws TagContextSerializationException {
+ final byte[] serialized = serializer.toByteArray(tagContext);
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(serializer.toByteArray(tagContext)).isEmpty();
+ tagsComponent.setState(TaggingState.ENABLED);
+ assertThat(serializer.toByteArray(tagContext)).isEqualTo(serialized);
+ }
+
+ @Test
+ public void fromByteArray_TaggingDisabled()
+ throws TagContextDeserializationException, TagContextSerializationException {
+ byte[] serialized = serializer.toByteArray(tagContext);
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(TagsTestUtil.tagContextToList(serializer.fromByteArray(serialized))).isEmpty();
+ }
+
+ @Test
+ public void fromByteArray_TaggingReenabled()
+ throws TagContextDeserializationException, TagContextSerializationException {
+ byte[] serialized = serializer.toByteArray(tagContext);
+ tagsComponent.setState(TaggingState.DISABLED);
+ assertThat(TagsTestUtil.tagContextToList(serializer.fromByteArray(serialized))).isEmpty();
+ tagsComponent.setState(TaggingState.ENABLED);
+ assertThat(serializer.fromByteArray(serialized)).isEqualTo(tagContext);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java
new file mode 100644
index 00000000..14118be0
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2016-17, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags.propagation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.ByteArrayDataOutput;
+import com.google.common.io.ByteStreams;
+import io.opencensus.implcore.internal.VarInt;
+import io.opencensus.implcore.tags.TagsComponentImplBase;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.Tagger;
+import io.opencensus.tags.TagsComponent;
+import io.opencensus.tags.propagation.TagContextBinarySerializer;
+import io.opencensus.tags.propagation.TagContextDeserializationException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for deserializing tags with {@link SerializationUtils} and {@link
+ * TagContextBinarySerializerImpl}.
+ */
+@RunWith(JUnit4.class)
+public class TagContextDeserializationTest {
+
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ private final TagsComponent tagsComponent = new TagsComponentImplBase();
+ private final TagContextBinarySerializer serializer =
+ tagsComponent.getTagPropagationComponent().getBinarySerializer();
+ private final Tagger tagger = tagsComponent.getTagger();
+
+ @Test
+ public void testVersionAndValueTypeConstants() {
+ // Refer to the JavaDoc on SerializationUtils for the definitions on these constants.
+ assertThat(SerializationUtils.VERSION_ID).isEqualTo(0);
+ assertThat(SerializationUtils.TAG_FIELD_ID).isEqualTo(0);
+ }
+
+ @Test
+ public void testDeserializeNoTags() throws TagContextDeserializationException {
+ TagContext expected = tagger.empty();
+ TagContext actual =
+ serializer.fromByteArray(
+ new byte[] {SerializationUtils.VERSION_ID}); // One byte that represents Version ID.
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testDeserializeEmptyByteArrayThrowException()
+ throws TagContextDeserializationException {
+ thrown.expect(TagContextDeserializationException.class);
+ thrown.expectMessage("Input byte[] can not be empty.");
+ serializer.fromByteArray(new byte[0]);
+ }
+
+ @Test
+ public void testDeserializeInvalidTagKey() throws TagContextDeserializationException {
+ ByteArrayDataOutput output = ByteStreams.newDataOutput();
+ output.write(SerializationUtils.VERSION_ID);
+
+ // Encode an invalid tag key and a valid tag value:
+ encodeTagToOutput("\2key", "value", output);
+ final byte[] bytes = output.toByteArray();
+
+ thrown.expect(TagContextDeserializationException.class);
+ thrown.expectMessage("Invalid tag key: \2key");
+ serializer.fromByteArray(bytes);
+ }
+
+ @Test
+ public void testDeserializeInvalidTagValue() throws TagContextDeserializationException {
+ ByteArrayDataOutput output = ByteStreams.newDataOutput();
+ output.write(SerializationUtils.VERSION_ID);
+
+ // Encode a valid tag key and an invalid tag value:
+ encodeTagToOutput("my key", "val\3", output);
+ final byte[] bytes = output.toByteArray();
+
+ thrown.expect(TagContextDeserializationException.class);
+ thrown.expectMessage("Invalid tag value for key TagKey{name=my key}: val\3");
+ serializer.fromByteArray(bytes);
+ }
+
+ @Test
+ public void testDeserializeOneTag() throws TagContextDeserializationException {
+ ByteArrayDataOutput output = ByteStreams.newDataOutput();
+ output.write(SerializationUtils.VERSION_ID);
+ encodeTagToOutput("Key", "Value", output);
+ TagContext expected =
+ tagger.emptyBuilder().put(TagKey.create("Key"), TagValue.create("Value")).build();
+ assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected);
+ }
+
+ @Test
+ public void testDeserializeMultipleTags() throws TagContextDeserializationException {
+ ByteArrayDataOutput output = ByteStreams.newDataOutput();
+ output.write(SerializationUtils.VERSION_ID);
+ encodeTagToOutput("Key1", "Value1", output);
+ encodeTagToOutput("Key2", "Value2", output);
+ TagContext expected =
+ tagger
+ .emptyBuilder()
+ .put(TagKey.create("Key1"), TagValue.create("Value1"))
+ .put(TagKey.create("Key2"), TagValue.create("Value2"))
+ .build();
+ assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected);
+ }
+
+ @Test
+ public void stopParsingAtUnknownField() throws TagContextDeserializationException {
+ ByteArrayDataOutput output = ByteStreams.newDataOutput();
+ output.write(SerializationUtils.VERSION_ID);
+ encodeTagToOutput("Key1", "Value1", output);
+ encodeTagToOutput("Key2", "Value2", output);
+
+ // Write unknown field ID 1.
+ output.write(1);
+ output.write(new byte[] {1, 2, 3, 4});
+
+ encodeTagToOutput("Key3", "Value3", output);
+
+ // key 3 should not be included
+ TagContext expected =
+ tagger
+ .emptyBuilder()
+ .put(TagKey.create("Key1"), TagValue.create("Value1"))
+ .put(TagKey.create("Key2"), TagValue.create("Value2"))
+ .build();
+ assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected);
+ }
+
+ @Test
+ public void stopParsingAtUnknownTagAtStart() throws TagContextDeserializationException {
+ ByteArrayDataOutput output = ByteStreams.newDataOutput();
+ output.write(SerializationUtils.VERSION_ID);
+
+ // Write unknown field ID 1.
+ output.write(1);
+ output.write(new byte[] {1, 2, 3, 4});
+
+ encodeTagToOutput("Key", "Value", output);
+ assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(tagger.empty());
+ }
+
+ @Test
+ public void testDeserializeWrongFormat() throws TagContextDeserializationException {
+ // encoded tags should follow the format <version_id>(<tag_field_id><tag_encoding>)*
+ thrown.expect(TagContextDeserializationException.class);
+ serializer.fromByteArray(new byte[3]);
+ }
+
+ @Test
+ public void testDeserializeWrongVersionId() throws TagContextDeserializationException {
+ thrown.expect(TagContextDeserializationException.class);
+ thrown.expectMessage("Wrong Version ID: 1. Currently supported version is: 0");
+ serializer.fromByteArray(new byte[] {(byte) (SerializationUtils.VERSION_ID + 1)});
+ }
+
+ // <tag_encoding> ==
+ // <tag_key_len><tag_key><tag_val_len><tag_val>
+ // <tag_key_len> == varint encoded integer
+ // <tag_key> == tag_key_len bytes comprising tag key name
+ // <tag_val_len> == varint encoded integer
+ // <tag_val> == tag_val_len bytes comprising UTF-8 string
+ private static void encodeTagToOutput(String key, String value, ByteArrayDataOutput output) {
+ output.write(SerializationUtils.TAG_FIELD_ID);
+ encodeString(key, output);
+ encodeString(value, output);
+ }
+
+ private static void encodeString(String input, ByteArrayDataOutput output) {
+ int length = input.length();
+ byte[] bytes = new byte[VarInt.varIntSize(length)];
+ VarInt.putVarInt(length, bytes, 0);
+ output.write(bytes);
+ output.write(input.getBytes(Charsets.UTF_8));
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java
new file mode 100644
index 00000000..88abcc1d
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags.propagation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.implcore.tags.TagsComponentImplBase;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.Tagger;
+import io.opencensus.tags.TagsComponent;
+import io.opencensus.tags.propagation.TagContextBinarySerializer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for roundtrip serialization with {@link TagContextBinarySerializerImpl}. */
+@RunWith(JUnit4.class)
+public class TagContextRoundtripTest {
+
+ private static final TagKey K1 = TagKey.create("k1");
+ private static final TagKey K2 = TagKey.create("k2");
+ private static final TagKey K3 = TagKey.create("k3");
+
+ private static final TagValue V_EMPTY = TagValue.create("");
+ private static final TagValue V1 = TagValue.create("v1");
+ private static final TagValue V2 = TagValue.create("v2");
+ private static final TagValue V3 = TagValue.create("v3");
+
+ private final TagsComponent tagsComponent = new TagsComponentImplBase();
+ private final TagContextBinarySerializer serializer =
+ tagsComponent.getTagPropagationComponent().getBinarySerializer();
+ private final Tagger tagger = tagsComponent.getTagger();
+
+ @Test
+ public void testRoundtripSerialization() throws Exception {
+ testRoundtripSerialization(tagger.empty());
+ testRoundtripSerialization(tagger.emptyBuilder().put(K1, V1).build());
+ testRoundtripSerialization(tagger.emptyBuilder().put(K1, V1).put(K2, V2).put(K3, V3).build());
+ testRoundtripSerialization(tagger.emptyBuilder().put(K1, V_EMPTY).build());
+ }
+
+ private void testRoundtripSerialization(TagContext expected) throws Exception {
+ byte[] bytes = serializer.toByteArray(expected);
+ TagContext actual = serializer.fromByteArray(bytes);
+ assertThat(actual).isEqualTo(expected);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java
new file mode 100644
index 00000000..6227fe54
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2016-17, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.tags.propagation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Collections2;
+import io.opencensus.implcore.internal.VarInt;
+import io.opencensus.implcore.tags.TagsComponentImplBase;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContextBuilder;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.Tagger;
+import io.opencensus.tags.TagsComponent;
+import io.opencensus.tags.propagation.TagContextBinarySerializer;
+import io.opencensus.tags.propagation.TagContextSerializationException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for serializing tags with {@link SerializationUtils} and {@link
+ * TagContextBinarySerializerImpl}.
+ */
+@RunWith(JUnit4.class)
+public class TagContextSerializationTest {
+
+ private static final int VERSION_ID = 0;
+ private static final int TAG_FIELD_ID = 0;
+
+ private static final TagKey K1 = TagKey.create("k1");
+ private static final TagKey K2 = TagKey.create("k2");
+ private static final TagKey K3 = TagKey.create("k3");
+ private static final TagKey K4 = TagKey.create("k4");
+
+ private static final TagValue V1 = TagValue.create("v1");
+ private static final TagValue V2 = TagValue.create("v2");
+ private static final TagValue V3 = TagValue.create("v3");
+ private static final TagValue V4 = TagValue.create("v4");
+
+ private static final Tag T1 = Tag.create(K1, V1);
+ private static final Tag T2 = Tag.create(K2, V2);
+ private static final Tag T3 = Tag.create(K3, V3);
+ private static final Tag T4 = Tag.create(K4, V4);
+
+ private final TagsComponent tagsComponent = new TagsComponentImplBase();
+ private final TagContextBinarySerializer serializer =
+ tagsComponent.getTagPropagationComponent().getBinarySerializer();
+ private final Tagger tagger = tagsComponent.getTagger();
+
+ @Test
+ public void testSerializeDefault() throws Exception {
+ testSerialize();
+ }
+
+ @Test
+ public void testSerializeWithOneTag() throws Exception {
+ testSerialize(T1);
+ }
+
+ @Test
+ public void testSerializeWithMultipleTags() throws Exception {
+ testSerialize(T1, T2, T3, T4);
+ }
+
+ private void testSerialize(Tag... tags) throws IOException, TagContextSerializationException {
+ TagContextBuilder builder = tagger.emptyBuilder();
+ for (Tag tag : tags) {
+ builder.put(tag.getKey(), tag.getValue());
+ }
+
+ byte[] actual = serializer.toByteArray(builder.build());
+
+ Collection<List<Tag>> tagPermutation = Collections2.permutations(Arrays.asList(tags));
+ Set<String> possibleOutputs = new HashSet<String>();
+ for (List<Tag> list : tagPermutation) {
+ ByteArrayOutputStream expected = new ByteArrayOutputStream();
+ expected.write(VERSION_ID);
+ for (Tag tag : list) {
+ expected.write(TAG_FIELD_ID);
+ encodeString(tag.getKey().getName(), expected);
+ encodeString(tag.getValue().asString(), expected);
+ }
+ possibleOutputs.add(expected.toString());
+ }
+
+ assertThat(possibleOutputs).contains(new String(actual, Charsets.UTF_8));
+ }
+
+ private static void encodeString(String input, ByteArrayOutputStream byteArrayOutputStream)
+ throws IOException {
+ VarInt.putVarInt(input.length(), byteArrayOutputStream);
+ byteArrayOutputStream.write(input.getBytes(Charsets.UTF_8));
+ }
+}