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

[WIP] Add integration Rails environment #20350

Closed
wants to merge 11 commits into from

Conversation

NickLaMuro
Copy link
Member

@NickLaMuro NickLaMuro commented Jul 10, 2020

The intent of this is to have a separate environment that can be used for integration tests, and can have specific functionality to it that is propose driven to that environment, instead of trying to shoehorn it into test or development environments.

By default, the environment mirrors production for the most part, but the $CYPRESS_DEV var is designed to be able to toggle portions of the configuration to be more "dev-like" (for example: no compressing assets so TDD can be done while developing integration specs).

There is also included rake tasks to simplify spinning up a server for cypress or other integration style tests to run against and other tasks like seeding the database and compiling assets for the environment.

TODO

Most likely in separate PRs:

  • Add "integration only" routes for factory_bot, "database cleaning", and seeding
  • Login helpers

Links

@NickLaMuro NickLaMuro changed the title Add integration Rails environment [WIP] Add integration Rails environment Jul 10, 2020
@NickLaMuro NickLaMuro changed the title [WIP] Add integration Rails environment Add integration Rails environment Jul 10, 2020
@NickLaMuro
Copy link
Member Author

@miq-bot add-reviewer @jvlcek
@miq-bot add-reviewer @himdel
@miq-bot assign @jrafanie

@NickLaMuro
Copy link
Member Author

NickLaMuro commented Jul 10, 2020

Gemfile

Invalid rule for the Gemfile. We do this all over the place to align elements of the Hash. This file should probably be an exception in our config for this rule.

lib/tasks/integration.rake

Unsure how I want to handle this yet, so this one is valid (probably the only one). Mostly trying to decide if any form of a response is good enough for the ping, of if we do want to validate if the body is "pong" (if it is not, then we probably need to raise something else and rescue that error as well.)

Incorrect catch here. Using "touch" from FileUtils, not from Rails.

Not sure if I agree with this one. Just makes the code simpler to digest.

While a "valid catch", I am using this to line up command line arguments, so I think it is better in this form, and more readable.

lib/tasks/integration.rake Outdated Show resolved Hide resolved
@Fryguy
Copy link
Member

Fryguy commented Jul 13, 2020

Only concern I have is there are a number of places in the code where we check the Rails environment (and probably in a number of ways too (e.g. instead of Rails.env.production? maybe we do Rails.env == "production" or ENV['RAILS_ENV'] == 'production'). We probably need to audit all of those to see ifeach of those checks needs to also include intergration or not, particularly because this is a sort-of hybrid environment.

desc "With a UI worker for integration tests"
task :with_ui => :setup do
ui_config = "ui: env PORT=$PORT ruby #{RUN_SINGLE_WORKER_BIN} MiqUiWorker\n"
File.write(INTEGRATION_PROCFILE, ui_config, :mode => "a")
Copy link
Member

Choose a reason for hiding this comment

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

Instead of generating this on the fly, can we just have a Procfile.integration file committed, and then in setup it's just copied to the right place?

Copy link
Member

Choose a reason for hiding this comment

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

Also this appends to a file, but the file is empty to start with, so I'm not sure what this is doing?

Copy link
Member Author

@NickLaMuro NickLaMuro Jul 13, 2020

Choose a reason for hiding this comment

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

Yeah, probably. My thoughts were that eventually we might need a generic worker at a minimum to test certain things in the app, and so I figured that being able to make this configurable for a local user might be ideal.

But, again, YAGNI and all that, so I am not opposed to just doing a Procfile.integration for now.

Update: Will look into how to do this later today, but want to push the other simpler changes that I have before diving into re-writing this section.

Copy link
Member Author

Choose a reason for hiding this comment

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

"Sorta solved" this with the last couple of commits. I am 50/50 on the last commit, and might still make a few tweaks to handling some of the file dependencies since I realize they might be better served as file/dir tasks instead of in a .setup method.

Regardless, it is still "generated" a bit because I want to make sure the run_single_worker.rb path is calculated and not hard coded, so using ERB for that bit at a minimum.


15.times do
ui_ready = Net::HTTP.get_response(URI(ui_endpoint)).body
break if ui_ready == "pong"
Copy link
Member

Choose a reason for hiding this comment

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

Would it be simpler to just to a HEAD request and check for 200? I guess it's not really much of a difference, but less is more.

Copy link
Member Author

Choose a reason for hiding this comment

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

I would still want to hit against the /api/ping route since it doesn't even load our base controller:

https://github.com/ManageIQ/manageiq-api/blob/fdc94421077ecedfc509c413b17a566d07dbebd0/app/controllers/api/ping_controller.rb#L1-L7

And so that makes the request much cheaper, where a HEAD / ends up actually making some database calls. I don't know if you could do a HEAD /api/ping, but seems like it would minimal difference if anything.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I mean HEAD to /api/ping as opposed to GET /api/ping, but yeah it's going to be a pretty minimal difference. My only thought was if for some reason we change the pong to something else, then this creates an unnecessary coupling, that a HEAD could avoid.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fair enough. I can do a quick test to see if we would have to make an addition to that controller to do this. I honestly don't know the answer off hand, or what it would look like for the code in Ruby (I think .get_response is a special method for net/http at least).

Copy link
Member Author

Choose a reason for hiding this comment

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

Switched to HEAD in some refactoring commits, and it works. The response.code comes back as a string, which I wasn't expecting, but besides that, it is probably a better approach. Requires setting up a http object ahead of time since there isn't a class method for it, so one extra line of code was required.

lib/tasks/integration.rake Outdated Show resolved Hide resolved
Rake::Task["assets:clobber"].invoke
Rake::Task["assets:precompile"].invoke
Rake::Task["#{app_prefix}assets:clobber"].invoke
Rake::Task["#{app_prefix}assets:precompile"].invoke
Copy link
Member

@Fryguy Fryguy Jul 13, 2020

Choose a reason for hiding this comment

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

I'm concerned this will break callers of this that might live outside of this app (like from UI classic), though perhaps this is fixing that?

Copy link
Member Author

@NickLaMuro NickLaMuro Jul 13, 2020

Choose a reason for hiding this comment

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

... though perhaps this is fixing that?

It is, and we actually use this in other places as well, and I just ripped it off (I used the same app_prefix variable name, so you should be able to grep in lib/tasks to find it).

Effectively, if this doesn't need a "app:" prefix, it will just be blank, and call the default task. But when running from manageiq-ui-classic, these tasks need to have the "app_prefix" for them to work.

That said, I was thinking that it might make sense to have a generic helper function for this, but figured it wasn't worth starting on that in the PR, though I could still be convinced if we think it makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

I actually found a way to fix a part of this with Rails itself, but never got around to blasting it out...I'd like to pair on it if you have time at some point. However, I think your prefix code here would still be needed.

@Fryguy
Copy link
Member

Fryguy commented Jul 13, 2020

Overall, LGTM!

@NickLaMuro
Copy link
Member Author

NickLaMuro commented Aug 14, 2020

Stepping away from this for a few days, but figured I should leave a quick status:

This has shown to be working in practice here, with the last few commits (with [DONOTMERGE]) that will be broken out into a separate PR effort eventually (ran out of time today). For now, they can be viewed in isolation here:

NickLaMuro/manageiq@integration_env^^...integration_env

Those two commits in detail:

  • [DONOTMERGE][WIP] Add ManageIQ::Integration::DatabaseCleaner: Creates a custom strategy for cleaning the database. This is described further in he commit, but effectively it makes use of a copy of the seeded integration database that can be connected to by the integration DB and used after a sweep of TRUNCATE calls to reload tables back to their "seeded" state. Some tables are skipped (miq_servers for example), since they are in direct use the entire time, and dropping their records mid running would most likely cause side effects.
  • [POC][WIP][DONOTMERGE] Integration Factories Makes FactoryBot, as well as the above ManageIQ::Integration::DatabaseCleaner available through routes in the application. This is a very small engine that just loads works with the existing ManageIQ::Integration code, as well as the spec/support/factory_bot_helper.rb code to integrate those two pieces. Only loaded in a Rails.env.integration? environment (ideally).

I haven't tests this from cypress yet, though I am basically following the strategies outlined in this post:

https://blog.simplificator.com/2019/10/11/setting-up-cypress-with-rails/

And so integrating it from the UI should be straight forward. We might want a shard .js file for this (similar to the lib/manageiq/integration/cypress_rake.rb tasks that the UI is currently consuming, but that will be something I explore next week.

Configuration settings for integration testings.  A mix between
development and production, using production as a base and pulling in
specific options from development where appropriate.

`ENV['CYPRESS_DEV']` can be used as flag to enable more debugging
settings where needed.
The `sync_config` code assumes memcache, so for now just skip if in the
`Rails.env.integration?`

This is a poor solution long term since this causes issues when trying
to run integration tests against an "Integration ENV appliance", so this
should be addressed to work in a different way.
Adds an integration group for dependencies that need to be used for both
integration tests and "regular tests"
Allows them to be reused.
When calling `evm:compile_assets`, allow it to be called from a plugin
so that repos like the UI can compile assets from the plugin repo
instead of the `manageiq` repo.
Helper tasks that is used to run the necessary MiqWorker components for
running integration tests.

CYPRESS_DEV
-----------

Note on different modes:

- no `CYPRESS_DEV`:  "prod mode" where assets are static (CI, "faster")
- w/ `CYPRESS_DEV`:  dev mode where javascript assets might be edited

When using $CYPRESS_DEV, it is assumed that the user is modifying specs
or what they are testing, so being able to change those without having
to re-compile is ideal, but on CI, compiling should be a speed up for
the specs overall, and more "production like".
This is a hidden feature for now, but it is just a low cost way to
include support for multiple workers.  Easily removable if we don't like
it.
We `gzip` compress assets via `webpack`, so this "should" be
unecessary... need to confirm.
When doing `rake :env`, the `config.paths` method has already been
called/memoized when the `config/application.rb`, so that causes the
following to be called:

    paths.add "config/environments", glob: "#{Rails.env}.rb"

Which even before `:env` has a chance to run, it will set the `:glob`
attribute to the "default `Rails.env`", which in turn only allows
loading the include `developement.rb` when the initializer to load the
environment config for `Vmdb::Applciation` is finally trigger.

While not the best of solutions, I prefer it to having to have super
long commands like this:

    $ RAILS_ENV=integration rake integration:seed:db

Where `integration` is implied by the task itself (and helps "codify"
workflows).
While working through and debugging the previous FIXUP commits, this
came up as something to try, but not sure if it is needed.  Might go
away, but trying to commit/push what I have so I can transition to
working on something else.
@miq-bot
Copy link
Member

miq-bot commented Aug 21, 2020

Some comments on commits NickLaMuro/manageiq@af7daeb~...90623d0

lib/manageiq/integration/foreman_manager.rb

  • ⚠️ - 142 - Detected puts. Remove all debugging statements.
  • ⚠️ - 180 - Detected puts. Remove all debugging statements.
  • ⚠️ - 181 - Detected puts. Remove all debugging statements.
  • ⚠️ - 182 - Detected puts. Remove all debugging statements.
  • ⚠️ - 183 - Detected puts. Remove all debugging statements.
  • ⚠️ - 191 - Detected puts. Remove all debugging statements.
  • ⚠️ - 192 - Detected puts. Remove all debugging statements.
  • ⚠️ - 193 - Detected puts. Remove all debugging statements.
  • ⚠️ - 88 - Detected puts. Remove all debugging statements.
  • ⚠️ - 90 - Detected puts. Remove all debugging statements.
  • ⚠️ - 92 - Detected puts. Remove all debugging statements.

@miq-bot
Copy link
Member

miq-bot commented Aug 21, 2020

Checked commits NickLaMuro/manageiq@af7daeb~...90623d0 with ruby 2.6.3, rubocop 0.69.0, haml-lint 0.28.0, and yamllint
12 files checked, 26 offenses detected

Gemfile

app/models/miq_worker/runner.rb

config/initializers/session_store.rb

lib/manageiq/integration.rb

lib/manageiq/integration/cypress_rake_task.rb

lib/manageiq/integration/foreman_manager.rb

@miq-bot
Copy link
Member

miq-bot commented Sep 23, 2020

This pull request is not mergeable. Please rebase and repush.

@miq-bot
Copy link
Member

miq-bot commented Mar 6, 2023

This pull request has been automatically closed because it has not been updated for at least 3 months.

Feel free to reopen this pull request if these changes are still valid.

Thank you for all your contributions! More information about the ManageIQ triage process can be found in the triage process documentation.

@Fryguy Fryguy removed the stale label Jul 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants