Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate C++ coverage reports too! #2314

Closed
wants to merge 25 commits into from

Conversation

cinderblock
Copy link

@cinderblock cinderblock commented Sep 6, 2021

Coverage tests are wonderful.

This PR adds support for running coverage tests on this package's C++ sources alongside JavaScript's!

Before After    Change
Covered Lines 1 019 1 397 + 37%
Uncovered Lines 96 1 219 + 1 170%
Tracked Lines 1 115 2 616 + 135%
Coverage 91% 53% ⚠️- 42%
Sunburst Sunburst Before Update: codecov broke this image!
Sunburst After

Before

Before C++ coverage tracking

After

Update: codecov broke this image!

After C++ coverage tracking

Platforms & Issues

Initially, I'd like to get coverage reports working on Linux and macOS. Windows looks like it will be a little more involved and could be added after initial merging of this PR.

  • Linux
    • Test
  • macOS
    • Install missing libgcov
    • Link to libgcov correctly
    • Test
  • Windows
    • MSBuild.exe's gcov equivalent: OpenCppCoverage
    • Convert to something codedev can read - cobertura✔️
    • Write package.json#scripts and update workflows

macOS

Thoughts on the "correct" way to make coverage reports on macOS would be appreciated. While it works, it could probably be improved.

On Linux, apt install -y gcc also installs libgcov.a (via dependency libgcc-9-dev:amd64: /usr/lib/gcc/x86_64-linux-gnu/9/libgcov.a). I've tried installing gcovr and gcc with brew to see if they provide the missing libraries to no avail.

A CI test shows that libgcov.a is available on the system. So maybe it's just an LD_LIBRARY_PATH setting that needs to be set in bindings.gyp?

> find /usr -name 'libgcov.*'
/usr/local/lib/gcc/9/gcc/x86_64-apple-darwin19/9.4.0/libgcov.a
/usr/local/Cellar/gcc@10/10.3.0/lib/gcc/10/gcc/x86_64-apple-darwin19/10.3.0/libgcov.a
/usr/local/Cellar/gcc/11.2.0/lib/gcc/11/gcc/x86_64-apple-darwin19/11.2.0/libgcov.a
/usr/local/Cellar/gcc@9/9.4.0/lib/gcc/9/gcc/x86_64-apple-darwin19/9.4.0/libgcov.a

Note: the above was run after brew install gcc, which probably isn't necessary and probably added a few of these.

Update 1

Adding -L /usr/local/lib/gcc/9/gcc/x86_64-apple-darwin19/9.4.0 to the linker seems to have gotten it to compile on macOS, but when I run it, no gcda files seem to be generated... https://github.com/cinderblock/node-serialport/runs/3528420934?check_suite_focus=true

Update 2

Found a minimally working setup. Some improvements could probably be made.

                      'xcode_settings': {
                        'GCC_GENERATE_TEST_COVERAGE_FILES': ['YES'],
                        'GCC_INSTRUMENT_PROGRAM_FLOW_ARCS': ['YES'],
                        'OTHER_CFLAGS+': [
                          '-fprofile-arcs -ftest-coverage',
                        ],
                        'OTHER_LDFLAGS+': [
                          '-fprofile-arcs -ftest-coverage',
                          # There has to be a better way to do this...
                          '-L/usr/local/lib/gcc/9/gcc/x86_64-apple-darwin19/9.4.0',
                        ],
                      },

Windows

As for coverage tests on Windows, I'm not sure where to start. I'm sure there is an equivalent to gcc's gcov but I haven't had the time to look yet.

Update 1

Some possibly helpful tools/links:

Update 2

CPPCoverage is running, but not generating coverage information yet for some reason.

npm run rebuild -- -- --debug
# https://github.com/atlaste/CPPCoverage/raw/c4b5ed0e39007295ea98e120b7f4b127681fe998/CoverageExt/Resources/Coverage-x64.exe
.\Coverage-x64.exe -p . -- npm.cmd test

Update 3

OpenCppCoverage works!

npm i -D npm
npm run rebuild -- -- --debug
OpenCppCoverage.exe --modules "*.node" --source "packages\bindings\src\*" -- node test.js

Time to format the data in a way that codecov likes and then package this up into the branch!

@cinderblock cinderblock changed the title WIP - Generate C++ coverage reports too! Generate C++ coverage reports too! Sep 7, 2021
@@ -9,7 +9,10 @@
"license": "MIT",
"scripts": {
"rebuild": "lerna run --stream rebuild",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
Copy link
Author

Choose a reason for hiding this comment

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

nyc report --reporter=text-lcov > coverage.lcov is redundant with nyc --reporter lcovonly mocha (npm test).

@cinderblock
Copy link
Author

@reconbot any thoughts?

@@ -1,19 +1,21 @@
name: Test / Lint
on:
push:
pull_request:
Copy link
Author

Choose a reason for hiding this comment

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

The test-merge.yml workflow was basically identical to this one. I thought might as well de-dupe. Happy to not do this if you prefer.

Copy link
Member

Choose a reason for hiding this comment

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

yeah lets merge that in another pr and rebase this one

test:
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
Copy link
Author

Choose a reason for hiding this comment

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

I say might as well let other tests finish even if there is an error. Cover more systems faster.

{
'cflags+': ['--coverage'],
'link_settings': {'libraries+': ['-lgcov']},
'xcode_settings': {
Copy link
Author

Choose a reason for hiding this comment

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

I've seen others put macOS conditions around xcode_settings but that doesn't seem to be necessary as far as I've seen.

Comment on lines 77 to 81
'GCC_GENERATE_TEST_COVERAGE_FILES': ['YES'],
'GCC_INSTRUMENT_PROGRAM_FLOW_ARCS': ['YES'],
'OTHER_CFLAGS+': ['-fprofile-arcs -ftest-coverage'],
'OTHER_LDFLAGS+': [
'-fprofile-arcs -ftest-coverage',
Copy link
Author

@cinderblock cinderblock Sep 12, 2021

Choose a reason for hiding this comment

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

I've tested without each setting individually. Theses all seem to be necessary instead of the one --coverage GCC flag.

Way to think different Xcode 😉

@reconbot
Copy link
Member

I like it! I haven't had time to do a proper review

@cinderblock
Copy link
Author

Well, it all seems to work! I bet some things could be cleaned up a bit but it all seems to be there.

@cinderblock
Copy link
Author

@reconbot what are the steps for including this? I suspect this will be helpful for #2305 as well.

@GazHank
Copy link
Contributor

GazHank commented Oct 6, 2021

Hi @cinderblock I agree and am super keen to expand the test coverage and visibility.

Sorry, other than a cursory glance at the coverage report output, I haven't had chance to take a closer look yet. I was a little surprised that the platform specific files showed different levels of coverage for similar functionality, but I guess some of this could be down to the different tooling per platform.

Overall I don't think this change should present much in the way of risk to any production users, and will help dev and test in the long term.

I know @reconbot is very busy at the moment, but am sure he will help to get this included when he gets some time.

@cinderblock
Copy link
Author

No worries. I know how life can be. Just don't want this to fall by the wayside.

I would relish some thoughts on the new package.json#scripts. Getting native code coverage reports on Windows is significantly different than macOS/Linux. It might be nice to have a single script to run that does the right thing no matter the platform. However this very quickly would want to be some extra node script that effectively replaces what I've achieved already. I'm all for having as much code as possible in one language but this seems like diminishing returns.


Of note, I haven't tried running these tests with an Arduino (or equivalent) attached. That would almost certainly significantly affect coverage for various platforms.

It might be worth figuring out how to regularly run these tests with either a virtual (loopback) COM port (that's all the Arduino test code does anyway) or setting up a custom action runner just for this repo that has the dedicated hardware attached so that anyone can more easily run the full suite of tests.


Related, we might want to make the codecov token a proper secret. As it stands, anyone can add a report to codecov.

Notice I accidentally did this running tests on my personal machine:

image

@reconbot
Copy link
Member

reconbot commented Oct 6, 2021

It might be worth figuring out how to regularly run these tests with either a virtual (loopback) COM port (that's all the Arduino test code does anyway) or setting up a custom action runner just for this repo that has the dedicated hardware attached so that anyone can more easily run the full suite of tests.

This has been my dream for years, we just need a loopback serialport.

package.json Outdated
@@ -40,6 +46,7 @@
"lerna": "^3.22.1",
"mocha": "^8.3.0",
"node-abi": "^3.0.0",
"npm": "^7.23.0",
Copy link
Member

Choose a reason for hiding this comment

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

why?

Copy link
Author

Choose a reason for hiding this comment

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

Good question.This was because both of the Windows coverage tools I chose to use could not find npm.cmd on the path (or something like that).

I just started a branch to try without this explicitly: https://github.com/cinderblock/node-serialport/actions/runs/1314282300

You can see the Windows builds failing because:

[...]
Error: Cannot find module 'D:\a\node-serialport\node-serialport\node_modules\npm\bin\npm-cli.js'
[...]

We could probably solve this problem in an alternate way, but my initial goal was to get it working.

Copy link
Author

@cinderblock cinderblock Oct 7, 2021

Choose a reason for hiding this comment

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

One simple alternative would be to add a specific npm install npm@7 step to the Windows workflows.

It works: https://github.com/cinderblock/node-serialport/actions/runs/1314333987

Copy link
Author

@cinderblock cinderblock Oct 9, 2021

Choose a reason for hiding this comment

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

@reconbot would you prefer to not soil the devDependencies? I can merge the npm i npm step into this PR which fixes this problem. Just means that anyone that wants to run coverage tests on their Windows machines will need to install npm locally. That being said, all platforms need some extra tools installed for this all to work, so maybe this isn't a big deal.

Alternatively, I bet someone could fix the underlying problem with the Windows paths if they were feeling more ambitious than I am at the moment.

@cinderblock
Copy link
Author

cinderblock commented Nov 26, 2021

Some macOS updates broke the gcov linking that was previously done with a hard coded path. I put in a find based search for the needed libgcov.a file that I expect will be more reliable but still think a better solution could be found.

I also decided to include a change that splits the different OS tests up into fully separate jobs. This makes it a little more readable when following the jobs. We just need to remember to edit all 3 jobs for any test changes. Ultimately, I made this change because of loopback testing plans (#2327) and the assumption that each OS would have even more differences in their respective test environments.

@cinderblock cinderblock mentioned this pull request Dec 4, 2021
@reconbot
Copy link
Member

reconbot commented Jan 7, 2022

@cinderblock I've definitely messed up your pr with the introduction of #2384 I want to apologize for that. But I do hope it will a bunch easier to maintain the bindings in a separate repository. I'm game for helping move all this over there.

@cinderblock
Copy link
Author

This makes sense! I think I'll have time to take a look at moving things over sometime this weekend.

Does this have implications for my other pending PRs too?

@reconbot
Copy link
Member

reconbot commented Mar 5, 2022

This need to be moved to https://github.com/serialport/bindings-cpp

@reconbot reconbot closed this Mar 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants