diff --git a/Gemfile b/Gemfile index 77627808d..cc92bec3d 100644 --- a/Gemfile +++ b/Gemfile @@ -28,9 +28,12 @@ gem 'redfinger', :git => 'git://github.com/rsofaer/redfinger.git' #EventMachine gem 'em-http-request',:git => 'git://github.com/igrigorik/em-http-request.git', :require => 'em-http' -gem 'em-websocket' gem 'thin' +#Websocket +gem 'em-websocket' +gem 'magent', :git => 'http://github.com/dcu/magent.git' + #File uploading gem 'carrierwave', :git => 'git://github.com/rsofaer/carrierwave.git' , :branch => 'master' #Untested mongomapper branch gem 'mini_magick' diff --git a/Gemfile.lock b/Gemfile.lock index 007810850..dd181b320 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -47,6 +47,14 @@ GIT bcrypt-ruby (~> 2.1.2) warden (~> 0.10.7) +GIT + remote: http://github.com/dcu/magent.git + revision: 06513f3dac812469a55f2e365c349af4d2abc92a + specs: + magent (0.4.2) + mongo (>= 0.1.0) + uuidtools (>= 2.0.0) + GIT remote: http://github.com/jnunemaker/mongomapper.git revision: 931dab779011aa7acf60c1a4c7ad19e1ba838345 @@ -213,6 +221,7 @@ GEM treetop (1.4.8) polyglot (>= 0.3.1) tzinfo (0.3.23) + uuidtools (2.1.1) warden (0.10.7) rack (>= 1.0.0) webmock (1.3.5) @@ -242,6 +251,7 @@ DEPENDENCIES haml jnunemaker-validatable (= 1.8.4)! json + magent! mini_magick mocha mongo_mapper (= 0.8.4)! diff --git a/README.md b/README.md index d941ac182..2398be5dc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ You are welcome to contribute, add and extend Diaspora however you see fit. We We need you to fill out a [contributor agreement form](https://spreadsheets.google.com/a/joindiaspora.com/viewform?formkey=dGI2cHA3ZnNHLTJvbm10LUhXRTJjR0E6MQ&theme=0AX42CRMsmRFbUy1iOGYwN2U2Mi1hNWU0LTRlNjEtYWMyOC1lZmU4ODg1ODc1ODI&ifq) before we can accept your patches. The agreement gives Diaspora joint ownership of the patch so the copyright isn't scattered. You can find it [here](https://spreadsheets.google.com/a/joindiaspora.com/viewform?formkey=dGI2cHA3ZnNHLTJvbm10LUhXRTJjR0E6MQ&theme=0AX42CRMsmRFbUy1iOGYwN2U2Mi1hNWU0LTRlNjEtYWMyOC1lZmU4ODg1ODc1ODI&ifq). -All commits must be tested, and after each commit, all tests should be green before a pull request is sent. Please write your tests in Rspec or Test-Unit. +All commits must be tested, and after each commit, all tests should be green before a pull request is sent. Please write your tests in Rspec. GEMS: We would like to keep external dependencies unduplicated. We're using Nokogiri, and Mongomapper, and EM::HttpRequest as much as possible. We have a few gems in the project we'd rather not use, but if you can, use dependencies we already have. @@ -195,9 +195,15 @@ If you installed the OsX package through "brew", MongoDB will need to be started Diaspora will not run unless mongo is running. Mongo will not run by default, and will need to be started every time you wish to use or run the test suite for Diaspora. +### Run the server +`./script/server` will start both thin and the websocket server. If you want to run a different app server, you will have to run them separately. See below for instructions. + ### Run the app server Once mongo is running and bundler has finished, run `bundle exec thin start` from the root Diaspora directory. This will start the app server in development mode[.](http://bit.ly/9mwtUw) +### Run the websocket server +run `bundle exec ruby ./script/websocket_server` to start the websocket server on port 8080. Change the port in config/app_config.yml. + ### Logging in Run `rake db:seed:tom`, then login with user `tom` and password `evankorth`. More details in db/seeds/tom.rb. diff --git a/app/controllers/sockets_controller.rb b/app/controllers/sockets_controller.rb index 2852a7160..9b90ea831 100644 --- a/app/controllers/sockets_controller.rb +++ b/app/controllers/sockets_controller.rb @@ -14,7 +14,7 @@ class SocketsController < ApplicationController def outgoing(uid,object,opts={}) @_request = ActionDispatch::Request.new({}) - Diaspora::WebSocket.push_to_user(uid, action_hash(uid, object, opts)) + Diaspora::WebSocket.queue_to_user(uid, action_hash(uid, object, opts)) end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4a36672bc..72666bc30 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -7,13 +7,6 @@ class UsersController < ApplicationController before_filter :authenticate_user!, :except => [:new, :create] respond_to :html - respond_to :json, :only => :show - - def show - @user = User.find_by_id params[:id] - @user_profile = @user.person.profile - respond_with @user - end def edit @user = current_user @@ -23,7 +16,7 @@ class UsersController < ApplicationController end def update - @user = User.find_by_id params[:id] + @user = current_user prep_image_url(params[:user]) @user.update_profile params[:user] diff --git a/app/models/person.rb b/app/models/person.rb index 48e8b0816..1e2a7b18d 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -85,10 +85,12 @@ class Person local_person elsif !identifier.include?("localhost") && !opts[:local] begin - puts "begin finger" + Rails.logger.info("Webfingering #{identifier}") f = Redfinger.finger(identifier) rescue SocketError => e raise "Diaspora server for #{identifier} not found" if e.message =~ /Name or service not known/ + rescue Errno::ETIMEDOUT => e + raise "Connection timed out to Diaspora server for #{identifier}" end raise "No webfinger profile found at #{identifier}" if f.nil? || f.links.empty? Person.from_webfinger_profile(identifier, f ) diff --git a/app/models/post.rb b/app/models/post.rb index e2dd53d3d..9f7c3ff27 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -4,6 +4,7 @@ class Post + require 'lib/diaspora/websocket' require 'lib/encryptable' include MongoMapper::Document include ApplicationHelper diff --git a/app/models/user.rb b/app/models/user.rb index 718d23674..4ec528e70 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -34,7 +34,6 @@ class User many :aspects, :class_name => 'Aspect' - after_create :seed_aspects before_validation_on_create :downcase_username @@ -239,8 +238,7 @@ class User Rails.logger.info( "the person id is #{object.post_id} the friend found is #{visible_person_by_id(object.post_id).inspect}") unfriended_by visible_person_by_id(object.post_id) - - else +else object.perform self.id aspects = self.aspects_with_person(object.person) aspects.each{ |aspect| aspect.post_ids.delete(object.post_id.to_id) diff --git a/config/app_config.yml b/config/app_config.yml index 0a206c366..a138424ee 100644 --- a/config/app_config.yml +++ b/config/app_config.yml @@ -8,6 +8,7 @@ development: debug: false socket_debug : false socket_port: 8080 + socket_collection_name: 'websocket' pubsub_server: 'https://pubsubhubbub.appspot.com/' test: diff --git a/config/deploy.rb b/config/deploy.rb index b4870f94d..bceef51b5 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -27,24 +27,19 @@ set :deploy_via, :checkout # set :rails_env, ENV['rails_env'] || ENV['RAILS_ENV'] || all['default_env'] -role :tom, "tom.joindiaspora.com" -backers.each{ |backer| - role :backer, "#{backer['username']}.joindiaspora.com", :number => backer['number'] -} +role :pivots, config['servers']['pivots']['url'] -#role :ci, "ci.joindiaspora.com" # If you are using Passenger mod_rails uncomment this: # if you're still using the script/reapear helper you will need # these http://github.com/rails/irs_process_scripts # Start Nginx after "deploy:cold" do - run("nginx stop") - run("killall nginx") - #run("nginx") + run("nginx") end namespace :deploy do + task :symlink_images do run "mkdir -p #{shared_path}/uploads" run "ln -s -f #{shared_path}/uploads #{current_path}/public/uploads" @@ -58,23 +53,33 @@ namespace :deploy do task :start do start_mongo start_thin + start_websocket + end + + task :start_websocket do + run("cd #{current_path} && bundle exec ruby ./script/websocket_server.rb > /dev/null&") end task :start_mongo do - run("mkdir -p -v #{current_path}/log/db/ ") - run("mkdir -p -v #{shared_path}/db/") - run("mongod --fork --logpath #{current_path}/log/db/mongolog.txt --dbpath #{shared_path}/db/ " ) + run("mkdir -p -v #{current_path}/log/db/ ") + run("mkdir -p -v #{shared_path}/db/") + run("mongod --fork --logpath #{current_path}/log/db/mongolog.txt --dbpath #{shared_path}/db/ " ) end task :start_thin do - run("mkdir -p -v #{current_path}/log/thin/ ") - run("cd #{current_path} && bundle exec thin start -C config/thin.yml") + run("mkdir -p -v #{current_path}/log/thin/ ") + run("cd #{current_path} && bundle exec thin start -C config/thin.yml") end task :stop do stop_thin run("killall -s 2 mongod || true") end + + task :go_cold do + stop + run("killall nginx") + end task :stop_thin do run("killall -s 2 ruby || true") @@ -116,32 +121,13 @@ namespace :cloud do end end namespace :db do - - task :purge, :roles => [:tom, :backer] do + + task :purge, :roles => [:pivots] do run "cd #{current_path} && bundle exec rake db:purge --trace RAILS_ENV=#{rails_env}" end - - task :tom_seed, :roles => :tom do - run "cd #{current_path} && bundle exec rake db:seed:tom --trace RAILS_ENV=#{rails_env}" - run "curl -silent -u tom@tom.joindiaspora.com:evankorth http://tom.joindiaspora.com/zombiefriends" - backers.each do |backer| - run "curl -silent -u #{backer['username']}@#{backer['username']}.joindiaspora.com:#{backer['username']}#{backer['pin']} http://#{backer['username']}.joindiaspora.com/zombiefriendaccept" - #run "curl -silent -u #{backer['username']}@#{backer['username']}.joindiaspora.com:#{backer['username']}#{backer['pin']} http://#{backer['username']}.joindiaspora.com/set_profile_photo" - end - - end - - task :backer_seed, :roles => :backer do - (0..10).each { |n| - run "curl -silent http://localhost/set_backer_number?number=#{n}", :only => {:number => n} - } - run "cd #{current_path} && bundle exec rake db:seed:backer --trace RAILS_ENV=#{rails_env}" - end - + task :reset do purge - backer_seed - tom_seed end diff --git a/config/deploy_config.yml b/config/deploy_config.yml index c653b6565..01bd94470 100644 --- a/config/deploy_config.yml +++ b/config/deploy_config.yml @@ -7,65 +7,9 @@ cross_server: deploy_to: '/usr/local/app/diaspora' user: 'root' + branch: 'production' repo: 'git@github.com:diaspora/diaspora.git' - branch: 'master' - default_env: 'development' + default_env: 'production' servers: - tom: - - url: 'tom.joindiaspora.com' - backer: - - username: 'washington' - given_name: 'George' - family_name: 'Washington' - number: 0 - pin: 5072 - - username: 'adams' - given_name: 'John' - family_name: 'Adams' - number: 1 - pin: 3742 - - username: 'jefferson' - given_name: 'Thomas' - family_name: 'Jefferson' - number: 2 - pin: 7782 - - username: 'madison' - given_name: 'James' - family_name: 'Madison' - number: 3 - pin: 2691 - - username: 'monroe' - given_name: 'James' - family_name: 'Monroe' - number: 4 - pin: 6133 - - username: 'quincyadams' - given_name: 'John Quincy' - family_name: 'Adams' - number: 5 - pin: 7558 - - username: 'jackson' - given_name: 'Andrew' - family_name: 'Jackson' - number: 6 - pin: 8670 - - username: 'buren' - given_name: 'Martin' - family_name: 'Van Buren' - number: 7 - pin: 1559 - - username: 'harrison' - given_name: 'William Henry' - family_name: 'Harrison' - number: 8 - pin: 5404 - - username: 'tyler' - given_name: 'John' - family_name: 'Tyler' - number: 9 - pin: 6431 - - username: 'polk' - given_name: 'James K.' - family_name: 'Polk' - number: 10 - pin: 1957 + pivots: + url: 'pivots.joindiaspora.com' diff --git a/config/environments/development.rb b/config/environments/development.rb index 66a0ef31a..e73a3e9d1 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -21,8 +21,19 @@ Diaspora::Application.configure do config.action_controller.perform_caching = false # Don't care if the mailer can't send - config.action_mailer.raise_delivery_errors = false + config.action_mailer.raise_delivery_errors = true config.active_support.deprecation = :log config.middleware.use MongoMapper::ClearDevMemory #config.threadsafe! + config.action_mailer.delivery_method = :smtp + config.action_mailer.default_url_options = {:host => 'localhost:3000'} + config.action_mailer.smtp_settings = { + :address => 'smtp.gmail.com', + :port => 587, + :domain => 'mail.joindiaspora.com', + :authentication => 'plain', + :user_name => 'diaspora-pivots@joindiaspora.com', + :password => "xy289|]G+R*-kA", + :enable_starttls_auto => true + } end diff --git a/config/environments/production.rb b/config/environments/production.rb index 1267a96a3..3207c627d 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -15,12 +15,12 @@ Diaspora::Application.configure do config.action_controller.perform_caching = true # Specifies the header that your server uses for sending files - config.action_dispatch.x_sendfile_header = "X-Sendfile" + #config.action_dispatch.x_sendfile_header = "X-Sendfile" config.active_support.deprecation = :notify # For nginx: - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' + config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # If you have no front-end server that supports something like X-Sendfile, # just comment this out and Rails will serve the files @@ -36,7 +36,7 @@ Diaspora::Application.configure do # Disable Rails's static asset server # In production, Apache or nginx will already do this - config.serve_static_assets = true + #config.serve_static_assets = true # Enable serving of images, stylesheets, and javascripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" @@ -44,12 +44,20 @@ Diaspora::Application.configure do # Disable delivery errors, bad email addresses will be ignored # config.action_mailer.raise_delivery_errors = false - # Enable threaded mode - # config.threadsafe! - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found) config.i18n.fallbacks = true config.threadsafe! + config.action_mailer.delivery_method = :smtp + config.action_mailer.default_url_options = {:host => 'pivots.joindiaspora.com'} + config.action_mailer.smtp_settings = { + :address => 'smtp.gmail.com', + :port => 587, + :domain => 'mail.joindiaspora.com', + :authentication => 'plain', + :user_name => 'diaspora-pivots@joindiaspora.com', + :password => "xy289|]G+R*-kA", + :enable_starttls_auto => true + } end diff --git a/config/initializers/socket.rb b/config/initializers/socket.rb deleted file mode 100644 index 0b1035001..000000000 --- a/config/initializers/socket.rb +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2010, Diaspora Inc. This file is -# licensed under the Affero General Public License version 3. See -# the COPYRIGHT file. - - -require 'em-websocket' -require 'eventmachine' -require 'lib/diaspora/websocket' - EM.next_tick { - Diaspora::WebSocket.initialize_channels - - EventMachine::WebSocket.start( - :host => "0.0.0.0", - :port => APP_CONFIG[:socket_port], - :debug =>APP_CONFIG[:socket_debug]) do |ws| - ws.onopen { - - sid = Diaspora::WebSocket.subscribe(ws.request['Path'].gsub('/',''), ws) - - ws.onmessage { |msg| SocketsController.new.incoming(msg) } - - ws.onclose { Diaspora::WebSocket.unsubscribe(ws.request['Path'].gsub('/',''), sid) } - } - end - } - diff --git a/config/routes.rb b/config/routes.rb index 12dd20ba7..188c4b137 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,7 +6,7 @@ Diaspora::Application.routes.draw do resources :people, :only => [:index, :show, :destroy] - resources :users, :except => [:create, :new] + resources :users, :except => [:create, :new, :show] resources :status_messages, :only => [:create, :destroy, :show] resources :comments, :except => [:index] resources :requests, :except => [:edit, :update] diff --git a/config/sprinkle/conf/nginx.conf b/config/sprinkle/conf/nginx.conf index 2b3aa8a40..eba9fa45b 100644 --- a/config/sprinkle/conf/nginx.conf +++ b/config/sprinkle/conf/nginx.conf @@ -33,12 +33,14 @@ http { # gzip_disable "MSIE [1-6]\.(?!.*SV1)"; upstream thin_cluster { server unix:/tmp/thin.0.sock; + server unix:/tmp/thin.1.sock; + server unix:/tmp/thin.2.sock; } server { listen 80; - server_name babycakes.sofaer.net www.babycakes.sofaer.net; + server_name pivots.joindiaspora.com www.pivots.joindiaspora.com; root /usr/local/app/diaspora/current; location / { diff --git a/config/sprinkle/provision.rb b/config/sprinkle/provision.rb index ce0fd7374..fc81b1ca3 100644 --- a/config/sprinkle/provision.rb +++ b/config/sprinkle/provision.rb @@ -13,7 +13,7 @@ require '#{File.dirname(__FILE__)}/packages/server' require '#{File.dirname(__FILE__)}/packages/scm' require '#{File.dirname(__FILE__)}/packages/ruby' -policy :diaspora, :roles => [:tom,:backer] do +policy :diaspora, :roles => [:pivots] do # requires :clean_dreamhost requires :tools requires :rubygems diff --git a/config/thin.yml b/config/thin.yml index cc071975d..6a00fdb6c 100644 --- a/config/thin.yml +++ b/config/thin.yml @@ -13,9 +13,9 @@ max_conns: 1024 require: [] max_persistent_conns: 512 -environment: development -servers: 1 +environment: production +servers: 3 daemonize: true #chdir: /usr/applications/localhash/current -#socket: /tmp/thin.sock -port: 80 +socket: /tmp/thin.sock +#port: 80 diff --git a/db/seeds/tom.rb b/db/seeds/tom.rb index af6f737a9..2e06913f2 100644 --- a/db/seeds/tom.rb +++ b/db/seeds/tom.rb @@ -7,6 +7,7 @@ require 'config/environment' remote_url = "http://tom.joindiaspora.com/" +remote_url = "http://localhost:3000/" # Create seed user user = User.instantiate!( :email => "tom@tom.joindiaspora.com", :username => "tom", diff --git a/lib/diaspora/websocket.rb b/lib/diaspora/websocket.rb index fc79559f6..687bd2b7c 100644 --- a/lib/diaspora/websocket.rb +++ b/lib/diaspora/websocket.rb @@ -6,6 +6,11 @@ module Diaspora module WebSocket + def self.queue_to_user(uid, data) + channel = Magent::GenericChannel.new('websocket') + channel.enqueue({:uid => uid, :data => data}) + end + def self.initialize_channels @channels = {} end @@ -44,6 +49,5 @@ module Diaspora def unsocket_from_uid(id, opts={}) SocketsController.new.outgoing(id, Retraction.for(self), opts) end - end end diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 22f995325..80e3bafe5 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -63,6 +63,7 @@ namespace :db do return this.diaspora_handle.charAt(this.diaspora_handle.length-1) == '@' }") + puts "Found #{people.count} people with broken diaspora_handle fields" people.each do |person| if person.owner puts "Resetting diaspora handle for #{person.owner.username}" diff --git a/script/server b/script/server new file mode 100755 index 000000000..0094482b1 --- /dev/null +++ b/script/server @@ -0,0 +1,5 @@ +#!/bin/bash + +mkdir -p -v log/thin/ +bundle exec ruby ./script/websocket_server.rb& +bundle exec thin start $@ diff --git a/script/websocket_server.rb b/script/websocket_server.rb new file mode 100644 index 000000000..2fbc1370a --- /dev/null +++ b/script/websocket_server.rb @@ -0,0 +1,48 @@ +# Copyright (c) 2010, Diaspora Inc. This file is +# licensed under the Affero General Public License version 3. See +# the COPYRIGHT file. + +require File.dirname(__FILE__) + '/../config/environment' +require File.dirname(__FILE__) + '/../lib/diaspora/websocket' + +CHANNEL = Magent::GenericChannel.new('websocket') +def process_message + if CHANNEL.queue_count > 0 + message = CHANNEL.dequeue + if message + Diaspora::WebSocket.push_to_user(message['uid'], message['data']) + end + EM.next_tick{ process_message} + else + EM::Timer.new(1){process_message} + end + +end + +begin + EM.run { + Diaspora::WebSocket.initialize_channels + + EventMachine::WebSocket.start( + :host => "0.0.0.0", + :port => APP_CONFIG[:socket_port], + :debug =>APP_CONFIG[:socket_debug]) do |ws| + ws.onopen { + + sid = Diaspora::WebSocket.subscribe(ws.request['Path'].gsub('/',''), ws) + + ws.onmessage { |msg| SocketsController.new.incoming(msg) } + + ws.onclose { Diaspora::WebSocket.unsubscribe(ws.request['Path'].gsub('/',''), sid) } + } + end + + puts "Websocket server started." + process_message + } +rescue RuntimeError => e + raise e unless e.message.include?("no acceptor") + puts "Are you sure the websocket server isn't already running?" + puts "Just start thin with bundle exec thin start." + Process.exit +end diff --git a/spec/factories.rb b/spec/factories.rb index 4c59631d8..c1dfcd50a 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -36,7 +36,7 @@ end Factory.define :user do |u| u.sequence(:username) {|n| "bob#{n}"} - u.sequence(:email) {|n| "bob#{n}@aol.com"} + u.sequence(:email) {|n| "bob#{n}@pivotallabs.com"} u.password "bluepin7" u.password_confirmation "bluepin7" u.person { |a| Factory.create(:person_with_user, :owner_id => a._id)} diff --git a/spec/lib/websocket_spec.rb b/spec/lib/websocket_spec.rb new file mode 100644 index 000000000..018f5020d --- /dev/null +++ b/spec/lib/websocket_spec.rb @@ -0,0 +1,37 @@ +# Copyright (c) 2010, Diaspora Inc. This file is +# licensed under the Affero General Public License version 3. See +# the COPYRIGHT file. + +require File.dirname(__FILE__) + '/../spec_helper' + +describe Diaspora::WebSocket do + before do + @user = Factory.create(:user) + @aspect = @user.aspect(:name => "losers") + @post = @user.build_post(:status_message, :message => "hey", :to => @aspect.id) + unstub_sockets + end + + it 'should queue a job' do + Diaspora::WebSocket.should_receive(:queue_to_user) + @post.socket_to_uid(@user.id, :aspect_ids => @aspect.id) + end + + describe 'queuing and dequeuing ' do + before do + @post.socket_to_uid(@user.id, :aspect_ids => @aspect.id) + @channel = Magent::GenericChannel.new('websocket') + end + + it 'should send the queued job to Magent' do + @channel.message_count.should == 1 + end + + it 'should dequeue the job successfully' do + messages = @channel.message_count + @channel.dequeue + @channel.message_count.should == messages -1 + end + end + +end diff --git a/spec/models/album_spec.rb b/spec/models/album_spec.rb index 189361622..ed13ba102 100644 --- a/spec/models/album_spec.rb +++ b/spec/models/album_spec.rb @@ -2,87 +2,81 @@ # licensed under the Affero General Public License version 3. See # the COPYRIGHT file. - - -require File.dirname(__FILE__) + '/../spec_helper' +require 'spec_helper' describe Album do - before do - @fixture_name = File.dirname(__FILE__) + '/../fixtures/button.png' - @user = Factory.create(:user) - @user.person.save - @aspect = @user.aspect(:name => "Foo") - @album = @user.post(:album, :name => "test collection", :to => @aspect.id) + let(:user) { Factory.create(:user) } + let(:person) { user.person } + let(:aspect) { user.aspect(:name => "Foo") } + let(:album) { user.post(:album, :name => "test collection", :to => aspect.id) } + + it 'is valid' do + album.should be_valid end - it 'should require a name' do - @album.name = "test collection" - @album.valid?.should be true - - @album.name = nil - @album.valid?.should be false + it 'validates presence of a name' do + album.name = nil + album.should_not be_valid end - it 'should contain photos' do - photo = Factory.build(:photo, :person => @user.person) - - @album.photos << photo - @album.photos.count.should == 1 + it 'has many photos' do + album.associations[:photos].type == :many end - it 'should remove all photos on album delete' do - photos = [] - 1.upto 3 do - photo = Photo.new(:person => @user.person, :album => @album, :created_at => Time.now) - photo.image.store! File.open @fixture_name - photos << photo - end - @album.photos += photos - - Photo.all.count.should == 3 - @album.destroy - Photo.all.count.should == 0 - end - - describe 'traversing' do + context 'when an album has two attached images' do before do - @photos = [] - 1.upto 3 do |n| - photo = Photo.new(:person => @user.person, :album => @album, :created_at => Time.now + n) - photo.image.store! File.open @fixture_name - @photos << photo + 2.times do + photo = Factory.build(:photo, :person => person, :album => album) + album.photos << photo end - @album.photos += @photos end - it 'should traverse the album correctly' do - #should retrieve the next photo relative to a given photo - @album.next_photo(@photos[1]).id.should == @photos[2].id - - #should retrieve the previous photo relative to a given photo - @album.prev_photo(@photos[1]).id.should == @photos[0].id - - #wrapping - #does next photo of last to first - @album.next_photo(@photos[2]).id.should == @photos[0].id - - #does previous photo of first to last - @album.prev_photo(@photos[0]).id.should == @photos[2].id + context 'when the album is deleted' do + it 'removes all child photos' do + expect{ album.destroy }.to change(Photo, :count).from(2).to(0) + end end end - describe 'serialization' do - before do - @xml = @album.to_xml.to_s + context 'traversing photos' do + let(:attrs) { {:person => person, :album => album} } + let!(:photo_1) { Factory(:photo, attrs.merge(:created_at => 2.days.ago)) } + let!(:photo_2) { Factory(:photo, attrs.merge(:created_at => 1.day.ago)) } + let!(:photo_3) { Factory(:photo, attrs.merge(:created_at => Time.now)) } + + describe '#next_photo' do + it 'returns the next photo' do + album.next_photo(photo_1).id.should == photo_2.id + end + + it 'returns the first photo when given the last photo in the album' do + album.next_photo(photo_3).id.should == photo_1.id + end end - it 'should have a person' do - @xml.include?(@album.person.id.to_s).should be true + + describe '#prev_photo' do + it 'returns the previous photo' do + album.prev_photo(photo_2).id.should == photo_1.id + end + + it 'returns the last photo when given the first photo in the album' do + album.prev_photo(photo_1).id.should == photo_3.id + end end - it 'should have a name' do - @xml.include?(@album.name).should be true + end + + describe '#to_xml' do + let(:doc) { album.to_xml } + it 'has a name' do + doc.at_xpath('./name').text.should == album.name end - it 'should have an id' do - @xml.include?(@album.id.to_s).should be true + + it 'has an id' do + doc.at_xpath('./_id').text.should == album.id.to_s + end + + it 'includes the person' do + doc.at_xpath('./person/_id').text.should == album.person.id.to_s end end end diff --git a/spec/models/request_spec.rb b/spec/models/request_spec.rb index 72a3b8dc1..5899cb7fb 100644 --- a/spec/models/request_spec.rb +++ b/spec/models/request_spec.rb @@ -19,8 +19,7 @@ describe Request do person_request.valid?.should be true end - it 'should generate xml for the User as a Person' do - + it 'should generate xml for the User as a Person' do request = @user.send_friend_request_to Factory.create(:person), @aspect xml = request.to_xml.to_s diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6e8355021..223881671 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -11,6 +11,15 @@ describe User do @user = Factory.create(:user) @aspect = @user.aspect(:name => 'heroes') end + + it 'should create with pivotal or allowed emails' do + user1 = Factory.create(:user, :email => "kimfuh@yahoo.com") + user2 = Factory.create(:user, :email => "awesome@sofaer.net") + user3 = Factory.create(:user, :email => "steveellis@pivotallabs.com") + user1.created_at.nil?.should be false + user2.created_at.nil?.should be false + user3.created_at.nil?.should be false + end describe 'profiles' do it 'should be able to update their profile and send it to their friends' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9d6317d30..3fdac9810 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -38,6 +38,7 @@ RSpec.configure do |config| config.before(:each) do DatabaseCleaner.start stub_sockets + User.stub!(:allowed_email?).and_return(:true) end config.after(:each) do @@ -45,11 +46,17 @@ RSpec.configure do |config| end end def stub_sockets - Diaspora::WebSocket.stub!(:push_to_user).and_return(true) + Diaspora::WebSocket.stub!(:queue_to_user).and_return(true) Diaspora::WebSocket.stub!(:subscribe).and_return(true) Diaspora::WebSocket.stub!(:unsubscribe).and_return(true) end + def unstub_sockets + Diaspora::WebSocket.unstub!(:queue_to_user) + Diaspora::WebSocket.unstub!(:subscribe) + Diaspora::WebSocket.unstub!(:unsubscribe) + end + def stub_signature_verification (get_models.map{|model| model.camelize.constantize} - [User]).each do |model| model.any_instance.stubs(:verify_signature).returns(true)