Skip to content

Commit

Permalink
Merge branch 'release/4.4.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
codenirvana committed Jul 29, 2024
2 parents 9b99f37 + d6acd44 commit b31a70e
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,4 @@ jobs:

- if: ${{ matrix.coverage }}
name: Upload coverage
run: npm run codecov -- -c -Z -f .coverage/coverage-final.json -F unit
run: npm run codecov -- -c -Z -f .coverage/coverage-final.json -F unit -t ${{ secrets.CODECOV_TOKEN }}
8 changes: 8 additions & 0 deletions CHANGELOG.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
4.4.1:
date: 2024-07-29
fixed bugs:
- GH-1366 Fixed a bug where $randomAvatarImage was returning an invalid URL
chores:
- GH-1362 Updated `Request~size` to handle `downloadedBytes` property
- GH-1364 Added support for `prefix` in VariableScope

4.4.0:
date: 2024-02-28
new features:
Expand Down
3 changes: 2 additions & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ coverage:

# coverage status for unit tests
unit:
flags: unit
target: 100
flags:
- unit

parsers:
javascript:
Expand Down
68 changes: 35 additions & 33 deletions lib/collection/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ _.assign(Response.prototype, /** @lends Response.prototype */ {
update (options) {
// options.stream accepts Buffer, Buffer.toJSON() or base64 string
// @todo this temporarily doubles the memory footprint (options.stream + generated buffer).
var stream = normalizeStream(options.stream);
const stream = normalizeStream(options.stream);

_.mergeDefined((this._details = _.clone(httpReasons.lookup(options.code))), {
name: _.choose(options.reason, options.status),
Expand Down Expand Up @@ -255,7 +255,13 @@ _.assign(Response.prototype, /** @lends Response.prototype */ {
* @private
* @type {Number}
*/
responseSize: stream && stream.byteLength
responseSize: stream && stream.byteLength,

/**
* @private
* @type {Number}
*/
downloadedBytes: options.downloadedBytes
});
}
});
Expand Down Expand Up @@ -397,61 +403,57 @@ _.assign(Response.prototype, /** @lends Response.prototype */ {
},

/**
* Get the response size by computing the same from content length header or using the actual response body.
* @typedef Response.sizeInfo
* @property {Number} body - size of the response body in bytes
* @property {Number} header - size of the response header in bytes
* @property {Number} total - total size of the response body and header in bytes
*/
/**
* Get the response size by computing the same from content length header or
* using the actual response body.
*
* @returns {Number}
* @todo write unit tests
* @returns {Response.sizeInfo} - Response size object
*/
size: function () {
var sizeInfo = {
const sizeInfo = {
body: 0,
header: 0,
total: 0
},
contentLength = this.headers.get(CONTENT_LENGTH);

contentEncoding = this.headers.get(CONTENT_ENCODING),
contentLength = this.headers.get(CONTENT_LENGTH),
isCompressed = false,
byteLength;

// if server sent encoded data, we should first try deriving length from headers
if (_.isString(contentEncoding)) {
// desensitise case of content encoding
contentEncoding = contentEncoding.toLowerCase();
// eslint-disable-next-line lodash/prefer-includes
isCompressed = (contentEncoding.indexOf('gzip') > -1) || (contentEncoding.indexOf('deflate') > -1);
// Set body size from downloadedBytes if available
if (util.isNumeric(this.downloadedBytes)) {
sizeInfo.body = this.downloadedBytes;
}

// if 'Content-Length' header is present and encoding is of type gzip/deflate, we take body as declared by
// server. else we need to compute the same.
if (contentLength && isCompressed && util.isNumeric(contentLength)) {
// Rely on content-length header
else if (contentLength && util.isNumeric(contentLength)) {
sizeInfo.body = _.parseInt(contentLength, 10);
}
// if there is a stream defined which looks like buffer, use it's data and move on
else if (this.stream) {
byteLength = this.stream.byteLength;
sizeInfo.body = util.isNumeric(byteLength) ? byteLength :
/* istanbul ignore next */
0;
// Fall back to stream if available
else if (this.stream && util.isNumeric(this.stream.byteLength)) {
sizeInfo.body = this.stream.byteLength;
}
// otherwise, if body is defined, we try get the true length of the body
// Or, calculate size from body string
else if (!_.isNil(this.body)) {
sizeInfo.body = supportsBuffer ? Buffer.byteLength(this.body.toString()) :
sizeInfo.body = supportsBuffer ?
Buffer.byteLength(this.body.toString()) :
/* istanbul ignore next */
this.body.toString().length;
}

// size of header is added
// Header size is calculated as per the HTTP message format
// https://tools.ietf.org/html/rfc7230#section-3
// HTTP-message = start-line (request-line / status-line)
// *( header-field CRLF )
// CRLF
// [ message-body ]
// status-line = HTTP-version SP status-code SP reason-phrase CRLF
sizeInfo.header = (HTTP_X_X + SP + this.code + SP + this.reason() + CRLF + CRLF).length +
this.headers.contentSize();
sizeInfo.header = (
HTTP_X_X + SP + this.code + SP + this.reason() + CRLF + CRLF
).length + this.headers.contentSize();

// compute the approximate total body size by adding size of header and body
// Compute the approximate total body size by adding size of header and body
sizeInfo.total = (sizeInfo.body || 0) + (sizeInfo.header);

return sizeInfo;
Expand Down
25 changes: 17 additions & 8 deletions lib/collection/variable-scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var _ = require('../util').lodash,
* @typedef VariableScope.definition
* @property {String} [id] ID of the scope
* @property {String} [name] A name of the scope
* @property {String} [prefix] A prefix to be used for variable names in this scope
* @property {Array.<Variable.definition>} [values] A list of variables defined in an array in form of `{name:String,
* value:String}`
*
Expand Down Expand Up @@ -111,6 +112,10 @@ _.inherit((
if (mutations) {
this.mutations = new MutationTracker(mutations);
}

if (definition && definition.prefix) {
this.prefix = definition.prefix;
}
}), Property);

/**
Expand Down Expand Up @@ -176,15 +181,16 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {
* false otherwise
*/
has: function (key) {
var variable = this.values.oneNormalizedVariable(key),
const _key = (this.prefix || '') + key;
var variable = this.values.oneNormalizedVariable(_key),
i,
ii;

// if a variable is disabled or does not exist in local scope,
// we search all the layers and return the first occurrence.
if ((!variable || variable.disabled === true) && this._layers) {
for (i = 0, ii = this._layers.length; i < ii; i++) {
variable = this._layers[i].oneNormalizedVariable(key);
variable = this._layers[i].oneNormalizedVariable(_key);
if (variable && variable.disabled !== true) { break; }
}
}
Expand All @@ -199,14 +205,15 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {
* @returns {*} The value of the specified variable across scopes.
*/
get: function (key) {
var variable = this.values.oneNormalizedVariable(key),
const _key = (this.prefix || '') + key;
var variable = this.values.oneNormalizedVariable(_key),
i,
ii;

// if a variable does not exist in local scope, we search all the layers and return the first occurrence.
if ((!variable || variable.disabled === true) && this._layers) {
for (i = 0, ii = this._layers.length; i < ii; i++) {
variable = this._layers[i].oneNormalizedVariable(key);
variable = this._layers[i].oneNormalizedVariable(_key);
if (variable && variable.disabled !== true) { break; }
}
}
Expand All @@ -222,10 +229,11 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {
* @param {Variable.types} [type] - Optionally, the value of the variable can be set to a type
*/
set: function (key, value, type) {
var variable = this.values.oneNormalizedVariable(key),
const _key = (this.prefix || '') + key;
var variable = this.values.oneNormalizedVariable(_key),

// create an object that will be used as setter
update = { key, value };
update = { key: _key, value: value };

_.isString(type) && (update.type = type);

Expand All @@ -248,11 +256,12 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {
* @param {String} key -
*/
unset: function (key) {
const _key = (this.prefix || '') + key;
var lastDisabledVariable;

this.values.remove(function (variable) {
// bail out if variable name didn't match
if (variable.key !== key) {
if (variable.key !== _key) {
return false;
}

Expand All @@ -269,7 +278,7 @@ _.assign(VariableScope.prototype, /** @lends VariableScope.prototype */ {

// restore the reference with the last disabled variable
if (lastDisabledVariable) {
this.values.reference[key] = lastDisabledVariable;
this.values.reference[_key] = lastDisabledVariable;
}

// track the change if mutation tracking is enabled
Expand Down
9 changes: 8 additions & 1 deletion lib/superstring/dynamic-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,14 @@ var faker = require('@faker-js/faker/locale/en'),

$randomAvatarImage: {
description: 'A random avatar image',
generator: faker.image.avatar
generator: () => {
// ref: https://github.com/faker-js/faker/blob/v8.4.1/src/modules/image/index.ts#L61
return faker.random.arrayElement([
// eslint-disable-next-line max-len
`https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/${faker.datatype.number(1249)}.jpg`,
`https://avatars.githubusercontent.com/u/${faker.datatype.number(100000000)}`
]);
}
},
$randomImageUrl: {
description: 'A URL for a random image',
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "postman-collection",
"version": "4.4.0",
"version": "4.4.1",
"description": "Enables developers to use a unified Postman Collection format Object across projects",
"author": "Postman Inc.",
"license": "Apache-2.0",
Expand Down
7 changes: 7 additions & 0 deletions test/unit/dynamic-variables.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,12 @@ describe('Dynamic variable', function () {
expect(directoryPath).to.not.be.undefined;
expect(directoryPath).to.not.be.null;
});

it('$randomAvatarImage returns a random avatar image', function () {
var avatarImage = dynamicVariables.$randomAvatarImage.generator();

expect(avatarImage).to.be.a('string')
.and.match(/^https:\/\/(avatars\.githubusercontent\.com|cloudflare-ipfs\.com)\/.+/);
});
});
});
48 changes: 47 additions & 1 deletion test/unit/response.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,20 @@ describe('Response', function () {
it('should handle blank responses correctly', function () {
var response = new Response();

expect(response.size()).to.eql({ body: 0, header: 32, total: 32 });
});

it('should handle string responses correctly', function () {
var response = new Response({ body: 'random' });

expect(response.size()).to.eql({ body: 6, header: 32, total: 38 });
});

it('should report downloaded size correctly', function () {
var response = new Response({ body: 'random', downloadedBytes: 6 });

expect(response.size()).to.eql({
body: 0, header: 32, total: 32
body: 6, header: 32, total: 38
});
});
});
Expand Down Expand Up @@ -477,6 +489,17 @@ describe('Response', function () {
expect(response.size().body).to.equal(20);
});

it('must match the content-length of the response if brotli encoded', function () {
var rawResponse = {
code: 200,
body: 'gzipped content xyzxyzxyzxyzxyzxyz',
header: 'Content-Encoding: br\nContent-Length: 20'
},
response = new Response(rawResponse);

expect(response.size().body).to.equal(20);
});

it('must use byteLength from buffer if provided', function () {
var rawResponse = {
code: 200,
Expand All @@ -487,6 +510,29 @@ describe('Response', function () {

expect(response.size().body).to.equal(14);
});

it('must use downloaded size if provided', function () {
var rawResponse = {
code: 200,
body: 'something nice',
header: 'Transfer-Encoding: chunked\nContent-Length: 20',
downloadedBytes: 10
},
response = new Response(rawResponse);

expect(response.size().body).to.equal(10);
});

it('must use content length of stream if header is provided and downloaded bytes is not present', function () {
var rawResponse = {
code: 200,
stream: Buffer.from('something nice'),
header: 'Transfer-Encoding: chunked\nContent-Length: 20\nContent-Encoding: gzip'
},
response = new Response(rawResponse);

expect(response.size().body).to.equal(20);
});
});

describe('toJSON', function () {
Expand Down
Loading

0 comments on commit b31a70e

Please sign in to comment.