Skip to content

Re-enable IDV outage feature spec 🤞 #8188

Merged
matthinz merged 7 commits intomainfrom
matthinz/100-percent-totally-fix-idv-outage-spec
Apr 13, 2023
Merged

Re-enable IDV outage feature spec 🤞 #8188
matthinz merged 7 commits intomainfrom
matthinz/100-percent-totally-fix-idv-outage-spec

Conversation

@matthinz
Copy link
Contributor

@matthinz matthinz commented Apr 12, 2023

🛠 Summary of changes

Background

A while back, we added a frontend analytics call that fires when the IdV "Welcome" screen is loaded. It turns out these frontend logging API calls can clash with Rails.application.reload_routes!, which is used heavily in the IdV outage feature spec. This clash would result in errors during test runs:

Got 0 failures and 2 other errors:

 1.1) Failure/Error: raise BrowserConsoleLogError.new(javascript_errors) if javascript_errors.present?
      BrowserConsoleLogError:
        Unexpected browser console logging:
        http://127.0.0.1:42645/api/logger - Failed to load resource: the server responded with a status of 500 (Internal Server Error)

...

 1.2) Failure/Error: status, headers, body = @app.call(env)
      ActionController::RoutingError:
        No route matches [POST] "/api/logger"

(See full example.)

Here's the order of events:

  1. Outage feature spec runs, and leaves the headless test browser on the Idv "welcome" screen at the end of the test.
  2. In an after handler, we call Rails.application.reload_routes! to clean up.
  3. While that call is processing, the browser we were using in step 1 (which is still open) makes a POST to /api/logger
  4. There is no route, since we haven't finished reloading them yet! The logging request returns a 500 response to the browser
  5. The browser logs an error to its console
  6. The test ends up failing for two reasons: because the logging request returned a 500 AND there was something unexpected in the browser's console.

To resolve the flakiness, we're adding a line to wait for any pending requests in the test browser to complete before reloading the Rails routes.

@matthinz matthinz force-pushed the matthinz/100-percent-totally-fix-idv-outage-spec branch from 19991bf to 3c9122c Compare April 12, 2023 16:36
Let our app hang out the partially-reloaded routes state while the frontend is just innocently making logging API calls.
(Frontend will not make /api/logger calls if analyticsEndpoint is not set)
Analytics calls can cause failures related to the user of `Rails.application.reload_routes!`
@matthinz matthinz force-pushed the matthinz/100-percent-totally-fix-idv-outage-spec branch from 3c9122c to 79afeef Compare April 12, 2023 17:47
@matthinz matthinz marked this pull request as ready for review April 12, 2023 19:24
@matthinz
Copy link
Contributor Author

See 58eb833 for how I attempted to reliably simulate the error condition locally.

{
'appName' => APP_NAME,
'analyticsEndpoint' => api_logger_path,
'analyticsEndpoint' => (api_logger_path if IdentityConfig.store.frontend_analytics_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.

If analyticsEndpoint is not set, trackEvent won't make any requests.

@matthinz
Copy link
Contributor Author

(I'm going to run CI for this branch several times to see if I can get another failure)

@matthinz matthinz requested review from a team and aduth April 12, 2023 19:40
@aduth
Copy link
Contributor

aduth commented Apr 12, 2023

Rather than disabling frontend analytics outright, I wonder if there might be some option to either...

  1. Wait for network requests to settle in the browser before reloading routes using Capybara built-in helpers
    • e.g. page.server.wait_for_pending_requests prior to Rails.application.reload_routes!
  2. Wait for network requests to settle in the browser before reloading routes using some client-side indicator
    • We don't really have anything user-facing to judge unfortunately
    • Could expose some indicator of pending fetch requests either as a DOM global or CSS class, which we monitor in the specs
      • e.g. page.evaluate_async_script('window._pendingTrackedEvents') (not sure I love this 😅 )
  3. A bit more extreme, but always worth reevaluating usefulness of our events: Do we still actively monitor the event being tracked, or could it be removed?

@aduth
Copy link
Contributor

aduth commented Apr 12, 2023

I'm also still curious if there's an option which avoids the need to reload the Rails route table, like if what we're defining in config/routes.rb could be handled in a controller instead (common before_action, etc).

event_disavowal_expiration_hours: 240
feature_idv_force_gpo_verification_enabled: false
feature_idv_hybrid_flow_enabled: true
frontend_analytics_enabled: true
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Is there a way to make the analytics disabled config only apply in the test environment to avoid affecting prod,
    or
  2. Is this something that could happen in prod and we want to protect against it there too

@matthinz
Copy link
Contributor Author

Wait for network requests to settle in the browser before reloading routes using Capybara built-in helpers
e.g. page.server.wait_for_pending_requests prior to Rails.application.reload_routes!

wait_for_pending_requests is a good suggestion, I will try that. trackEvent may be called after some delay, so I don't think it's guaranteed that the request would be in-flight at the time, but it might be good enough.

I'm also still curious if there's an option which avoids the need to reload the Rails route table, like if what we're defining in config/routes.rb could be handled in a controller instead (common before_action, etc).

Yeah, my main concern with this approach is it means new controllers in the IdV space need to remember to check to see if IdV is disabled before they do anything. We have a lot of controllers, and are adding more and more as we migrate away from the flow state machine. I guess it's not the end of the world, since a lot of these controllers have to remember to do a lot of other checks as well.

Rather than completely disabling analytics, just wait for any pending requests to complete before proceeding.
Copy link
Contributor

@zachmargolis zachmargolis left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@aduth aduth left a comment

Choose a reason for hiding this comment

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

Nice 👍

@matthinz
Copy link
Contributor Author

Thanks all, we've had 8 successive green runs of this branch in CI, so I'm going to merge.

@matthinz matthinz merged commit aadad47 into main Apr 13, 2023
@matthinz matthinz deleted the matthinz/100-percent-totally-fix-idv-outage-spec branch April 13, 2023 16:22
jc-gsa pushed a commit that referenced this pull request Apr 19, 2023
* Unskip my spec

* Make it more likely for the flakiness to occur

Let our app hang out the partially-reloaded routes state while the frontend is just innocently making logging API calls.

* Add config to enable/disable frontend analytics

(Frontend will not make /api/logger calls if analyticsEndpoint is not set)

* Selectively disable analytics for idv outage spec

Analytics calls can cause failures related to the user of `Rails.application.reload_routes!`

* [skip changelog]

* Remove temp code used to reliably trigger failure

* Wait for pending requests to complete before dismantling routing table

Rather than completely disabling analytics, just wait for any pending requests to complete before proceeding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants