diff options
Diffstat (limited to 'impl_core/src/test/java/io/opencensus/implcore/tags')
10 files changed, 1472 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/ScopedTagContextsTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java new file mode 100644 index 00000000..6a8fe4c7 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.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 io.opencensus.common.Scope; +import io.opencensus.implcore.internal.CurrentState; +import io.opencensus.implcore.internal.CurrentState.State; +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 CurrentState(State.ENABLED)); + + @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..1859e081 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java @@ -0,0 +1,167 @@ +/* + * 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 org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.testing.EqualsTester; +import io.opencensus.implcore.internal.CurrentState; +import io.opencensus.implcore.internal.CurrentState.State; +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 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}. + * + * <p>Tests for {@link TagContextBuilderImpl#buildScoped()} are in {@link ScopedTagContextsTest}. + */ +@RunWith(JUnit4.class) +public class TagContextImplTest { + private final Tagger tagger = new TaggerImpl(new CurrentState(State.ENABLED)); + + private static final TagKey K1 = TagKey.create("k1"); + private static final TagKey K2 = 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 getTags_empty() { + TagContextImpl tags = new TagContextImpl(ImmutableMap.<TagKey, TagValue>of()); + assertThat(tags.getTags()).isEmpty(); + } + + @Test + public void getTags_nonEmpty() { + TagContextImpl tags = new TagContextImpl(ImmutableMap.of(K1, V1, K2, V2)); + assertThat(tags.getTags()).containsExactly(K1, V1, K2, V2); + } + + @Test + public void put_newKey() { + TagContext tags = new TagContextImpl(ImmutableMap.of(K1, V1)); + assertThat(((TagContextImpl) tagger.toBuilder(tags).put(K2, V2).build()).getTags()) + .containsExactly(K1, V1, K2, V2); + } + + @Test + public void put_existingKey() { + TagContext tags = new TagContextImpl(ImmutableMap.of(K1, V1)); + assertThat(((TagContextImpl) tagger.toBuilder(tags).put(K1, V2).build()).getTags()) + .containsExactly(K1, V2); + } + + @Test + public void put_nullKey() { + TagContext tags = new TagContextImpl(ImmutableMap.of(K1, V1)); + TagContextBuilder builder = tagger.toBuilder(tags); + thrown.expect(NullPointerException.class); + thrown.expectMessage("key"); + builder.put(null, V2); + } + + @Test + public void put_nullValue() { + TagContext tags = new TagContextImpl(ImmutableMap.of(K1, V1)); + TagContextBuilder builder = tagger.toBuilder(tags); + thrown.expect(NullPointerException.class); + thrown.expectMessage("value"); + builder.put(K2, null); + } + + @Test + public void remove_existingKey() { + TagContext tags = new TagContextImpl(ImmutableMap.of(K1, V1, K2, V2)); + assertThat(((TagContextImpl) tagger.toBuilder(tags).remove(K1).build()).getTags()) + .containsExactly(K2, V2); + } + + @Test + public void remove_differentKey() { + TagContext tags = new TagContextImpl(ImmutableMap.of(K1, V1)); + assertThat(((TagContextImpl) tagger.toBuilder(tags).remove(K2).build()).getTags()) + .containsExactly(K1, V1); + } + + @Test + public void remove_nullKey() { + TagContext tags = new TagContextImpl(ImmutableMap.of(K1, V1)); + TagContextBuilder builder = tagger.toBuilder(tags); + thrown.expect(NullPointerException.class); + thrown.expectMessage("key"); + builder.remove(null); + } + + @Test + public void testIterator() { + TagContextImpl tags = new TagContextImpl(ImmutableMap.of(K1, V1, K2, V2)); + Iterator<Tag> i = tags.getIterator(); + 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(K1, V1), Tag.create(K2, V2)); + thrown.expect(NoSuchElementException.class); + i.next(); + } + + @Test + public void disallowCallingRemoveOnIterator() { + TagContextImpl tags = new TagContextImpl(ImmutableMap.of(K1, V1, K2, V2)); + Iterator<Tag> i = tags.getIterator(); + i.next(); + thrown.expect(UnsupportedOperationException.class); + i.remove(); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + tagger.emptyBuilder().put(K1, V1).put(K2, V2).build(), + tagger.emptyBuilder().put(K1, V1).put(K2, V2).build(), + tagger.emptyBuilder().put(K2, V2).put(K1, V1).build(), + new TagContext() { + @Override + protected Iterator<Tag> getIterator() { + return Lists.<Tag>newArrayList(Tag.create(K1, V1), Tag.create(K2, V2)).iterator(); + } + }) + .addEqualityGroup(tagger.emptyBuilder().put(K1, V1).put(K2, V1).build()) + .addEqualityGroup(tagger.emptyBuilder().put(K1, V2).put(K2, 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..1bc13c59 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java @@ -0,0 +1,84 @@ +/* + * 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.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link TagsComponentImplBase}. */ +@RunWith(JUnit4.class) +public class TagsComponentImplBaseTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + + @Test + public void defaultState() { + assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED); + } + + @Test + @SuppressWarnings("deprecation") + public void setState_Disabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagsComponent.getState()).isEqualTo(TaggingState.DISABLED); + } + + @Test + @SuppressWarnings("deprecation") + public void setState_Enabled() { + tagsComponent.setState(TaggingState.DISABLED); + tagsComponent.setState(TaggingState.ENABLED); + assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED); + } + + @Test + @SuppressWarnings("deprecation") + public void setState_DisallowsNull() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("newState"); + tagsComponent.setState(null); + } + + @Test + @SuppressWarnings("deprecation") + public void preventSettingStateAfterGettingState_DifferentState() { + tagsComponent.setState(TaggingState.DISABLED); + tagsComponent.getState(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("State was already read, cannot set state."); + tagsComponent.setState(TaggingState.ENABLED); + } + + @Test + @SuppressWarnings("deprecation") + public void preventSettingStateAfterGettingState_SameState() { + tagsComponent.setState(TaggingState.DISABLED); + tagsComponent.getState(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("State was already read, cannot set state."); + tagsComponent.setState(TaggingState.DISABLED); + } +} 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..dcfba508 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java @@ -0,0 +1,33 @@ +/* + * 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 { + private 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..26a072f6 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java @@ -0,0 +1,94 @@ +/* + * 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 + @SuppressWarnings("deprecation") + public void toByteArray_TaggingDisabled() throws TagContextSerializationException { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(serializer.toByteArray(tagContext)).isEmpty(); + } + + @Test + @SuppressWarnings("deprecation") + 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 + @SuppressWarnings("deprecation") + 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..8db0e389 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java @@ -0,0 +1,329 @@ +/* + * 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 testConstants() { + // 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); + assertThat(SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT).isEqualTo(8192); + } + + @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 testDeserializeTooLargeByteArrayThrowException() + throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + for (int i = 0; i < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8 - 1; i++) { + // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. + String str; + if (i < 10) { + str = "000" + i; + } else if (i < 100) { + str = "00" + i; + } else if (i < 1000) { + str = "0" + i; + } else { + str = String.valueOf(i); + } + encodeTagToOutput(str, str, output); + } + // The last tag will be of size 9, so the total size of the TagContext (8193) will be one byte + // more than limit. + encodeTagToOutput("last", "last1", output); + + byte[] bytes = output.toByteArray(); + thrown.expect(TagContextDeserializationException.class); + thrown.expectMessage("Size of TagContext exceeds the maximum serialized size "); + serializer.fromByteArray(bytes); + } + + // Deserializing this input should cause an error, even though it represents a relatively small + // TagContext. + @Test + public void testDeserializeTooLargeByteArrayThrowException_WithDuplicateTagKeys() + throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + for (int i = 0; i < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8 - 1; i++) { + // Each tag will be with format {key : "key_", value : "0123"}, so the length of it is 8. + String str; + if (i < 10) { + str = "000" + i; + } else if (i < 100) { + str = "00" + i; + } else if (i < 1000) { + str = "0" + i; + } else { + str = String.valueOf(i); + } + encodeTagToOutput("key_", str, output); + } + // The last tag will be of size 9, so the total size of the TagContext (8193) will be one byte + // more than limit. + encodeTagToOutput("key_", "last1", output); + + byte[] bytes = output.toByteArray(); + thrown.expect(TagContextDeserializationException.class); + thrown.expectMessage("Size of TagContext exceeds the maximum serialized size "); + serializer.fromByteArray(bytes); + } + + @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 testDeserializeDuplicateKeys() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + encodeTagToOutput("Key1", "Value1", output); + encodeTagToOutput("Key1", "Value2", output); + TagContext expected = + tagger.emptyBuilder().put(TagKey.create("Key1"), TagValue.create("Value2")).build(); + assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); + } + + @Test + public void testDeserializeNonConsecutiveDuplicateKeys() + throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + encodeTagToOutput("Key1", "Value1", output); + encodeTagToOutput("Key2", "Value2", output); + encodeTagToOutput("Key3", "Value3", output); + encodeTagToOutput("Key1", "Value4", output); + encodeTagToOutput("Key2", "Value5", output); + TagContext expected = + tagger + .emptyBuilder() + .put(TagKey.create("Key1"), TagValue.create("Value4")) + .put(TagKey.create("Key2"), TagValue.create("Value5")) + .put(TagKey.create("Key3"), TagValue.create("Value3")) + .build(); + assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); + } + + @Test + public void testDeserializeDuplicateTags() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + encodeTagToOutput("Key1", "Value1", output); + encodeTagToOutput("Key1", "Value1", output); + TagContext expected = + tagger.emptyBuilder().put(TagKey.create("Key1"), TagValue.create("Value1")).build(); + assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); + } + + @Test + public void testDeserializeNonConsecutiveDuplicateTags() + throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + encodeTagToOutput("Key1", "Value1", output); + encodeTagToOutput("Key2", "Value2", output); + encodeTagToOutput("Key3", "Value3", output); + 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")) + .put(TagKey.create("Key3"), TagValue.create("Value3")) + .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 supports version up to: 0"); + serializer.fromByteArray(new byte[] {(byte) (SerializationUtils.VERSION_ID + 1)}); + } + + @Test + public void testDeserializeNegativeVersionId() throws TagContextDeserializationException { + thrown.expect(TagContextDeserializationException.class); + thrown.expectMessage("Wrong Version ID: -1. Currently supports version up to: 0"); + serializer.fromByteArray(new byte[] {(byte) -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..1b1aa042 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java @@ -0,0 +1,85 @@ +/* + * 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.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 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_NormalTagContext() 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()); + } + + @Test + public void testRoundtrip_TagContextWithMaximumSize() throws Exception { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8; i++) { + // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. + // Add 1024 tags, the total size should just be 8192. + String str; + if (i < 10) { + str = "000" + i; + } else if (i < 100) { + str = "00" + i; + } else if (i < 1000) { + str = "0" + i; + } else { + str = "" + i; + } + builder.put(TagKey.create(str), TagValue.create(str)); + } + testRoundtripSerialization(builder.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..ed68fe3d --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java @@ -0,0 +1,147 @@ +/* + * 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.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.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.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +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 { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + 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); + } + + @Test + public void testSerializeTooLargeTagContext() throws TagContextSerializationException { + TagContextBuilder builder = tagger.emptyBuilder(); + for (int i = 0; i < SerializationUtils.TAGCONTEXT_SERIALIZED_SIZE_LIMIT / 8 - 1; i++) { + // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. + String str; + if (i < 10) { + str = "000" + i; + } else if (i < 100) { + str = "00" + i; + } else if (i < 1000) { + str = "0" + i; + } else { + str = String.valueOf(i); + } + builder.put(TagKey.create(str), TagValue.create(str)); + } + // The last tag will be of size 9, so the total size of the TagContext (8193) will be one byte + // more than limit. + builder.put(TagKey.create("last"), TagValue.create("last1")); + + TagContext tagContext = builder.build(); + thrown.expect(TagContextSerializationException.class); + thrown.expectMessage("Size of TagContext exceeds the maximum serialized size "); + serializer.toByteArray(tagContext); + } + + 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(SerializationUtils.VERSION_ID); + for (Tag tag : list) { + expected.write(SerializationUtils.TAG_FIELD_ID); + encodeString(tag.getKey().getName(), expected); + encodeString(tag.getValue().asString(), expected); + } + possibleOutputs.add(new String(expected.toByteArray(), Charsets.UTF_8)); + } + + 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)); + } +} |