I am working on the rails 3.1.1 and using socery 0.7.11 for authentication, i need to implement the performance testing where i can test following things
Simulate 100 users signing on and off simultaneously
Simulate 100 users adding new interests simultaneously.
I have go through the following links:
http://rubylearning.com/blog/2011/08/14/performance-testing-rails-applications-how-to/
http://guides.rubyonrails.org/performance_testing.html
And able to do following things
created test folder with test_helper.rb
created test/performance/login_test.rb
created fixtures/users.yml
test_helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here...
end
/performance/login_test.rb
require 'test_helper'
require 'rails/performance_test_help'
class LoginTest < ActionDispatch::PerformanceTest
fixtures :users
# Refer to the documentation for all available options
self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory],
:output => 'tmp/performance', :formats => [:flat] }
def test_login
post_via_redirect "http://bc.lvh.me/", :username => users(:youruser).username, :password => users(:youruser).password
#using lvh.me coz login page is on my subdomain
end
end
fixtures/users.yml
one:
username: eagleschasar12
password: chaitanyA1#
two:
username: eaglesmarktell12
password: chaitanyA1#
when i run rake test:profile, i got following result
E
===============================================================================
Error: test_login(LoginTest)
ActiveRecord::StatementInvalid: SQLite3::SQLException: table users has no column named password: INSERT INTO "users" ("username", "password", "created_at", "updated_at", "id") VALUES ('eagleschasar12', 'chaitanyA1#', '2012-06-15 06:43:01', '2012-06-15 06:43:01', 980190962)
So my questions are
Why test command firing insert query?
Do i need to write 100 records of users in fixture file to test the functionality?
How to check session login/logoff?
Also when i select interest types from db my user should logged in the system, so how can i test this scenario in performance testing?
Does this tests run on webrick, which is my local server.
I will try to answer your questions in order as best I can. I'm sure others might give more complete answers for each one individually and they're welcome to, but I hope to get you started so you can know what to look for:
1. Why test command firing insert query?
Your insert queries are run from your fixtures. Personally I user FactoryGirl, but the logic is the same. When you run your fixture, it inserts that object into your database. That way you can do something like fixture :user and it will create a user for you without having to supply all the User object details every time. If you have 5 fixtures in your file, running something like fixture :users will create 5 entries (If someone can confirm this for Fixtures I'd be grateful, as I don't user fixtures).
2. Do i need to write 100 records of users in fixture file to test the functionality?
No you don't. You can use the Faker gem to automatically create as many users (or anything else) as you want with random names, strings, etc. The documentation is here.
3. How to check session login/logoff?
When you create your session, you should be setting the session[user_id] variable, so you can test for that. Needless to say, on logoff (i.e. session destroy) you should be setting it to nil. In any case, when a session is created by setting the session[:user_id] variable, then you can access the session ID using request.session_options[:id]
4. Also when i select interest types from db my user should logged in the system, so how can i test this scenario in performance testing?
Before each test you should run a "test_log_in" function that logs in the test user you create. Then the tests that require a logged in user should pass. You should also create tests where without logging in the test user, and they should not perform the changes (or should not display the pages) that require a logged in user.
5. Does this tests run on webrick, which is my local server?
If that is the server you have installed in you Gemfile, that it will be used. It will work with whichever server you have installed.
You have asked a lot of questions in one question, so if you need more detail on the the answers I would recommend you ask each question in a different post with a more detail description on what you're looking for. That way your answers will not be broad like this one, but more specific.
Hope I at least gave you a good place to start from.
Related
In Rspec, I'm creating records, e.g. let!(:user) { create(:user) }.
I can access the new user in Rspec and in the main thread of the subject. Both of these return the user:
puts User.all.to_a
puts ActiveRecord::Base.connection.exec_query('select * from users')
However, I can now longer access the user in a new thread:
Thread.new do
puts User.all.to_a
puts ActiveRecord::Base.connection.exec_query('select * from users')
end
How do I fix this? Is this just an Rspec issue? I don't think I can reproduce it in Rails console.
You have probably configured RSpec to run its test within a database transaction
Quote from the RSpec Docs:
>
When you run rails generate rspec:install, the spec/rails_helper.rb file
includes the following configuration:
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
The name of this setting is a bit misleading. What it really means in Rails
is "run every test method within a transaction." In the context of rspec-rails,
it means "run every example within a transaction."
The idea is to start each example with a clean database, create whatever data
is necessary for that example, and then remove that data by simply rolling back
the transaction at the end of the example.
You might want to disable this configuration when your application tests have the requirement to support multiple threads at the same time.
But that means that your test database will not be cleared from test data automatically anymore when a test is done. Instead, you will need to delete the test data manually or use another gem (like database_cleaner) to reset the database after running tests.
I've sucessfully rolled my own roles and permissions based authorisation system:
Roles and Permissions are both models in the database that have a many-to-many relationship through another table.
Users belong_to a role and have_many permissions through that role
Admin users are able to create new roles and define which permissions go with which roles.
Controllers and Views check the current user has particular permissions before acting or rendering certain things.
It all works wonderfully. Here's a key part of the code which gets included into application_controller,rb:
def permitted_action (permission_names)
# if the users permissions do not instersect with those given then redirect to root
redirect_to(root_url) if (permission_names & current_user.permissions.map(&:name)).empty?
end
and here's a controller validating user permissions:
before_action only: [:new, :create] do
permitted_action ['create_user']
end
My problem is that permissions are DB rows with unique string names, and I use the names when I want to identify the permissions. So I seed the DB with all the permissions that I need, and then when a View or Controller needs to check the permission I need to get the permission name right at that point. If I check for permission "add_user" but in the db the permission name is "add_users" it goes wrong.
Then in testing I have to put all the permissions in again as fixtures, and get all the names right again.
When I add functionality that requires more permissions I have to add these permissions in with the same string in at least 3 different places. That seems like the wrong thing to me.
Ideally the controllers would define what the permissions are that they use, and the db/seeds.rb file would pick up those and seed the db, and the test fixtures would also pick them up, but I'm not sure if this is possible.
How should I structure this?
Edit:
I think what would help me is a fixtures parser that feeds the db/seeds.rb file. Taking something like this from permissions.yml:
archive_tally:
name: archive_tally
description: Archive or make active any tally
category: 3
And spitting out something like this:
archive_tally = Permission.find_or_initiate_by_name("archive_tally")
archive_tally.description = "Archive or make active any tally"
archive_tally.category = 3
archive_tally.save!
I don't think this sort of thing exists yet.
You can actually cut this down to just being the user table (or roles too depending on how many there are) by adding fields like is_admin or is_general_user to group your users into permissions groups. Then the permissions are just a matter of methods on the User Model, for example:
def can_create_new_roles?
self.is_admin
end
So now you can just do
before_action only: [:create, :new] do
redirect_to root_path unless current_user.can_create_new_roles?
end
Which reads much nicer. Plus since this all happens on the User model vs. on its own DB table it would make testing for all of these UserPermissions much easier.
This is what I've come up with and it satisfies me, though it's not the ideal solution that I was hunting for in the question:
It turns out that I want the production database to be seeded with fixtures that are a subset of the fixtures I want appearing in the testing database.
I've made a directory db/seed_fixtures that includes files such as roles.yml and permissions.yml. In these files I've put the fixtures I want to seed the production database with.
In tests/fixtures/roles.yml I've included the other fixtures with this line at the top of the file:
<%= ERB.new(IO.read(Rails.root.join "db/seed_fixtures/roles.yml")).result %>
Same deal with permissions.yml and other YAML files this applies to. I put any testing-only fixtures in there under that include line.
In db/seeds.rb I generate seeding code from the fixtures for production like this: ActiveRecord::Fixtures.create_fixtures("#{Rails.root}/db/seed_fixtures", "roles")
Now I write all my fixtures once each, some for use as seeds in the production database, others are only for testing. To load the seeds in to the database I run rake db:seed (which I do on the production server) and to load all the testing fixtures in the database I run rake db:fixtures:load
Update:
I've just started using Cucumber and I've realised that I can use the code in step 3 above in a Cucumber Step to get the seed data into Cucumber's test database:
Given(/^seed data is loaded into the database$/) do
ActiveRecord::FixtureSet.create_fixtures("#{Rails.root}/db/seed_fixtures", "roles")
_(Role.count).wont_equal 0
end
Cucumber also informed me that ActiveRecord::Fixtures is deprecated in favour of ActiveRecord::FixtureSet
I've come up with a completely different solution: I've created a fixture parser.
Most of my first solution still applies (see my other answer) but now, instead of step 3 in that solution, I've made a parser that reads the fixtures that I want to use for seeds and adds them to the database, checking for whether they are already there or not. I run the parser from db/seeds.rb
I've put the code for the parser up as a gist on github
I'm trying to use fixtures to add more complex test data in order to test specific scenarios with the front-end, which is in Flex. I'm not sure this is the right way to go about it with rails. My rails app is a card game and the 'more complex test data' I'm trying to test are various combinations of cards.
For example, I want to set up a test game where player 1 has cards B and C in hand, where I've specifically added cards B and C to the player's hand in a fixture.
I have basic fixtures for players, games, and users, which have been there for awhile and working fine. I've tried to add the following erb code in the games fixture, to invoke the Game.start method, and am getting
NoMethodError: undefined method `games' for main:Object
The fixture code snippet is :
four:
id: 4
num_players: 3
turn_num: 0
status_id: 1
<% game_four = games(:four).find
game_four.start
%>
game_four = games(:four).find
games method exists only in test cases, not in fixtures.
You should either query the database or use relationships.
This is just an example.
four:
id: 4
num_players: 3
turn_num: 0
status_id: 1
<% Game.find_by_name(four).start %>
Also, this is not really the right place for such command. Fixtures are not intended "to start games".
You should really move this command elsewhere, perhaps in a dedicated test case within the setup block.
EDIT:
I copy here my comment posted a couple of days ago on the original answer with a link to the new Rails Database Seeding feature: http://ryandaigle.com/articles/2009/5/13/what-s-new-in-edge-rails-database-seeding
This is the one explained by Yehuda Katz in his answer and definitely the best way to solve this problem.
Probably the best solution (and in fact, the one that is now canonized on edge) is to have a seeds.rb file in your db directory that you load from a rake task.
Here's what Rails does now on edge (to be in Rails 3).
# db/seeds.rb
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
# Major.create(:name => 'Daley', :city => cities.first)
And then a new rake task (which you can add to your Rakefile):
desc 'Load the seed data from db/seeds.rb'
task :seed => :environment do
seed_file = File.join(Rails.root, 'db', 'seeds.rb')
load(seed_file) if File.exist?(seed_file)
end
If you set up your seeds.rb file this way, you will be following the new convention and will be able to delete the seeds rake task when you upgrade to Rails 3.
Also, migrations are not for data. This is well established and the universal opinion of the Rails core team as far as I know.
If you want to use fixtures method (when loading data for development, not during tests) you can use fixtures_references plugin. Its behaviour will be the same.
I have fixtures with initial data that needs to reside in my database (countries, regions, carriers, etc.). I have a task rake db:seed that will seed a database.
namespace :db do
desc "Load seed fixtures (from db/fixtures) into the current environment's database."
task :seed => :environment do
require 'active_record/fixtures'
Dir.glob(RAILS_ROOT + '/db/fixtures/yamls/*.yml').each do |file|
Fixtures.create_fixtures('db/fixtures/yamls', File.basename(file, '.*'))
end
end
end
I am a bit worried because this task wipes my database clean and loads the initial data. The fact that this is even possible to do more than once on production scares the crap out of me. Is this normal and do I just have to be cautious? Or do people usually protect a task like this in some way?
Seeding data with fixtures is an extremely bad idea.
Fixtures are not validated and since most Rails developers don't use database constraints this means you can easily get invalid or incomplete data inserted into your production database.
Fixtures also set strange primary key ids by default, which is not necessarily a problem but is annoying to work with.
There are a lot of solutions for this. My personal favorite is a rake task that runs a Ruby script that simply uses ActiveRecord to insert records. This is what Rails 3 will do with db:seed, but you can easily write this yourself.
I complement this with a method I add to ActiveRecord::Base called create_or_update. Using this I can run the seed script multiple times, updating old records instead of throwing an exception.
I wrote an article about these techniques a while back called Loading seed data.
For the first part of your question, yes I'd just put some precaution for running a task like this in production. I put a protection like this in my bootstrapping/seeding task:
task :exit_or_continue_in_production? do
if Rails.env.production?
puts "!!!WARNING!!! This task will DESTROY " +
"your production database and RESET all " +
"application settings"
puts "Continue? y/n"
continue = STDIN.gets.chomp
unless continue == 'y'
puts "Exiting..."
exit!
end
end
end
I have created this gist for some context.
For the second part of the question -- usually you really want two things: a) very easily seeding the database and setting up the application for development, and b) bootstrapping the application on production server (like: inserting admin user, creating folders application depends on, etc).
I'd use fixtures for seeding in development -- everyone from the team then sees the same data in the app and what's in app is consistent with what's in tests. (Usually I wrap rake app:bootstrap, rake app:seed rake gems:install, etc into rake app:install so everyone can work on the app by just cloning the repo and running this one task.)
I'd however never use fixtures for seeding/bootstrapping on production server. Rails' db/seed.rb is really fine for this task, but you can of course put the same logic in your own rake app:seed task, like others pointed out.
Rails 3 will solve this for you using a seed.rb file.
http://github.com/brynary/rails/commit/4932f7b38f72104819022abca0c952ba6f9888cb
We've built up a bunch of best practices that we use for seeding data. We rely heavily on seeding, and we have some unique requirements since we need to seed multi-tenant systems. Here's some best practices we've used:
Fixtures aren't the best solution, but you still should store your seed data in something other than Ruby. Ruby code for storing seed data tends to get repetitive, and storing data in a parseable file means you can write generic code to handle your seeds in a consistent fashion.
If you're going to potentially update seeds, use a marker column named something like code to match your seeds file to your actual data. Never rely on ids being consistent between environments.
Think about how you want to handle updating existing seed data. Is there any potential that users have modified this data? If so, should you maintain the user's information rather than overriding it with seed data?
If you're interested in some of the ways we do seeding, we've packaged them into a gem called SeedOMatic.
How about just deleting the task off your production server once you have seeded the database?
I just had an interesting idea...
what if you created \db\seeds\ and added migration-style files:
file: 200907301234_add_us_states.rb
class AddUsStates < ActiveRecord::Seeds
def up
add_to(:states, [
{:name => 'Wisconsin', :abbreviation => 'WI', :flower => 'someflower'},
{:name => 'Louisiana', :abbreviation => 'LA', :flower => 'cypress tree'}
]
end
end
def down
remove_from(:states).based_on(:name).with_values('Wisconsin', 'Louisiana', ...)
end
end
alternately:
def up
State.create!( :name => ... )
end
This would allow you to run migrations and seeds in an order that would allow them to coexist more peaceably.
thoughts?
I've got a rails application where users have to log in. Therefore in order for the application to be usable, there must be one initial user in the system for the first person to log in with (they can then create subsequent users). Up to now I've used a migration to add a special user to the database.
After asking this question, it seems that I should be using db:schema:load, rather than running the migrations, to set up fresh databases on new development machines. Unfortunately, this doesn't seem to include the migrations which insert data, only those which set up tables, keys etc.
My question is, what's the best way to handle this situation:
Is there a way to get d:s:l to include data-insertion migrations?
Should I not be using migrations at all to insert data this way?
Should I not be pre-populating the database with data at all? Should I update the application code so that it handles the case where there are no users gracefully, and lets an initial user account be created live from within the application?
Any other options? :)
Try a rake task. For example:
Create the file /lib/tasks/bootstrap.rake
In the file, add a task to create your default user:
namespace :bootstrap do
desc "Add the default user"
task :default_user => :environment do
User.create( :name => 'default', :password => 'password' )
end
desc "Create the default comment"
task :default_comment => :environment do
Comment.create( :title => 'Title', :body => 'First post!' )
end
desc "Run all bootstrapping tasks"
task :all => [:default_user, :default_comment]
end
Then, when you're setting up your app for the first time, you can do rake db:migrate OR rake db:schema:load, and then do rake bootstrap:all.
Use db/seed.rb found in every Rails application.
While some answers given above from 2008 can work well, they are pretty outdated and they are not really Rails convention anymore.
Populating initial data into database should be done with db/seed.rb file.
It's just works like a Ruby file.
In order to create and save an object, you can do something like :
User.create(:username => "moot", :description => "king of /b/")
Once you have this file ready, you can do following
rake db:migrate
rake db:seed
Or in one step
rake db:setup
Your database should be populated with whichever objects you wanted to create in seed.rb
I recommend that you don't insert any new data in migrations. Instead, only modify existing data in migrations.
For inserting initial data, I recommend you use YML. In every Rails project I setup, I create a fixtures directory under the DB directory. Then I create YML files for the initial data just like YML files are used for the test data. Then I add a new task to load the data from the YML files.
lib/tasks/db.rake:
namespace :db do
desc "This loads the development data."
task :seed => :environment do
require 'active_record/fixtures'
Dir.glob(RAILS_ROOT + '/db/fixtures/*.yml').each do |file|
base_name = File.basename(file, '.*')
say "Loading #{base_name}..."
Fixtures.create_fixtures('db/fixtures', base_name)
end
end
desc "This drops the db, builds the db, and seeds the data."
task :reseed => [:environment, 'db:reset', 'db:seed']
end
db/fixtures/users.yml:
test:
customer_id: 1
name: "Test Guy"
email: "test#example.com"
hashed_password: "656fc0b1c1d1681840816c68e1640f640c6ded12"
salt: "188227600.754087929365988"
This is my new favorite solution, using the populator and faker gems:
http://railscasts.com/episodes/126-populating-a-database
Try the seed-fu plugin, which is quite a simple plugin that allows you to seed data (and change that seed data in the future), will also let you seed environment specific data and data for all environments.
I guess the best option is number 3, mainly because that way there will be no default user which is a great way to render otherwise good security useless.
I thought I'd summarise some of the great answers I've had to this question, together with my own thoughts now I've read them all :)
There are two distinct issues here:
Should I pre-populate the database with my special 'admin' user? Or should the application provide a way to set up when it's first used?
How does one pre-populate the database with data? Note that this is a valid question regardless of the answer to part 1: there are other usage scenarios for pre-population than an admin user.
For (1), it seems that setting up the first user from within the application itself is quite a bit of extra work, for functionality which is, by definition, hardly ever used. It may be slightly more secure, however, as it forces the user to set a password of their choice. The best solution is in between these two extremes: have a script (or rake task, or whatever) to set up the initial user. The script can then be set up to auto-populate with a default password during development, and to require a password to be entered during production installation/deployment (if you want to discourage a default password for the administrator).
For (2), it appears that there are a number of good, valid solutions. A rake task seems a good way, and there are some plugins to make this even easier. Just look through some of the other answers to see the details of those :)
Consider using the rails console. Good for one-off admin tasks where it's not worth the effort to set up a script or migration.
On your production machine:
script/console production
... then ...
User.create(:name => "Whoever", :password => "whichever")
If you're generating this initial user more than once, then you could also add a script in RAILS_ROOT/script/, and run it from the command line on your production machine, or via a capistrano task.
That Rake task can be provided by the db-populate plugin:
http://github.com/joshknowles/db-populate/tree/master
Great blog post on this:
http://railspikes.com/2008/2/1/loading-seed-data
I was using Jay's suggestions of a special set of fixtures, but quickly found myself creating data that wouldn't be possible using the models directly (unversioned entries when I was using acts_as_versioned)
I'd keep it in a migration. While it's recommended to use the schema for initial setups, the reason for that is that it's faster, thus avoiding problems. A single extra migration for the data should be fine.
You could also add the data into the schema file, as it's the same format as migrations. You'd just lose the auto-generation feature.
For users and groups, the question of pre-existing users should be defined with respect to the needs of the application rather than the contingencies of programming. Perhaps your app requires an administrator; then prepopulate. Or perhaps not - then add code to gracefully ask for a user setup at application launch time.
On the more general question, it is clear that many Rails Apps can benefit from pre-populated date. For example, a US address holding application may as well contain all the States and their abbreviations. For these cases, migrations are your friend, I believe.
Some of the answers are outdated. Since Rails 2.3.4, there is a simple feature called Seed available in db/seed.rb :
#db/seed.rb
User.create( :name => 'default', :password => 'password' )
Comment.create( :title => 'Title', :body => 'First post!' )
It provides a new rake task that you can use after your migrations to load data :
rake db:seed
Seed.rb is a classic Ruby file, feel free to use any classic datastructure (array, hashes, etc.) and iterators to add your data :
["bryan", "bill", "tom"].each do |name|
User.create(:name => name, :password => "password")
end
If you want to add data with UTF-8 characters (very common in French, Spanish, German, etc.), don't forget to add at the beginning of the file :
# ruby encoding: utf-8
This Railscast is a good introduction : http://railscasts.com/episodes/179-seed-data