Skip to content

Commit

Permalink
test: reduce cross-pollution of spans between tests with better isola…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
odeke-em committed Aug 8, 2024
1 parent 8efe033 commit 0292910
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 89 deletions.
58 changes: 34 additions & 24 deletions observability-test/grpc-instrumentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// 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.
//

describe('Enabled gRPC instrumentation with sampling on', () => {
const assert = require('assert');
Expand All @@ -30,47 +29,58 @@ describe('Enabled gRPC instrumentation with sampling on', () => {
instrumentations: [new GrpcInstrumentation()],
});
const {
startTrace,
disableContextAndManager,
setGlobalContextManager,
setTracerProvider,
startTrace,

Check warning on line 35 in observability-test/grpc-instrumentation.ts

View workflow job for this annotation

GitHub Actions / lint

'startTrace' is assigned a value but never used
} = require('../src/instrument');

const contextManager = new AsyncHooksContextManager();
setGlobalContextManager(contextManager);

const projectId = process.env.SPANNER_TEST_PROJECTID || 'test-project';
const exporter = new InMemorySpanExporter();
const sampler = new AlwaysOnSampler();
const provider = new NodeTracerProvider({
sampler: sampler,
exporter: exporter,
});
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();

const projectId = process.env.SPANNER_TEST_PROJECTID || 'test-project';
const {Spanner} = require('../src');
const spanner = new Spanner({
projectId: projectId,
});
const instance = spanner.instance('test-instance');
const database = instance.database('test-db');
const {Database, Spanner} = require('../src');

let provider: typeof NodeTracerProvider;
let contextManager: typeof ContextManager;
let spanner: typeof Spanner;
let database: typeof Database;

beforeEach(async () => {
provider = new NodeTracerProvider({
sampler: sampler,
exporter: exporter,
});
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
setTracerProvider(provider);

contextManager = new AsyncHooksContextManager();
setGlobalContextManager(contextManager);

spanner = new Spanner({
projectId: projectId,
});

const instance = spanner.instance('test-instance');
database = instance.database('test-db');

// Warm up session creation.
await database.run('SELECT 2');
// Mimick usual customer usage in which at setup time, the
// Spanner and Database handles are created once then sit
// and wait until they service HTTP or gRPC calls that
// come in say 5+ seconds after the service is fully started.
// This gives time for the batch session creation to be be completed.
await new Promise((resolve, reject) => setTimeout(resolve, 100));

Check warning on line 75 in observability-test/grpc-instrumentation.ts

View workflow job for this annotation

GitHub Actions / lint

'reject' is defined but never used

exporter.reset();
});

after(async () => {
database.close();
afterEach(async () => {
spanner.close();
exporter.forceFlush();
exporter.reset();
await provider.shutdown();
fini();
disableContextAndManager(contextManager);
});

it('Invoking database methods creates spans: gRPC enabled', () => {
Expand All @@ -88,7 +98,7 @@ describe('Enabled gRPC instrumentation with sampling on', () => {

span.end();

await new Promise((resolve, reject) => setTimeout(resolve, 1900));
await new Promise((resolve, reject) => setTimeout(resolve, 600));

Check warning on line 101 in observability-test/grpc-instrumentation.ts

View workflow job for this annotation

GitHub Actions / lint

'reject' is defined but never used
await exporter.forceFlush();

// We need to ensure that spans were generated and exported.
Expand Down
175 changes: 110 additions & 65 deletions observability-test/observability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,90 +64,77 @@ describe('Testing spans produced with a sampler on', () => {

spanner = new Spanner({
projectId: projectId,
observabilityConfig: {
tracerProvider: provider,
},
});

const instance = spanner.instance('test-instance');
database = instance.database('test-db');

// Warm up session creation.
await database.run('SELECT 2');
await new Promise((resolve, reject) => setTimeout(resolve, 100));
// await new Promise((resolve, reject) => setTimeout(resolve, 100));
});

afterEach(async () => {
database.close();
spanner.close();
exporter.forceFlush();
exporter.reset();
await provider.shutdown();
disableContextAndManager(contextManager);
});

it('Invoking database methods creates spans: no gRPC instrumentation', async () => {
it('Invoking database methods creates spans: no gRPC instrumentation', () => {
const query = {sql: 'SELECT 1'};
const [rows] = await database.run(query);
assert.strictEqual(rows.length, 1);

const spans = exporter.getFinishedSpans();
// We need to ensure that spans were generated and exported
// correctly.
assert.ok(spans.length > 0, 'at least 1 span must have been created');

// Now sort the spans by duration, in reverse magnitude order.
spans.sort((spanA, spanB) => {
return spanA.duration > spanB.duration;
});

const got: string[] = [];
spans.forEach(span => {
got.push(span.name);
});

const want = [
'cloud.google.com/nodejs/spanner/Database.runStream',
'cloud.google.com/nodejs/spanner/Database.run',
'cloud.google.com/nodejs/spanner/Transaction.runStream',
];

assert.deepEqual(
want,
got,
'The spans order by duration has been violated:\n\tGot: ' +
got.toString() +
'\n\tWant: ' +
want.toString()
);

// Ensure that each span has the attribute
// SEMATTRS_DB_SYSTEM, set to 'spanner'
spans.forEach(span => {
assert.equal(
span.attributes[SEMATTRS_DB_SYSTEM],
'spanner',
'Missing DB_SYSTEM attribute'
);
assert.equal(
span.attributes[SEMATTRS_DB_STATEMENT],
undefined,
'unexpected DB_STATEMENT attribute without it being toggled'
database.run(query, async (err, rows, stats, metadata) => {

Check warning on line 87 in observability-test/observability.ts

View workflow job for this annotation

GitHub Actions / lint

'stats' is defined but never used

Check warning on line 87 in observability-test/observability.ts

View workflow job for this annotation

GitHub Actions / lint

'metadata' is defined but never used
assert.strictEqual(rows.length, 1);

// Give sometime for spans to be exported.
await new Promise((resolve, reject) => setTimeout(resolve, 500));

Check warning on line 91 in observability-test/observability.ts

View workflow job for this annotation

GitHub Actions / lint

'reject' is defined but never used

const spans = exporter.getFinishedSpans();
// We need to ensure that spans were generated and exported
// correctly.
assert.ok(spans.length > 0, 'at least 1 span must have been created');

// Now sort the spans by duration, in reverse magnitude order.
spans.sort((spanA, spanB) => {
return spanA.duration > spanB.duration;
});

const got: string[] = [];
spans.forEach(span => {
got.push(span.name);
});

const want = [
'cloud.google.com/nodejs/spanner/Database.runStream',
'cloud.google.com/nodejs/spanner/Database.run',
'cloud.google.com/nodejs/spanner/Transaction.runStream',
];

assert.deepEqual(
want,
got,
'The spans order by duration has been violated:\n\tGot: ' +
got.toString() +
'\n\tWant: ' +
want.toString()
);
});
});

it('Closing the client creates the closing span', () => {
spanner.close();

const spans = exporter.getFinishedSpans();
// We need to ensure that spans were generated and exported
// correctly.
assert.ok(spans.length == 1, 'exactly 1 span must have been created');
assert.strictEqual(
spans[0].name,
'cloud.google.com/nodejs/spanner/Spanner.close'
);
// Ensure that each span has the attribute
// SEMATTRS_DB_SYSTEM, set to 'spanner'
spans.forEach(span => {
assert.equal(
span.attributes[SEMATTRS_DB_SYSTEM],
'spanner',
'Missing DB_SYSTEM attribute'
);
assert.equal(
span.attributes[SEMATTRS_DB_STATEMENT],
undefined,
'unexpected DB_STATEMENT attribute without it being toggled'
);
});
});
});
});

Expand Down Expand Up @@ -176,14 +163,15 @@ describe('Extended tracing', () => {
});

afterEach(async () => {
database.close();
spanner.close();
exporter.forceFlush();
exporter.reset();
await provider.shutdown();
disableContextAndManager(contextManager);
});

after(async () => {});

const methodsTakingSQL = {
'cloud.google.com/nodejs/spanner/Database.run': true,
'cloud.google.com/nodejs/spanner/Database.runStream': true,
Expand Down Expand Up @@ -368,6 +356,63 @@ describe('Capturing sessionPool annotations', () => {
});
});

describe('Close span', () => {
const exporter = new InMemorySpanExporter();
const sampler = new AlwaysOnSampler();

const {Spanner} = require('../src');

const provider = new NodeTracerProvider({
sampler: sampler,
exporter: exporter,
});
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
setTracerProvider(provider);

const contextManager = new AsyncHooksContextManager();
setGlobalContextManager(contextManager);

afterEach(async () => {
exporter.forceFlush();
exporter.reset();
await provider.shutdown();
disableContextAndManager(contextManager);
});

it('Close span must be emitted', async () => {
const spanner = new Spanner({
projectId: projectId,
});
spanner.close();

const spans = exporter.getFinishedSpans();

spans.sort((spanA, spanB) => {
return spanA.startTime < spanB.startTime;
});
const gotSpans: string[] = [];
spans.forEach(span => {
gotSpans.push(span.name);
});
// We need to ensure that spans were generated and exported
// correctly.
assert.strictEqual(
spans.length,
1,
'exactly 1 span must have been emitted ' + gotSpans.toString()
);

const got = spans[0].name;
const want = 'cloud.google.com/nodejs/spanner/Spanner.close';
assert.deepEqual(
want,
got,
'Mismatched span:\n\tGot: ' + got + '\n\tWant: ' + want
);
});
});

describe('Always off sampler used', () => {
const exporter = new InMemorySpanExporter();
const sampler = new AlwaysOffSampler();
Expand Down

0 comments on commit 0292910

Please sign in to comment.