Skip to content

Commit

Permalink
service tests for [cocoapods] (#1472)
Browse files Browse the repository at this point in the history
* service tests for [cocoapods]

* Add tests for CocoaPods Endpoints

Bug fixes:
* Call `metrics.cocoapods.org` API endpoints over HTTPs
* Show correct left-side badge text on error in version/platform/license badges
* Handle null doc coverage gracefully
* Add handling for 'not found' responses

* drop last param to checkErrorResponse

* remove redundant line

* set badge label using more terse notation

* specify allowed platform values
  • Loading branch information
chris48s authored and paulmelnikow committed Feb 3, 2018
1 parent e4199bc commit cbb263b
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 16 deletions.
29 changes: 13 additions & 16 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3383,11 +3383,11 @@ cache(function(data, match, sendBadge, request) {
var spec = match[2]; // eg, AFNetworking
var format = match[3];
var apiUrl = 'https://trunk.cocoapods.org/api/v1/pods/' + spec + '/specs/latest';
var badgeData = getBadgeData('pod', data);
const typeToLabel = {'v' : 'pod', 'p': 'platform', 'l': 'license'};
const badgeData = getBadgeData(typeToLabel[type], data);
badgeData.colorscheme = null;
request(apiUrl, function(err, res, buffer) {
if (err != null) {
badgeData.text[1] = 'inaccessible';
if (checkErrorResponse(badgeData, err, res)) {
sendBadge(format, badgeData);
return;
}
Expand All @@ -3407,11 +3407,9 @@ cache(function(data, match, sendBadge, request) {
badgeData.text[1] = versionText(version);
badgeData.colorscheme = versionColor(version);
} else if (type === 'p') {
badgeData.text[0] = getLabel('platform', data);
badgeData.text[1] = platforms;
badgeData.colorB = '#989898';
} else if (type === 'l') {
badgeData.text[0] = getLabel('license', data);
badgeData.text[1] = license;
badgeData.colorB = '#373737';
}
Expand All @@ -3429,19 +3427,20 @@ camp.route(/^\/cocoapods\/metrics\/doc-percent\/(.*)\.(svg|png|gif|jpg|json)$/,
cache(function(data, match, sendBadge, request) {
var spec = match[1]; // eg, AFNetworking
var format = match[2];
var apiUrl = 'http://metrics.cocoapods.org/api/v1/pods/' + spec;
var badgeData = getBadgeData('pod', data);
var apiUrl = 'https://metrics.cocoapods.org/api/v1/pods/' + spec;
var badgeData = getBadgeData('docs', data);
request(apiUrl, function(err, res, buffer) {
if (err != null) {
badgeData.text[1] = 'inaccessible';
if (checkErrorResponse(badgeData, err, res)) {
sendBadge(format, badgeData);
return;
}
try {
var parsedData = JSON.parse(buffer);
var percentage = parsedData.cocoadocs.doc_percent;
if (percentage == null) {
percentage = 0;
}
badgeData.colorscheme = coveragePercentageColor(percentage);
badgeData.text[0] = getLabel('docs', data);
badgeData.text[1] = percentage + '%';
sendBadge(format, badgeData);
} catch(e) {
Expand All @@ -3457,11 +3456,10 @@ cache(function(data, match, sendBadge, request) {
var info = match[1]; // One of these: "dm", "dw", "dt"
var spec = match[2]; // eg, AFNetworking
var format = match[3];
var apiUrl = 'http://metrics.cocoapods.org/api/v1/pods/' + spec;
var apiUrl = 'https://metrics.cocoapods.org/api/v1/pods/' + spec;
var badgeData = getBadgeData('downloads', data);
request(apiUrl, function(err, res, buffer) {
if (err != null) {
badgeData.text[1] = 'inaccessible';
if (checkErrorResponse(badgeData, err, res)) {
sendBadge(format, badgeData);
return;
}
Expand Down Expand Up @@ -3497,11 +3495,10 @@ cache(function(data, match, sendBadge, request) {
var info = match[1]; // One of these: "aw", "at"
var spec = match[2]; // eg, AFNetworking
var format = match[3];
var apiUrl = 'http://metrics.cocoapods.org/api/v1/pods/' + spec;
var apiUrl = 'https://metrics.cocoapods.org/api/v1/pods/' + spec;
var badgeData = getBadgeData('apps', data);
request(apiUrl, function(err, res, buffer) {
if (err != null) {
badgeData.text[1] = 'inaccessible';
if (checkErrorResponse(badgeData, err, res)) {
sendBadge(format, badgeData);
return;
}
Expand Down
204 changes: 204 additions & 0 deletions service-tests/cocoapods.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
'use strict';

const Joi = require('joi');
const ServiceTester = require('./runner/service-tester');

const {
isMetric,
isMetricOverTimePeriod,
isIntegerPercentage,
isVPlusDottedVersionAtLeastOne,
} = require('./helpers/validators');

const isPlatform = Joi.string().regex(/^(osx|ios|tvos|watchos)( \| (osx|ios|tvos|watchos))*$/);

const t = new ServiceTester({ id: 'cocoapods', title: 'Cocoa Pods' });
module.exports = t;


// version endpoint

t.create('version (valid)')
.get('/v/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'pod',
value: isVPlusDottedVersionAtLeastOne
}));

t.create('version (not found)')
.get('/v/not-a-package.json')
.expectJSON({name: 'pod', value: 'not found'});

t.create('version (connection error)')
.get('/v/AFNetworking.json')
.networkOff()
.expectJSON({name: 'pod', value: 'inaccessible'});

t.create('version (unexpected response)')
.get('/v/AFNetworking.json')
.intercept(nock => nock('https://trunk.cocoapods.org')
.get('/api/v1/pods/AFNetworking/specs/latest')
.reply(200, "{{{{{invalid json}}")
)
.expectJSON({name: 'pod', value: 'invalid'});


// platform endpoint

t.create('platform (valid)')
.get('/p/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'platform',
value: isPlatform
}));

t.create('platform (not found)')
.get('/p/not-a-package.json')
.expectJSON({name: 'platform', value: 'not found'});

t.create('platform (connection error)')
.get('/p/AFNetworking.json')
.networkOff()
.expectJSON({name: 'platform', value: 'inaccessible'});

t.create('platform (unexpected response)')
.get('/p/AFNetworking.json')
.intercept(nock => nock('https://trunk.cocoapods.org')
.get('/api/v1/pods/AFNetworking/specs/latest')
.reply(200, "{{{{{invalid json}}")
)
.expectJSON({name: 'platform', value: 'invalid'});


// license endpoint

t.create('license (valid)')
.get('/l/AFNetworking.json')
.expectJSON({name: 'license', value: 'MIT'});

t.create('license (not found)')
.get('/l/not-a-package.json')
.expectJSON({name: 'license', value: 'not found'});

t.create('license (connection error)')
.get('/l/AFNetworking.json')
.networkOff()
.expectJSON({name: 'license', value: 'inaccessible'});

t.create('license (unexpected response)')
.get('/l/AFNetworking.json')
.intercept(nock => nock('https://trunk.cocoapods.org')
.get('/api/v1/pods/AFNetworking/specs/latest')
.reply(200, "{{{{{invalid json}}")
)
.expectJSON({name: 'license', value: 'invalid'});


// doc percent endpoint

t.create('doc percent (valid)')
.get('/metrics/doc-percent/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'docs',
value: isIntegerPercentage
}));

t.create('doc percent (null)')
.get('/metrics/doc-percent/AFNetworking.json')
.intercept(nock => nock('https://metrics.cocoapods.org')
.get('/api/v1/pods/AFNetworking')
.reply(200, '{"cocoadocs": {"doc_percent": null}}')
)
.expectJSON({name: 'docs', value: '0%'});;

t.create('doc percent (not found)')
.get('/metrics/doc-percent/not-a-package.json')
.expectJSON({name: 'docs', value: 'not found'});

t.create('doc percent (connection error)')
.get('/metrics/doc-percent/AFNetworking.json')
.networkOff()
.expectJSON({name: 'docs', value: 'inaccessible'});

t.create('doc percent (unexpected response)')
.get('/metrics/doc-percent/AFNetworking.json')
.intercept(nock => nock('https://metrics.cocoapods.org')
.get('/api/v1/pods/AFNetworking')
.reply(200, "{{{{{invalid json}}")
)
.expectJSON({name: 'docs', value: 'invalid'});


// downloads endpoints

t.create('downloads (valid, monthly)')
.get('/dm/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'downloads',
value: isMetricOverTimePeriod
}));

t.create('downloads (valid, weekly)')
.get('/dw/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'downloads',
value: isMetricOverTimePeriod
}));

t.create('downloads (valid, total)')
.get('/dt/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'downloads',
value: isMetric
}));

t.create('downloads (not found)')
.get('/dt/not-a-package.json')
.expectJSON({name: 'downloads', value: 'not found'});

t.create('downloads (connection error)')
.get('/dt/AFNetworking.json')
.networkOff()
.expectJSON({name: 'downloads', value: 'inaccessible'});

t.create('downloads (unexpected response)')
.get('/dt/AFNetworking.json')
.intercept(nock => nock('https://metrics.cocoapods.org')
.get('/api/v1/pods/AFNetworking')
.reply(200, "{{{{{invalid json}}")
)
.expectJSON({name: 'downloads', value: 'invalid'});


// apps endpoints

t.create('apps (valid, weekly)')
.get('/aw/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'apps',
value: isMetricOverTimePeriod
}));

t.create('apps (valid, total)')
.get('/at/AFNetworking.json')
.expectJSONTypes(Joi.object().keys({
name: 'apps',
value: isMetric
}));

t.create('apps (not found)')
.get('/at/not-a-package.json')
.expectJSON({name: 'apps', value: 'not found'});

t.create('apps (connection error)')
.get('/at/AFNetworking.json')
.networkOff()
.expectJSON({name: 'apps', value: 'inaccessible'});

t.create('apps (unexpected response)')
.get('/at/AFNetworking.json')
.intercept(nock => nock('https://metrics.cocoapods.org')
.get('/api/v1/pods/AFNetworking')
.reply(200, "{{{{{invalid json}}")
)
.expectJSON({name: 'apps', value: 'invalid'});

0 comments on commit cbb263b

Please sign in to comment.