Skip to content

Commit

Permalink
Added more detailed user agent string (#223)
Browse files Browse the repository at this point in the history
* Added more detailed user agent string

* Added tests for user agent

* Getting rid of file that has been renamed

* Responding to feedback

* Responding to rest of feedback

* Added nock test for user agent

* Updated tests to use assert.equal instead of assert
  • Loading branch information
damccorm authored Sep 21, 2018
1 parent e88c657 commit 7b66ae5
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 6 deletions.
24 changes: 21 additions & 3 deletions api/WebApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ import * as rm from 'typed-rest-client/RestClient';
import vsom = require('./VsoClient');
import lim = require("./interfaces/LocationsInterfaces");

import fs = require('fs');
import crypto = require('crypto');
import fs = require('fs');
import os = require('os');

/**
* Methods to return handler objects (see handlers folder)
Expand Down Expand Up @@ -67,6 +68,11 @@ export function getHandlerFromToken(token: string): VsoBaseInterfaces.IRequestHa
}
}

export interface IWebApiRequestSettings {
productName: string,
productVersion: string
};

// ---------------------------------------------------------------------------
// Factory to return client apis
// When new APIs are added, a method must be added here to instantiate the API
Expand All @@ -86,7 +92,7 @@ export class WebApi {
* @param defaultUrl default server url to use when creating new apis from factory methods
* @param authHandler default authentication credentials to use when creating new apis from factory methods
*/
constructor(defaultUrl: string, authHandler: VsoBaseInterfaces.IRequestHandler, options?: VsoBaseInterfaces.IRequestOptions) {
constructor(defaultUrl: string, authHandler: VsoBaseInterfaces.IRequestHandler, options?: VsoBaseInterfaces.IRequestOptions, requestSettings?: IWebApiRequestSettings) {
this.serverUrl = defaultUrl;
this.authHandler = authHandler;
this.options = options || {};
Expand Down Expand Up @@ -124,7 +130,19 @@ export class WebApi {
this.options.ignoreSslError = !!global['_vsts_task_lib_skip_cert_validation'];
}

this.rest = new rm.RestClient('vsts-node-api', null, [this.authHandler], this.options);
let userAgent: string;
const nodeApiName: string = 'azure-devops-node-api';
const nodeApiVersion: string = JSON.parse(fs.readFileSync('package.json', 'utf8')).version;
const osName: string = os.platform();
const osVersion: string = os.release();

if(requestSettings) {
userAgent = `${requestSettings.productName}/${requestSettings.productVersion} (${nodeApiName} ${nodeApiVersion}; ${osName} ${osVersion})`;
}
else {
userAgent = `${nodeApiName}/${nodeApiVersion} (${osName} ${osVersion})`;
}
this.rest = new rm.RestClient(userAgent, null, [this.authHandler], this.options);
this.vsoClient = new vsom.VsoClient(defaultUrl, this.rest);
}

Expand Down
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
],
"license": "MIT",
"dependencies": {
"os": "0.1.1",
"tunnel": "0.0.4",
"typed-rest-client": "1.0.9",
"underscore": "1.8.3"
Expand Down
5 changes: 5 additions & 0 deletions samples/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 68 additions & 2 deletions test/units/vsoClientTests.ts → test/units/tests.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import assert = require('assert');
import fs = require('fs');
import nock = require('nock');
import os = require('os');
import vsom = require('../../api/VsoClient');
import WebApi = require('../../api/WebApi');
import * as rm from 'typed-rest-client/RestClient';
import { resolve } from 'path';
import { ApiResourceLocation } from '../../api/interfaces/common/VsoBaseInterfaces';

describe('VSOClient Units', function () {
Expand All @@ -27,7 +29,6 @@ describe('VSOClient Units', function () {
it('constructs', () => {
//Arrange
this.timeout(1000);
const baseUrl = 'https://dev.azure.com/';
const userAgent: string = "testAgent";
const rest: rm.RestClient = new rm.RestClient(userAgent, null, []);

Expand Down Expand Up @@ -182,4 +183,69 @@ describe('VSOClient Units', function () {
//Assert
assert(res.id === "testLocation");
});
});

describe('WebApi Units', function () {
const osName: string = os.platform();
const osVersion: string = os.release();
const nodeApiName: string = 'azure-devops-node-api';
const nodeApiVersion: string = JSON.parse(fs.readFileSync('package.json', 'utf8')).version;

it('sets the user agent correctly when request settings are specified', async () => {
const myWebApi: WebApi.WebApi = new WebApi.WebApi('microsoft.com', WebApi.getBasicHandler('user', 'password'),
undefined, {productName: 'name', productVersion: '1.2.3'});
const userAgent: string = `name/1.2.3 (${nodeApiName} ${nodeApiVersion}; ${osName} ${osVersion})`;
assert.equal(userAgent, myWebApi.rest.client.userAgent, 'User agent should be: ' + userAgent);
});

it('sets the user agent correctly when request settings are not specified', async () => {
const myWebApi: WebApi.WebApi = new WebApi.WebApi('microsoft.com', WebApi.getBasicHandler('user', 'password'), undefined);
const userAgent: string = `${nodeApiName}/${nodeApiVersion} (${osName} ${osVersion})`;
assert.equal(userAgent, myWebApi.rest.client.userAgent, 'User agent should be: ' + userAgent);
});

it('connects to the server with the correct user agent when request settings are specified', async () => {
const myWebApi: WebApi.WebApi = new WebApi.WebApi('https://dev.azure.com/', WebApi.getBasicHandler('user', 'password'),
undefined, {productName: 'name', productVersion: '1.2.3'});
const userAgent: string = `name/1.2.3 (${nodeApiName} ${nodeApiVersion}; ${osName} ${osVersion})`;
nock('https://dev.azure.com/_apis/testArea', {
reqheaders: {
'accept': 'application/json',
'user-agent': userAgent
}})
.options('')
.reply(200, {
value: [{id: 'testLocation', maxVersion: '1', releasedVersion: '1', routeTemplate: 'testTemplate', area: 'testArea', resourceName: 'testName', resourceVersion: '1'}]
});

// Act
const res: vsom.ClientVersioningData = await myWebApi.vsoClient.getVersioningData('1', 'testArea', 'testLocation', {'testKey': 'testValue'}, null);

// Assert
assert.equal(res.apiVersion, '1');
assert.equal(res.requestUrl, 'https://dev.azure.com/testTemplate');

});

it('connects to the server with the correct user agent when request settings are not specified', async () => {
// Arrange
const myWebApi: WebApi.WebApi = new WebApi.WebApi('https://dev.azure.com/', WebApi.getBasicHandler('user', 'password'), null);
const userAgent: string = `${nodeApiName}/${nodeApiVersion} (${osName} ${osVersion})`;
nock('https://dev.azure.com/_apis/testArea', {
reqheaders: {
'accept': 'application/json',
'user-agent': userAgent
}})
.options('')
.reply(200, {
value: [{id: 'testLocation', maxVersion: '1', releasedVersion: '1', routeTemplate: 'testTemplate', area: 'testArea', resourceName: 'testName', resourceVersion: '1'}]
});

// Act
const res: vsom.ClientVersioningData = await myWebApi.vsoClient.getVersioningData('1', 'testArea', 'testLocation', {'testKey': 'testValue'}, null);

// Assert
assert.equal(res.apiVersion, '1');
assert.equal(res.requestUrl, 'https://dev.azure.com/testTemplate');
});
});

0 comments on commit 7b66ae5

Please sign in to comment.