Skip to content

Commit

Permalink
Add unit tests for request_id exposed utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
odeke-em committed Jan 7, 2025
1 parent dd3c8fd commit b8630f5
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 53 deletions.
31 changes: 6 additions & 25 deletions src/request_id_header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class AtomicCounter {
return `${this.value()}`;
}

public reset(value: number) {
public reset() {
Atomics.store(this.backingBuffer, 0, 0);
}
}
Expand All @@ -65,7 +65,7 @@ const nthClientId = new AtomicCounter();

// Only exported for deterministic testing.
export function resetNthClientId() {
nthClientId.reset(0);
nthClientId.reset();
}

/*
Expand Down Expand Up @@ -152,27 +152,6 @@ class XGoogRequestHeaderInterceptor {
return this.streamCalls;
}

loggingClientInterceptor(options, call) {
const listener = new grpc.ListenerBuilder().withOnReceiveMessage(
(next, message) => {
console.log('Received message', JSON.stringify(message));
next(message);
}
);

const requester = new grpc.RequesterBuilder()
.withSendMessage((next, message) => {
console.log('Requesting', call.method, JSON.stringify(message));
next(message);
})
.build();
return new grpc.InterceptingCall(call(options), requester);
}

generateLoggingClientInterceptor() {
return this.loggingClientInterceptor.bind(this);
}

serverInterceptor(methodDescriptor, call) {
const method = call.handler.path;
const isUnary = call.handler.type === 'unary';
Expand Down Expand Up @@ -258,7 +237,10 @@ function injectRequestIDIntoError(config: any, err: Error) {

// Inject that RequestID into the actual
// error object regardless of the type.
Object.assign(err, {requestID: extractRequestID(config)});
const requestID = extractRequestID(config);
if (requestID) {
Object.assign(err, {requestID: requestID});
}
}

interface withNextNthRequest {
Expand Down Expand Up @@ -336,7 +318,6 @@ export {
X_GOOG_SPANNER_REQUEST_ID_HEADER,
XGoogRequestHeaderInterceptor,
craftRequestId,
extractRequestID,
injectRequestIDIntoError,
injectRequestIDIntoHeaders,
nextNthRequest,
Expand Down
166 changes: 139 additions & 27 deletions test/request_id_header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,147 @@

/* eslint-disable prefer-rest-params */
import * as assert from 'assert';
import {AtomicCounter} from '../src/request_id_header';

describe('AtomicCounter', () => {
it('Constructor with initialValue', done => {
const ac0 = new AtomicCounter();
assert.strictEqual(ac0.value(), 0);
assert.strictEqual(
ac0.increment(2),
2,
'increment should return the added value'
);
assert.strictEqual(
ac0.value(),
2,
'increment should have modified the value'
);
import {
RequestIDError,
X_GOOG_SPANNER_REQUEST_ID_HEADER,
craftRequestId,
injectRequestIDIntoError,
injectRequestIDIntoHeaders,
newAtomicCounter,
nextNthRequest,
randIdForProcess,
} from '../src/request_id_header';

describe('RequestId', () => {
describe('AtomicCounter', () => {
it('Constructor with initialValue', done => {
const ac0 = newAtomicCounter();
assert.deepStrictEqual(ac0.value(), 0);
assert.deepStrictEqual(
ac0.increment(2),
2,
'increment should return the added value'
);
assert.deepStrictEqual(
ac0.value(),
2,
'increment should have modified the value'
);

const ac1 = newAtomicCounter(1);
assert.deepStrictEqual(ac1.value(), 1);
assert.deepStrictEqual(
ac1.increment(1 << 27),
(1 << 27) + 1,
'increment should return the added value'
);
assert.deepStrictEqual(
ac1.value(),
(1 << 27) + 1,
'increment should have modified the value'
);
done();
});

it('reset', done => {
const ac0 = newAtomicCounter(1);
ac0.increment();
assert.strictEqual(ac0.value(), 2);
ac0.reset();
assert.strictEqual(ac0.value(), 0);
done();
});

it('toString', done => {
const ac0 = newAtomicCounter(1);
ac0.increment();
assert.strictEqual(ac0.value(), 2);
assert.strictEqual(ac0.toString(), '2');
assert.strictEqual(`${ac0}`, '2');
done();
});
});

describe('craftRequestId', () => {
it('with attempts', done => {
assert.strictEqual(
craftRequestId(1, 2, 3, 4),
`1.${randIdForProcess}.1.2.3.4`
);
done();
});
});

const ac1 = new AtomicCounter(1);
assert.strictEqual(ac1.value(), 1);
assert.strictEqual(
ac1.increment(1 << 27),
(1 << 27) + 1,
'increment should return the added value'
describe('injectRequestIDIntoError', () => {
it('with non-null error', done => {
const err: Error = new Error('this one');
const config = {headers: {}};
config.headers[X_GOOG_SPANNER_REQUEST_ID_HEADER] = '1.2.3.4.5.6';
injectRequestIDIntoError(config, err);
assert.strictEqual((err as RequestIDError).requestID, '1.2.3.4.5.6');
done();
});
});

describe('injectRequestIDIntoHeaders', () => {
it('with null session', done => {
const hdrs = {};
injectRequestIDIntoHeaders(hdrs, null, 2, 1);
done();
});

it('with nthRequest explicitly passed in', done => {
const session = {
parent: {
_nextNthRequest: () => {
return 5;
},
},
};
const got = injectRequestIDIntoHeaders({}, session, 2, 5);
const want = {
'x-goog-spanner-request-id': `1.${randIdForProcess}.1.1.2.5`,
};
assert.deepStrictEqual(got, want);
done();
});

it('infer nthRequest from session', done => {
const session = {
parent: {
_nextNthRequest: () => {
return 5;
},
},
};

const inputHeaders: {[k: string]: string} = {};
const got = injectRequestIDIntoHeaders(inputHeaders, session);
const want = {
'x-goog-spanner-request-id': `1.${randIdForProcess}.1.1.5.1`,
};
assert.deepStrictEqual(got, want);
done();
});
});

describe('nextNthRequest', () => {
const fauxDatabase = {};
assert.deepStrictEqual(
nextNthRequest(fauxDatabase),
1,
'Without override, should default to 1'
);
assert.strictEqual(
ac1.value(),
(1 << 27) + 1,
'increment should have modified the value'

Object.assign(fauxDatabase, {
_nextNthRequest: () => {
return 4;
},
});
assert.deepStrictEqual(
nextNthRequest(fauxDatabase),
4,
'With override should infer value'
);
done();
});
});
2 changes: 1 addition & 1 deletion test/spanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ describe('Spanner with mock server', () => {
servicePath: 'localhost',
port,
sslCreds: grpc.credentials.createInsecure(),
interceptors: [xGoogReqIDInterceptor.generateLoggingClientInterceptor()],
// interceptors: [xGoogReqIDInterceptor.generateLoggingClientInterceptor()],
});
// Gets a reference to a Cloud Spanner instance and database
instance = spanner.instance('instance');
Expand Down

0 comments on commit b8630f5

Please sign in to comment.