feat: Integration test for End to End tracing (#3691) · googleapis/java-spanner@bf1a07a (original) (raw)

``

1

`+

/*

`

``

2

`+

`

``

3

`+

`

``

4

`+

`

``

5

`+

`

``

6

`+

`

``

7

`+

`

``

8

`+

`

``

9

`+

`

``

10

`+

`

``

11

`+

`

``

12

`+

`

``

13

`+

`

``

14

`+

`

``

15

`+

*/

`

``

16

+

``

17

`+

package com.google.cloud.spanner.it;

`

``

18

+

``

19

`+

import static com.google.common.truth.Truth.assertThat;

`

``

20

`+

import static org.junit.Assert.assertTrue;

`

``

21

`+

import static org.junit.Assume.assumeTrue;

`

``

22

+

``

23

`+

import com.google.api.gax.core.FixedCredentialsProvider;

`

``

24

`+

import com.google.api.gax.rpc.ApiException;

`

``

25

`+

import com.google.api.gax.rpc.ResourceExhaustedException;

`

``

26

`+

import com.google.api.gax.rpc.StatusCode;

`

``

27

`+

import com.google.cloud.spanner.Database;

`

``

28

`+

import com.google.cloud.spanner.DatabaseClient;

`

``

29

`+

import com.google.cloud.spanner.IntegrationTestEnv;

`

``

30

`+

import com.google.cloud.spanner.IntegrationTestEnv.TestEnvOptions;

`

``

31

`+

import com.google.cloud.spanner.ParallelIntegrationTest;

`

``

32

`+

import com.google.cloud.spanner.ResultSet;

`

``

33

`+

import com.google.cloud.spanner.SpannerOptions;

`

``

34

`+

import com.google.cloud.spanner.SpannerOptionsHelper;

`

``

35

`+

import com.google.cloud.spanner.Statement;

`

``

36

`+

import com.google.cloud.spanner.Struct;

`

``

37

`+

import com.google.cloud.spanner.Type;

`

``

38

`+

import com.google.cloud.spanner.Type.StructField;

`

``

39

`+

import com.google.cloud.spanner.connection.ConnectionOptions;

`

``

40

`+

import com.google.cloud.trace.v1.TraceServiceClient;

`

``

41

`+

import com.google.cloud.trace.v1.TraceServiceSettings;

`

``

42

`+

import com.google.common.base.Stopwatch;

`

``

43

`+

import io.opentelemetry.api.trace.Span;

`

``

44

`+

import io.opentelemetry.api.trace.Tracer;

`

``

45

`+

import io.opentelemetry.context.Scope;

`

``

46

`+

import java.io.IOException;

`

``

47

`+

import java.util.Arrays;

`

``

48

`+

import java.util.Collection;

`

``

49

`+

import java.util.concurrent.TimeUnit;

`

``

50

`+

import org.junit.AfterClass;

`

``

51

`+

import org.junit.BeforeClass;

`

``

52

`+

import org.junit.ClassRule;

`

``

53

`+

import org.junit.Test;

`

``

54

`+

import org.junit.experimental.categories.Category;

`

``

55

`+

import org.junit.runner.RunWith;

`

``

56

`+

import org.junit.runners.JUnit4;

`

``

57

+

``

58

`+

/** Integration tests for End to End Tracing. */

`

``

59

`+

@Category(ParallelIntegrationTest.class)

`

``

60

`+

@RunWith(JUnit4.class)

`

``

61

`+

public class ITEndToEndTracingTest {

`

``

62

`+

public static Collection testEnvOptions =

`

``

63

`+

Arrays.asList(TestEnvOptions.USE_END_TO_END_TRACING);

`

``

64

`+

@ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(testEnvOptions);

`

``

65

`+

private static DatabaseClient googleStandardSQLClient;

`

``

66

+

``

67

`+

static {

`

``

68

`+

SpannerOptionsHelper.resetActiveTracingFramework();

`

``

69

`+

SpannerOptions.enableOpenTelemetryTraces();

`

``

70

`+

}

`

``

71

+

``

72

`+

private static String selectValueQuery = "SELECT @p1 + @p1";

`

``

73

+

``

74

`+

@BeforeClass

`

``

75

`+

public static void setUp() {

`

``

76

`+

setUpDatabase();

`

``

77

`+

}

`

``

78

+

``

79

`+

public static void setUpDatabase() {

`

``

80

`+

// Empty database.

`

``

81

`+

Database googleStandardSQLDatabase = env.getTestHelper().createTestDatabase();

`

``

82

`+

googleStandardSQLClient = env.getTestHelper().getDatabaseClient(googleStandardSQLDatabase);

`

``

83

`+

}

`

``

84

+

``

85

`+

@AfterClass

`

``

86

`+

public static void teardown() {

`

``

87

`+

ConnectionOptions.closeSpanner();

`

``

88

`+

}

`

``

89

+

``

90

`+

private void assertTrace(String traceId) throws IOException, InterruptedException {

`

``

91

`+

TraceServiceSettings settings =

`

``

92

`+

env.getTestHelper().getOptions().getCredentials() == null

`

``

93

`+

? TraceServiceSettings.newBuilder().build()

`

``

94

`+

: TraceServiceSettings.newBuilder()

`

``

95

`+

.setCredentialsProvider(

`

``

96

`+

FixedCredentialsProvider.create(

`

``

97

`+

env.getTestHelper().getOptions().getCredentials()))

`

``

98

`+

.build();

`

``

99

`+

try (TraceServiceClient client = TraceServiceClient.create(settings)) {

`

``

100

`+

boolean foundTrace = false;

`

``

101

`+

Stopwatch metricsPollingStopwatch = Stopwatch.createStarted();

`

``

102

`+

while (!foundTrace && metricsPollingStopwatch.elapsed(TimeUnit.SECONDS) < 30) {

`

``

103

`+

// Try every 5 seconds

`

``

104

`+

Thread.sleep(5000);

`

``

105

`+

try {

`

``

106

`+

foundTrace =

`

``

107

`+

client.getTrace(env.getTestHelper().getInstanceId().getProject(), traceId)

`

``

108

`+

.getSpansList().stream()

`

``

109

`+

.anyMatch(span -> "Spanner.ExecuteStreamingSql".equals(span.getName()));

`

``

110

`+

} catch (ApiException apiException) {

`

``

111

`+

assumeTrue(

`

``

112

`+

apiException.getStatusCode() != null

`

``

113

`+

&& StatusCode.Code.NOT_FOUND.equals(apiException.getStatusCode().getCode()));

`

``

114

`+

System.out.println("Trace NOT_FOUND error ignored");

`

``

115

`+

}

`

``

116

`+

}

`

``

117

`+

assertTrue(foundTrace);

`

``

118

`+

} catch (ResourceExhaustedException resourceExhaustedException) {

`

``

119

`+

if (resourceExhaustedException

`

``

120

`+

.getMessage()

`

``

121

`+

.contains("Quota exceeded for quota metric 'Read requests (free)'")) {

`

``

122

`+

// Ignore and allow the test to succeed.

`

``

123

`+

System.out.println("RESOURCE_EXHAUSTED error ignored");

`

``

124

`+

} else {

`

``

125

`+

throw resourceExhaustedException;

`

``

126

`+

}

`

``

127

`+

}

`

``

128

`+

}

`

``

129

+

``

130

`+

private Struct executeWithRowResultType(Statement statement, Type expectedRowType) {

`

``

131

`+

ResultSet resultSet = statement.executeQuery(googleStandardSQLClient.singleUse());

`

``

132

`+

assertThat(resultSet.next()).isTrue();

`

``

133

`+

assertThat(resultSet.getType()).isEqualTo(expectedRowType);

`

``

134

`+

Struct row = resultSet.getCurrentRowAsStruct();

`

``

135

`+

assertThat(resultSet.next()).isFalse();

`

``

136

`+

return row;

`

``

137

`+

}

`

``

138

+

``

139

`+

@Test

`

``

140

`+

public void simpleSelect() throws IOException, InterruptedException {

`

``

141

`+

Tracer tracer =

`

``

142

`+

env.getTestHelper()

`

``

143

`+

.getOptions()

`

``

144

`+

.getOpenTelemetry()

`

``

145

`+

.getTracer(ITEndToEndTracingTest.class.getName());

`

``

146

`+

Span span = tracer.spanBuilder("simpleSelect").startSpan();

`

``

147

`+

Scope scope = span.makeCurrent();

`

``

148

`+

Type rowType = Type.struct(StructField.of("", Type.int64()));

`

``

149

`+

Struct row =

`

``

150

`+

executeWithRowResultType(

`

``

151

`+

Statement.newBuilder(selectValueQuery).bind("p1").to(1234).build(), rowType);

`

``

152

`+

assertThat(row.isNull(0)).isFalse();

`

``

153

`+

assertThat(row.getLong(0)).isEqualTo(2468);

`

``

154

`+

scope.close();

`

``

155

`+

span.end();

`

``

156

`+

assertTrace(span.getSpanContext().getTraceId());

`

``

157

`+

}

`

``

158

`+

}

`