Gem testing with Rspec - ruby

I have written a custom Ruby Gem to hook into our company's authentication and authorization system and am starting to develop the unit tests for the gem.
In our rails app, the Gem can be configured via environment.rb and a custom initializer and yaml file containing the configuration values.
I need to translate the configuration of the Gem in rails to test the standalone Gem. How do I translate this over to Rspec to perform integration testing??
Gem configuration in rails
# environment.rb
MyGem.configure do |config|
config.url = MY_CONFIG ['url']
config.application_name = MY_CONFIG ['app_name']
config.application_id = MY_CONFIG ['app_id']
config.logger = Rails.logger
config.log_level = :debug
# Rails config/initalizers/load_config.rb
# Custom config file loading automatically done via initializers
MY_CONFIG = YAML.load_file("#{Rails.root.to_s}/config/my_config.yml")[Rails.env]
# config/my_config.yml
defaults: &defaults
url: http://url/to/service
app_name: my app
app_id: 1
development:
<<: *defaults
test:
<<: *defaults
production:
<<: *defaults
end

Here's a simple project where you can see how you'd go by doing it: multiplier
First and foremost, if you're doing the gem management by yourself, please don't, use helper tools like jeweler to do it for you. Install the jeweler gem (gem install jeweler) and once you have it installed, create your gem projet:
jeweler --rspec your_gem_name
With this, it's going to setup a skeleton gem that's going to have a single main file (where you would require your necessary gem files) and the spec folder.
At the spec folder there's spec_helper.rb, that's where our configuration lives, what I did was:
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rspec'
require 'multiplier'
# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
RSpec.configure do |config|
end
Multiplier.configure do |config| #these are the only lines I added myself
config.multiplier 4
end
So, here lives the config for our gem, but you could even do it on each spec, if you'd need it. But if you want to use a single config for all specs this is where you should place it.

Related

Ruby Gem: Install configuration files to the user-home directory

I have to make a REST-Client in Ruby.
The client must be runnable from the command-line like a binary and also it must be "requirable" in a ruby script and provide different functions.
My gemspec does exactly what it should.
But i have no idea how to install a configuration file (YAML) in the user-home folder?
The config file should be in the user directory to provide easy access for the user.
Is this even possible?
Should i check on the first run if there is a config file and create it?
Can i execute an own installation routine while installing a gem?
I did exactly the same thing in Python and it worked fine, so the Ruby client should behave similar.
For such decisions, I wrote gem persey. If you look at the description of the use of this gem, you can see that it provides what you expect:
# Rails.root are not initialized here
app_path = File.expand_path('../../', __FILE__)
# ...
# config with secret keys
# you don't want store this config in repository and copy to secret folder on host machine
my_secret_key_config = '/home/user/secret/keys.yml'
# ...
# Persey.init ENV["environment"] do # set current environment
Persey.init Rails.env do # set current environment
source :yaml, my_secret_key_config, :secret # no comments. It's secret!
env :production do
# ...
end
env :development, :parent => :production do
# ...
end
end

ENV variables not being read sinatra

So i am trying to serve my static assets from Amazon s3 locally and for Heroku, I was loading a yml file but that doesn't work as Heroku doesn't accept symlinks.
So i was given the suggestion to use ENV variables as Heroku also uses these. I have a rake task to precompile the assets to AWS. two problems at the moment
1) My ENV variables are not being read.(Fog directory can't be blank, Aws access key can't be blank, Aws secret access key can't be blank
2) When running a rake task i also get the error 'already initialized constant VALID_CHARACTER'
So the activesupport constant is being loaded twice?
My setup
env.rb
ENV['aws_bucket'] = 'bucketname'
ENV['aws_access_key'] = 'myaccesskey'
ENV['aws_secret_key'] = 'mysecretkey'
Rakefile
require 'bundler/setup'
Bundler.require(:default)
require './env' if File.exists?('env.rb')
AssetSync.configure do |con|
con.fog_provider = 'AWS'
con.fog_region = 'eu-west-1'
con.fog_directory = ENV['aws_bucket']
con.aws_access_key_id = ENV['aws_access_key']
con.aws_secret_access_key = ENV['aws_secret_key']
con.prefix = "assets"
con.public_path = Pathname("./public")
end
namespace :assets do
desc "Precompile assets"
task :precompile do
AssetSync.sync
end
Gemfile
source :rubygems
gem 'sinatra'
gem 'pony'
gem 'sinatra-flash'
gem 'heroku'
gem 'asset_sync', git: 'git://github.com/ejholmes/asset_sync.git', branch: 'sinatra'
UPDATE
AssetSync has activesupport in it's gemspec so that's getting included any way. It seems to be conflicting with the constant defined in the mail gem from the pony gemspec.
So with the Pony gem removed i can precompile assets locally, but when i try and compile for heroku nothing happens, it starts the rake task but then just goes back to the terminal ready for a new command.
The other thing is i need Pony for my mailer, how can i get around this?
To get rid of the clash between Pony and when running Rake locally, put the gems into different groups, e.g.
# Gemfile
group :assets do
gem 'asset_sync', git: 'git://github.com/ejholmes/asset_sync.git', branch: 'sinatra'
end
group :mail do
gem "pony"
end
# moreā€¦
in the Rakefile
Bundler.require(:assets,:database,:whatever_else_you_need)
in the rackup/app file
Bundler.require(default,:assets,:database,:mail,:whatever_else_you_need)
As to your other problem, you should set the env vars for production via heroku config (see https://devcenter.heroku.com/articles/config-vars) and load them locally using the Rakefile as I said in the other question you asked about this. The env vars will live for the extent of the Ruby process, so if you load them in via Rake and also start the local server within the same Rake process you'll get Sinatra picking up all the env vars.
Edit: env vars will last as long as the process that added them, so if you put them in a dependent task the following task will have access to them:
namespace :assets do
task :environment do
AssetSync.configure do |con|
con.fog_provider = 'AWS'
con.fog_region = 'eu-west-1'
con.fog_directory = ENV['aws_bucket']
con.aws_access_key_id = ENV['aws_access_key']
con.aws_secret_access_key = ENV['aws_secret_key']
con.prefix = "assets"
con.public_path = Pathname("./public")
end
end
desc "Precompile assets"
task :precompile => :"assets:environment" do
AssetSync.sync
end
You might want to split this into different questions. This makes it easier to help you. As for your first question: I assume you didn't put the env.rb under version control?
Why are your env vars not being picked up by Sinatra? Because you configure Fog in the Rakefile, and Simatra never sees that file. It's used by rake only.
I'd suggest you put the Fog configuration into a third file and require that in both Rakefile and Sinatra app.

Can't adapt the airbrake gem to a Sinatra app

I am using the airbrake gem like so:
require 'airbrake'
Airbrake.configure do |config|
config.api_key = 'XXXXX'
config.development_environments = ["development", "test", "cucumber"]
end
use Airbrake::Rack
enable :raise_errors
but it still sends airbrake notifications in development.
My environment is saved in ENV['RACK_ENV'].
I don't want to hack my way into this, is there an "outside" solution?
Also, I do want to raise exceptions in development - I just don't want them to be sent to airbrake..
You could use a configure block to only setup Airbrake in production:
configure :production do
require 'airbrake'
Airbrake.configure do |config|
config.api_key = 'XXXXX'
end
use Airbrake::Rack
end
If you have more than one environment you want Airbrake enabled in, you can specify a list, e.g.:
configure :production, :staging do
...
#matt's answer should work well, but if you want to do this in the rackup file when setting up the middleware instead of inside the Sinatra app, you could do:
use Airbrake::Rack if ENV['RACK_ENV'] == "production"
I quite often do this with middleware.

Creating a class that wraps my config.yml file, and using it in my rake files

This is a non-rails app, just a simple ruby script that uses rake etc. to automate some things.
My folder layout is this:
/scripts/Rakefile
/scripts/config/config.yml
/scripts/tasks/*.rake (various rake files with namespaces to organize them)
/scripts/lib/settings.rb
Now I want to create a Settings class that will load the config yaml file, and then expose properties/methods for the contents of the yaml file.
The yaml file has separate sections for development and production.
development:
scripts_path: '/dev/mygit/app1/scripts/'
production:
scripts_path: '/var/lib/app1/scripts/'
My rakefile so far looks like:
$LOAD_PATH.unshift File.expand_path('..', __FILE__)
#imports
require 'fileutils'
require 'rubygems'
require 'active_record'
require 'yaml'
require 'logger'
require 'ar/models'
require 'lib/app1'
env = ENV['ENV'] || 'development'
config = YAML::load(File.open('config/config.yml'))[env]
Dir.glob('tasks/*.rake').each { |r| import r }
I need help with the Settings.rb file, is this right?
module App1
class Settings
def initialize(config_path, env)
config = YAML.load(File.open(config_path))
end
def scripts_path
end
end
end
How can I pass in the env, and then read the correct value from the config for each method like scripts_path etc?
Now suppose each *.rake file needs to reference my Settings.rb file somehow (to get the config related information). How should I do this? Since my settings needs the path of the config.yml file, do I have to do this in each rake file?
Update
Sorry, this isn't a Rails app, just some ruby scripts.
I would do it quite simple.
You don't need a complex solution.
require 'ostruct'
require 'yaml'
MY_ENV = ENV['ENV'] || 'development'
CONFIG = OpenStruct.new(YAML.load_file("config/config.yml")[MY_ENV])
Stick this at the top of your rakefile
and CONFIG will be available in all rake tasks.
Just call CONFIG.scripts_path
Inside my applications I do something of this sort.
# config/application.yml
development:
some_variable: a string
production:
some_variable: a different string
Then in application.rb I load it up.
# config/application.rb
module MyApp
def self.config
#config ||= OpenStruct.new(YAML.load_file("config/application.yml")[Rails.env.to_s])
end
class Application < Rails::Application
...
In this case, anywhere the environment is loaded I can say
MyApp.config.some_variable
To get access to this inside a rake task, I just need to include environment
task :something => :environment do
MyApp.config.some_variable
# do something with it
end

Why do I need to run my sinatra app again when making changes and my environment is not :development?

I just implemented Compass configuration for my Sinatra app but when I change the environment to :test or :production and modify my files like screen.sass or index.haml my changes are not reflected when I reload the page so I need to run my app again?
Is it normal? Is is just me?
This is how my app.rb file looks like:
require 'sinatra'
require 'haml'
require 'sass'
require 'compass'
require './helpers.rb'
configure do
set :environment, :test
Compass.configuration do |config|
settings.environment == :production ?
config.output_style = :compressed :
config.output_style = :nested
settings.environment == :development ?
config.line_comments = true :
config.line_comments = false
end
set :sass, Compass.sass_engine_options
end
before do
#js = 'javascript:;'
end
get '/scripts/jquery.js' do
# Downloads the latest jQuery 1.x version when needed. Requires to reload the page after done.
`curl "https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" >> public/scripts/jquery.js`
end
get '/styles/:name.css' do
sass :"styles/#{params[:name]}"
end
get '/?' do
haml :index
end
get '/:page/?' do
haml params[:page].to_sym
end
Any idea?
Generally, if you make a change to a running Sinatra application, you have to restart the application, as the program has already been loaded to memory.
There are options for automatically detecting changes and restarting the application on the Sinatra FAQ.
Since Shotgun fix the issue partially (reloading the files for your at production, maybe try with Sinatra::Reloader which, IMHO, works better than Shotgun.
Maybe something like (not tested)
require "sinatra"
configure(:production) do |c|
require "sinatra/reloader"
c.also_reload "*.sass", "*.haml"
end
That being said, are you sure you do need this kind of behavior on a production/test environment for updating? Development env. should be (at least, for what I use it for) for this kind of hot testing.
I used to use sinatra::reloader
but I didn't like the huge dependencies incurred (as should we all be mindful how many gems get activated)
pistol ( at a tender age of ver 0.0.2) and I think does the required job nicely
I use shotgum gem for this.
gem install shotgun
then
shotgun app.rb
from within the app dir
this then reloads the app per request, rather than holding the whole thing in memory. you access the site on localhost:9393

Resources