Skip to content

feat: add callbackify() and callbackifyAll() methods#82

Merged
JustinBeckwith merged 12 commits intogoogleapis:masterfrom
AVaksman:callbackify
Feb 13, 2019
Merged

feat: add callbackify() and callbackifyAll() methods#82
JustinBeckwith merged 12 commits intogoogleapis:masterfrom
AVaksman:callbackify

Conversation

@AVaksman
Copy link
Contributor

@AVaksman AVaksman commented Feb 4, 2019

  • Tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs - please suggest how to edit README.md

@google-cloud/promisify

A simple utility for promisifying and callbackifying functions and classes.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Feb 4, 2019
src/index.ts Outdated
.then((res: []) => {
cb(null, ...res);
})
.catch((err: Error) => cb(err));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bug. The error handler should be passed as the second parameter of the then method. That prevents errors thrown in the callback method from triggering the catch clause, and double calling the callback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Fixed

src/index.ts Outdated
exports.callbackify(originalMethod, options);
}
});
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a newline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

});
});

it('should call the callback with error when promise rejects', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a "it should call the callback only a single time when the promise rejects" to test the error we caught above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test 'should call the callback only a single time when the promise resolves but callback throws an error', however skipping the test as of now as I am unable to catch the error thrown by the callback in the test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused. Why do we need to skip the test? I really think we need to have that enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the error that is thrown by the callback is crushing the test. I am not able to catch /intercept it.
I tried assert.throws, try=>catch block around func(callback), process.on('uncaughtException'), process.on('unhandledRejection').

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestions would be greatly appreciated.

Copy link
Contributor Author

@AVaksman AVaksman Feb 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the bug was only in case when promise resolves, but callback throws an error, then callback is called again with that error in the catch block.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so in that scenario it would be a user error, I misunderstood. I wonder if we would want to change our logic to look something like this

originalMethod
  .apply(context, arguments)
  // tslint:disable-next-line:no-any
  .then((res: any) => {
    res = Array.isArray(res) ? res : [res];
    cb(null, ...res);
  }, (err: Error) => cb(err))
  .catch(err => process.emitWarning(err));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fill that if error is thrown by the user's function, it should be propagated and the process should crush, no?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the native callbackify doesn't do anything special with the error either. So I don't think we shouldn't concern ourselves with user errors like that.

Copy link
Contributor Author

@AVaksman AVaksman Feb 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caught that error 👍
Test is enabled.

@JustinBeckwith JustinBeckwith changed the title Add callbackify() and callbackifyAll() feat: add callbackify() and callbackifyAll() methods Feb 6, 2019
@AVaksman
Copy link
Contributor Author

AVaksman commented Feb 6, 2019

Added changes for scenarios when promise returns not array.

src/index.ts Outdated
const originalMethod = Class.prototype[methodName];
if (!originalMethod.callbackified_) {
Class.prototype[methodName] =
exports.callbackify(originalMethod, options);
Copy link
Contributor

@callmehiphop callmehiphop Feb 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like callbackify actually accepts any options

});
});

it('should call the callback with error when promise rejects', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of a separate test, you could modify the current test to look like this

const error = new Error('err');
func = util.callbackify(async () => {
  throw error;
});
func((err: Error) => {
  assert.strictEqual(err, error);
  done();
});

If done gets called multiple times the test will fail, so I think that would satisfy @JustinBeckwith's ask (maybe?)

@yoshi-automation yoshi-automation added the 🚨 This issue needs some love. label Feb 11, 2019
@codecov
Copy link

codecov bot commented Feb 13, 2019

Codecov Report

Merging #82 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master    #82   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           1      1           
  Lines          34     54   +20     
  Branches        5      8    +3     
=====================================
+ Hits           34     54   +20
Impacted Files Coverage Δ
src/index.ts 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3569647...64bf092. Read the comment docs.

@JustinBeckwith JustinBeckwith merged commit c6127bb into googleapis:master Feb 13, 2019
@yoshi-automation yoshi-automation removed the 🚨 This issue needs some love. label Apr 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla: yes This human has signed the Contributor License Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants