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

Tag oidc unit tests #2706

Merged
merged 1 commit into from
Feb 6, 2023
Merged

Tag oidc unit tests #2706

merged 1 commit into from
Feb 6, 2023

Conversation

codihuston
Copy link
Contributor

@codihuston codihuston commented Jan 23, 2023

To run the tests, start conjur dev environment:

cd git/conjur/dev
./start

Exec into the conjur container and run the tests:

docker-compose exec conjur bash

rspec -f d --color --dry-run --tag @type:unit

Desired Outcome

First round of unittags to rspec tests for oidc pkce and v2.

See the above commands for visualizing which tests have been tagged.

Implemented Changes

Describe how the desired outcome above has been achieved with this PR. In
particular, consider:

  • What's changed? Why were these changes made?

    • Tests for the authn-oidc strategies were previously not being run due to a typo in the file name _rspec.rb vs _spec.rb
    • authn-oidc tests have been tagged as described above
  • How should the reviewer approach this PR, especially if manual tests are required?

  • Are there relevant screenshots you can add to the PR description?

Connected Issue/Story

CyberArk internal issue ID: [CNJR-178]

Definition of Done

At least 1 todo must be completed in the sections below for the PR to be
merged.

Changelog

  • The CHANGELOG has been updated, or
  • This PR does not include user-facing changes and doesn't require a
    CHANGELOG update

Test coverage

  • This PR includes new unit and integration tests to go with the code
    changes, or
  • The changes in this PR do not require tests

Documentation

  • Docs (e.g. READMEs) were updated in this PR
  • A follow-up issue to update official docs has been filed here: [insert issue ID]
  • This PR does not require updating any documentation

Behavior

  • This PR changes product behavior and has been reviewed by a PO, or
  • These changes are part of a larger initiative that will be reviewed later, or
  • No behavior was changed with this PR

Security

  • Security architect has reviewed the changes in this PR,
  • These changes are part of a larger initiative with a separate security review, or
  • There are no security aspects to these changes

@codihuston codihuston changed the title Label oidc-pkce unit tests Label oidc pkce unit tests Jan 23, 2023
Copy link
Contributor Author

@codihuston codihuston left a comment

Choose a reason for hiding this comment

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

@adamouamani What do you think? Do tests that leverage a DataObject in conjunction with another module always constitute as an integration test? https://github.com/cyberark/conjur/pull/2706/files#diff-cf99fb4eccb8c5d8aaeb05adb7d5063d743d31d8bd623cc38f878b318620bd60R41

Copy link
Contributor Author

@codihuston codihuston left a comment

Choose a reason for hiding this comment

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

@adamouamani Here's another example of a test that uses a mock and a data object. Should it be considered a unit test or an integration test? https://github.com/cyberark/conjur/pull/2706/files#diff-ecc086dac9693ffbe9eba71f440388e8e466250eae64880dadaef7f13f37ddf1R110

@codihuston
Copy link
Contributor Author

Hi @jvanderhoof and @adamouamani,

Currently, we have questions on the following tests (currently tagged with :review => true in this PR). I'll outline some of the ones I have questions about below, and a question(s) for each.

  1. spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_spec.rb

    These tests leverage a Authentication::AuthnOidc::PkceSupportFeature::Strategy
    instance that is instantiated with a Authentication::AuthnOidc::PkceSupportFeature::DataObjects::Authenticator
    and doubles of the Authentication::AuthnOidc::PkceSupportFeature::Client.

    Any tests that use doubles/mocks/stubs/etc. has been determined to be a
    unit test, however this test uses a combination of doubles and an unmocked
    DataObject that appears to be the system under test
    (the state being tested in the DataObject).

    Since the thing being tested here is the return value of the underlying
    data object (through a call to the strategy), do we think this would this qualify it as
    an integration test?

@codihuston
Copy link
Contributor Author

Here's another one @jvanderhoof and @adamouamani,

  1. spec/app/domain/authentication/authn-oidc/pkce_support_feature/views/providor_context_spec.rb

    Here, we are testing a Authentication::AuthnOidc::PkceSupportFeature::Views::ProviderContext,
    which is instantiated with doubled clients, but what is being tested
    is the output of the provider_context.call method with unmocked
    Authentication::AuthnOidc::PkceSupportFeature::DataObjects.

    Since this appears to be testing this method's public interface with an
    unmocked input, I'm thinking this would be more integration over it
    being a unit test. WDYT?

    In the same file, the test for when authenticator discovery endpoint is unreachable appears to be more unit than
    integration because of the client's discovery_information being mocked
    out, but the call is still using the same unmocked authenticators.

    I'm trying to identify if what we should qualify integration tests based
    on whether or not the public interfaces are being tested, or the output
    itself, or both?

@codihuston
Copy link
Contributor Author

And another, @jvanderhoof, @adamouamani

  1. spec/app/domain/authentication/authn-oidc/pkce_support_feature/client_spec.rb

    I didn't mark this one with the review tag, but I see the use of both
    an authenticator and a client here. All of these tests look very unit,
    since they are testing individual methods, but the fact that the test is
    driven with a client that was instantiated with an unmocked authenticator
    might be enough to warrant them being integration tests. WDYT?

@adamouamani
Copy link

@codihuston - you have highlighted a lot of great cases that we can review with @jvanderhoof and document and create a pattern we can apply for other tests!

@jvanderhoof
Copy link
Contributor

@codihuston, (cc. @adamouamani), my personal opinion is that the first two examples:

are both appropriate unit tests because they take advantage of dependency injection as alternative to excessive mocking.

The Authentication::AuthnOidc::V2::DataObject is a stateless class that holds common information (specifically, all the information that is stored in Conjur related to an OIDC Authenticator). It's intended as a glorified Struct (this allows us to keep the details of a particular authenticator outside the scope of the particular authentication actions).

We don't need to mock the data object, because it's essentially a mock already (but it's the real object). For this reason, I'd consider the first two examples appropriate to call unit tests on.

@jvanderhoof
Copy link
Contributor

@codihuston, (cc. @adamouamani). I do want to state that mocking must be understood as a code smell, albeit one which is necessary in any software which takes in external data (essentially all of them). Mocking is highly problematic as it requires two definitions of a single interface: one for the class being mocked, the second, the mock of the class. Mocks are necessary when we deal with outside data (loading from database, API requests, user input, etc.). Dependency inject simplifies the process of mocking (which is why we push this pattern), but any mocking is a poor substitute for the actual dependent object.

@jvanderhoof
Copy link
Contributor

@codihuston, (cc. @adamouamani), I'd also classify the third item (spec/app/domain/authentication/authn-oidc/pkce_support_feature/client_spec.rb) as being appropriate as a unit test give the same argument as above.

I do think it's very important to understand the risk in the mocked OIDC client in this test. We're using VCR to mock the OIDC client wrapped in this class. The danger in our mock is that if the upstream OIDC API changes, our tests will continue to pass. This is why it's important to have a few E2E tests over all this. Unit tests can only identify that when given a particular set of pre-defined inputs, the method returns an expected output.

@jvanderhoof
Copy link
Contributor

@codihuston, @adamouamani, I really should have started with the fact that I really like this approach! It's simple, natively part of RSpec, and gives more context to a particular test. Well done!!!!

@adamouamani
Copy link

@codihuston @jvanderhoof This is a fantastic start! I'll update the confluence page with approach, feedback from Jason and examples to help people determine test type when evaluating additional modules in the future.

https://ca-il-confluence.il.cyber-ark.com/display/rndp/Test+Level+Review+Patterns

@codihuston
Copy link
Contributor Author

@adamouamani Awesome!

We've only come out of this effort with identifying unit tests--should we consider merging this PR as is, or should we shelf it for the time being until we tag and review some true integration tests? If so, let me know and I'll mark this ready for review / undraft it.

Note: no changes have been added in the pipeline to leverage this tag (I believe we weren't planning on doing this anytime soon).

@adamouamani
Copy link

adamouamani commented Feb 2, 2023

@codihuston I would merge this and finish any remaining updates to docs on confluence if anything that I missed. We can then create a follow-up story to continue this effort for another section/module with more integration tests examples

@codihuston
Copy link
Contributor Author

codihuston commented Feb 2, 2023

Hey @jvanderhoof , this PR contains a commit that adds tests that were being ignored by rspec due to some files not following the *_spec.rb naming scheme (see commit details).

It looks like one of the oidc pkce strategy tests were failing when expecting a specific error code to be thrown, but it turns out a different error code was being thrown instead. I updated the test to account for that, but can you confirm that this is the intended behavior please? Thanks!

Failures:

  1) Authentication::AuthnOidc::PkceSupportFeature::Strategy #callback when required parameters are missing when code_verifier is missing raises a `MissingRequestParam` error
     Failure/Error:
       expect { strategy.callback(nonce: 'nonce', code: 'code') }
         .to raise_error(Errors::Authentication::RequestBody::MissingRequestParam)
     
       expected Errors::Authentication::RequestBody::MissingRequestParam, got #<Errors::Authentication::AuthnOidc::IdTokenClaimNotFoundOrEmpty: CONJ00013E Claim '' not found or empty in ID token. This claim is defined in the id-token-user-property variable.> with backtrace:
         # ./app/domain/authentication/authn_oidc/pkce_support_feature/strategy.rb:30:in `callback'
         # ./spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_spec.rb:73:in `block (6 levels) in <top (required)>'
         # ./spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_spec.rb:73:in `block (5 levels) in <top (required)>'
         # ./spec/spec_helper.rb:65:in `block (3 levels) in <top (required)>'
         # ./spec/spec_helper.rb:65:in `block (2 levels) in <top (required)>'
         # ./spec/spec_helper.rb:57:in `block (3 levels) in <top (required)>'
         # ./spec/spec_helper.rb:56:in `block (2 levels) in <top (required)>'
     # ./spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_spec.rb:73:in `block (5 levels) in <top (required)>'
     # ./spec/spec_helper.rb:65:in `block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:65:in `block (2 levels) in <top (required)>'
     # ./spec/spec_helper.rb:57:in `block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:56:in `block (2 levels) in <top (required)>'

@codihuston codihuston changed the title Label oidc pkce unit tests Add missing oidc strategy rspec tests and label oidc pkce unit tests Feb 2, 2023
@codihuston codihuston changed the title Add missing oidc strategy rspec tests and label oidc pkce unit tests Add missing oidc strategy rspec tests and label oidc unit tests Feb 2, 2023
@jvanderhoof
Copy link
Contributor

Hey @jvanderhoof , this PR contains a commit that adds tests that were being ignored by rspec due to some files not following the *_spec.rb naming scheme (see commit details).

It looks like one of the oidc pkce strategy tests were failing when expecting a specific error code to be thrown, but it turns out a different error code was being thrown instead. I updated the test to account for that, but can you confirm that this is the intended behavior please? Thanks!

Failures:

  1) Authentication::AuthnOidc::PkceSupportFeature::Strategy #callback when required parameters are missing when code_verifier is missing raises a `MissingRequestParam` error
     Failure/Error:
       expect { strategy.callback(nonce: 'nonce', code: 'code') }
         .to raise_error(Errors::Authentication::RequestBody::MissingRequestParam)
     
       expected Errors::Authentication::RequestBody::MissingRequestParam, got #<Errors::Authentication::AuthnOidc::IdTokenClaimNotFoundOrEmpty: CONJ00013E Claim '' not found or empty in ID token. This claim is defined in the id-token-user-property variable.> with backtrace:
         # ./app/domain/authentication/authn_oidc/pkce_support_feature/strategy.rb:30:in `callback'
         # ./spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_spec.rb:73:in `block (6 levels) in <top (required)>'
         # ./spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_spec.rb:73:in `block (5 levels) in <top (required)>'
         # ./spec/spec_helper.rb:65:in `block (3 levels) in <top (required)>'
         # ./spec/spec_helper.rb:65:in `block (2 levels) in <top (required)>'
         # ./spec/spec_helper.rb:57:in `block (3 levels) in <top (required)>'
         # ./spec/spec_helper.rb:56:in `block (2 levels) in <top (required)>'
     # ./spec/app/domain/authentication/authn-oidc/pkce_support_feature/strategy_spec.rb:73:in `block (5 levels) in <top (required)>'
     # ./spec/spec_helper.rb:65:in `block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:65:in `block (2 levels) in <top (required)>'
     # ./spec/spec_helper.rb:57:in `block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:56:in `block (2 levels) in <top (required)>'

Good catch. I just found and fixed this issue here: #2713.

You can display the tagged the tests with the following command(s). Drop the `--dry-run` to actually run the tests:

```bash
rspec -f d --color --dry-run --tag @type:unit
```
@codihuston codihuston marked this pull request as ready for review February 6, 2023 17:47
@codihuston codihuston requested a review from a team as a code owner February 6, 2023 17:47
@codihuston codihuston changed the title Add missing oidc strategy rspec tests and label oidc unit tests Tag oidc unit tests Feb 6, 2023
@codeclimate
Copy link

codeclimate bot commented Feb 6, 2023

Code Climate has analyzed commit f621ed6 and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 100.0% (50% is the threshold).

This pull request will bring the total coverage in the repository to 90.0% (-1.5% change).

View more on Code Climate.

@codihuston
Copy link
Contributor Author

Thanks Jason! I dropped those commits from this PR--it only contains the labeling effort then. Appreciate it!

Copy link

@adamouamani adamouamani left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks @codihuston

@codihuston codihuston merged commit 38d7ecc into master Feb 6, 2023
@codihuston codihuston deleted the test-tagging branch February 6, 2023 19:46
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