1 /* 2 * Copyright 2018, OpenCensus Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.opencensus.trace; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import com.google.common.testing.EqualsTester; 22 import io.opencensus.trace.Tracestate.Entry; 23 import java.util.Arrays; 24 import org.junit.Rule; 25 import org.junit.Test; 26 import org.junit.rules.ExpectedException; 27 import org.junit.runner.RunWith; 28 import org.junit.runners.JUnit4; 29 30 /** Unit tests for {@link Tracestate}. */ 31 @RunWith(JUnit4.class) 32 public class TracestateTest { 33 private static final String FIRST_KEY = "key_1"; 34 private static final String SECOND_KEY = "key_2"; 35 private static final String FIRST_VALUE = "value.1"; 36 private static final String SECOND_VALUE = "value.2"; 37 38 @Rule public final ExpectedException thrown = ExpectedException.none(); 39 40 private static final Tracestate EMPTY = Tracestate.builder().build(); 41 private final Tracestate firstTracestate = EMPTY.toBuilder().set(FIRST_KEY, FIRST_VALUE).build(); 42 private final Tracestate secondTracestate = 43 EMPTY.toBuilder().set(SECOND_KEY, SECOND_VALUE).build(); 44 private final Tracestate multiValueTracestate = 45 EMPTY.toBuilder().set(FIRST_KEY, FIRST_VALUE).set(SECOND_KEY, SECOND_VALUE).build(); 46 47 @Test get()48 public void get() { 49 assertThat(firstTracestate.get(FIRST_KEY)).isEqualTo(FIRST_VALUE); 50 assertThat(secondTracestate.get(SECOND_KEY)).isEqualTo(SECOND_VALUE); 51 assertThat(multiValueTracestate.get(FIRST_KEY)).isEqualTo(FIRST_VALUE); 52 assertThat(multiValueTracestate.get(SECOND_KEY)).isEqualTo(SECOND_VALUE); 53 } 54 55 @Test getEntries()56 public void getEntries() { 57 assertThat(firstTracestate.getEntries()).containsExactly(Entry.create(FIRST_KEY, FIRST_VALUE)); 58 assertThat(secondTracestate.getEntries()) 59 .containsExactly(Entry.create(SECOND_KEY, SECOND_VALUE)); 60 assertThat(multiValueTracestate.getEntries()) 61 .containsExactly( 62 Entry.create(FIRST_KEY, FIRST_VALUE), Entry.create(SECOND_KEY, SECOND_VALUE)); 63 } 64 65 @Test disallowsNullKey()66 public void disallowsNullKey() { 67 thrown.expect(NullPointerException.class); 68 EMPTY.toBuilder().set(null, FIRST_VALUE).build(); 69 } 70 71 @Test invalidFirstKeyCharacter()72 public void invalidFirstKeyCharacter() { 73 thrown.expect(IllegalArgumentException.class); 74 EMPTY.toBuilder().set("1_key", FIRST_VALUE).build(); 75 } 76 77 @Test invalidKeyCharacters()78 public void invalidKeyCharacters() { 79 thrown.expect(IllegalArgumentException.class); 80 EMPTY.toBuilder().set("kEy_1", FIRST_VALUE).build(); 81 } 82 83 @Test invalidKeySize()84 public void invalidKeySize() { 85 char[] chars = new char[257]; 86 Arrays.fill(chars, 'a'); 87 String longKey = new String(chars); 88 thrown.expect(IllegalArgumentException.class); 89 EMPTY.toBuilder().set(longKey, FIRST_VALUE).build(); 90 } 91 92 @Test allAllowedKeyCharacters()93 public void allAllowedKeyCharacters() { 94 StringBuilder stringBuilder = new StringBuilder(); 95 for (char c = 'a'; c <= 'z'; c++) { 96 stringBuilder.append(c); 97 } 98 for (char c = '0'; c <= '9'; c++) { 99 stringBuilder.append(c); 100 } 101 stringBuilder.append('_'); 102 stringBuilder.append('-'); 103 stringBuilder.append('*'); 104 stringBuilder.append('/'); 105 String allowedKey = stringBuilder.toString(); 106 assertThat(EMPTY.toBuilder().set(allowedKey, FIRST_VALUE).build().get(allowedKey)) 107 .isEqualTo(FIRST_VALUE); 108 } 109 110 @Test disallowsNullValue()111 public void disallowsNullValue() { 112 thrown.expect(NullPointerException.class); 113 EMPTY.toBuilder().set(FIRST_KEY, null).build(); 114 } 115 116 @Test valueCannotContainEqual()117 public void valueCannotContainEqual() { 118 thrown.expect(IllegalArgumentException.class); 119 EMPTY.toBuilder().set(FIRST_KEY, "my_vakue=5").build(); 120 } 121 122 @Test valueCannotContainComma()123 public void valueCannotContainComma() { 124 thrown.expect(IllegalArgumentException.class); 125 EMPTY.toBuilder().set(FIRST_KEY, "first,second").build(); 126 } 127 128 @Test valueCannotContainTrailingSpaces()129 public void valueCannotContainTrailingSpaces() { 130 thrown.expect(IllegalArgumentException.class); 131 EMPTY.toBuilder().set(FIRST_KEY, "first ").build(); 132 } 133 134 @Test invalidValueSize()135 public void invalidValueSize() { 136 char[] chars = new char[257]; 137 Arrays.fill(chars, 'a'); 138 String longValue = new String(chars); 139 thrown.expect(IllegalArgumentException.class); 140 EMPTY.toBuilder().set(FIRST_KEY, longValue).build(); 141 } 142 143 @Test allAllowedValueCharacters()144 public void allAllowedValueCharacters() { 145 StringBuilder stringBuilder = new StringBuilder(); 146 for (char c = ' ' /* '\u0020' */; c <= '~' /* '\u007E' */; c++) { 147 if (c == ',' || c == '=') { 148 continue; 149 } 150 stringBuilder.append(c); 151 } 152 String allowedValue = stringBuilder.toString(); 153 assertThat(EMPTY.toBuilder().set(FIRST_KEY, allowedValue).build().get(FIRST_KEY)) 154 .isEqualTo(allowedValue); 155 } 156 157 @Test addEntry()158 public void addEntry() { 159 assertThat(firstTracestate.toBuilder().set(SECOND_KEY, SECOND_VALUE).build()) 160 .isEqualTo(multiValueTracestate); 161 } 162 163 @Test updateEntry()164 public void updateEntry() { 165 assertThat(firstTracestate.toBuilder().set(FIRST_KEY, SECOND_VALUE).build().get(FIRST_KEY)) 166 .isEqualTo(SECOND_VALUE); 167 Tracestate updatedMultiValueTracestate = 168 multiValueTracestate.toBuilder().set(FIRST_KEY, SECOND_VALUE).build(); 169 assertThat(updatedMultiValueTracestate.get(FIRST_KEY)).isEqualTo(SECOND_VALUE); 170 assertThat(updatedMultiValueTracestate.get(SECOND_KEY)).isEqualTo(SECOND_VALUE); 171 } 172 173 @Test addAndUpdateEntry()174 public void addAndUpdateEntry() { 175 assertThat( 176 firstTracestate 177 .toBuilder() 178 .set(FIRST_KEY, SECOND_VALUE) // update the existing entry 179 .set(SECOND_KEY, FIRST_VALUE) // add a new entry 180 .build() 181 .getEntries()) 182 .containsExactly( 183 Entry.create(FIRST_KEY, SECOND_VALUE), Entry.create(SECOND_KEY, FIRST_VALUE)); 184 } 185 186 @Test addSameKey()187 public void addSameKey() { 188 assertThat( 189 EMPTY 190 .toBuilder() 191 .set(FIRST_KEY, SECOND_VALUE) // update the existing entry 192 .set(FIRST_KEY, FIRST_VALUE) // add a new entry 193 .build() 194 .getEntries()) 195 .containsExactly(Entry.create(FIRST_KEY, FIRST_VALUE)); 196 } 197 198 @Test remove()199 public void remove() { 200 assertThat(multiValueTracestate.toBuilder().remove(SECOND_KEY).build()) 201 .isEqualTo(firstTracestate); 202 } 203 204 @Test addAndRemoveEntry()205 public void addAndRemoveEntry() { 206 assertThat( 207 EMPTY 208 .toBuilder() 209 .set(FIRST_KEY, SECOND_VALUE) // update the existing entry 210 .remove(FIRST_KEY) // add a new entry 211 .build()) 212 .isEqualTo(EMPTY); 213 } 214 215 @Test remove_NullNotAllowed()216 public void remove_NullNotAllowed() { 217 thrown.expect(NullPointerException.class); 218 multiValueTracestate.toBuilder().remove(null).build(); 219 } 220 221 @Test tracestate_EqualsAndHashCode()222 public void tracestate_EqualsAndHashCode() { 223 EqualsTester tester = new EqualsTester(); 224 tester.addEqualityGroup(EMPTY, EMPTY); 225 tester.addEqualityGroup(firstTracestate, EMPTY.toBuilder().set(FIRST_KEY, FIRST_VALUE).build()); 226 tester.addEqualityGroup( 227 secondTracestate, EMPTY.toBuilder().set(SECOND_KEY, SECOND_VALUE).build()); 228 tester.testEquals(); 229 } 230 231 @Test tracestate_ToString()232 public void tracestate_ToString() { 233 assertThat(EMPTY.toString()).isEqualTo("Tracestate{entries=[]}"); 234 } 235 } 236