tekeya 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/.document +0 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +3 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +39 -0
  6. data/Guardfile +40 -0
  7. data/LICENSE +22 -0
  8. data/README.md +37 -0
  9. data/Rakefile +13 -0
  10. data/TODO.todo +8 -0
  11. data/app/active_record/tekeya/activity.rb +7 -0
  12. data/app/active_record/tekeya/attachment.rb +5 -0
  13. data/app/active_record/tekeya/notification.rb +5 -0
  14. data/app/mongoid/tekeya/activity.rb +9 -0
  15. data/app/mongoid/tekeya/attachment.rb +6 -0
  16. data/app/mongoid/tekeya/notification.rb +10 -0
  17. data/db/migrate/00_create_activities.rb +11 -0
  18. data/db/migrate/01_create_attachments.rb +13 -0
  19. data/db/migrate/02_create_notifications.rb +14 -0
  20. data/lib/tasks/resque_tasks.rake +3 -0
  21. data/lib/tekeya.rb +81 -0
  22. data/lib/tekeya/configuration.rb +48 -0
  23. data/lib/tekeya/entity.rb +432 -0
  24. data/lib/tekeya/entity/group.rb +22 -0
  25. data/lib/tekeya/errors/tekeya_error.rb +11 -0
  26. data/lib/tekeya/errors/tekeya_fatal.rb +11 -0
  27. data/lib/tekeya/errors/tekeya_non_entity.rb +6 -0
  28. data/lib/tekeya/errors/tekeya_non_group.rb +6 -0
  29. data/lib/tekeya/errors/tekeya_relation_already_exists.rb +6 -0
  30. data/lib/tekeya/errors/tekeya_relation_non_existent.rb +6 -0
  31. data/lib/tekeya/feed/activity.rb +101 -0
  32. data/lib/tekeya/feed/activity/feed_item.rb +58 -0
  33. data/lib/tekeya/feed/activity/resque.rb +56 -0
  34. data/lib/tekeya/feed/activity/resque/activity_fanout.rb +61 -0
  35. data/lib/tekeya/feed/activity/resque/delete_activity.rb +43 -0
  36. data/lib/tekeya/feed/activity/resque/feed_copy.rb +34 -0
  37. data/lib/tekeya/feed/activity/resque/untrack_feed.rb +34 -0
  38. data/lib/tekeya/feed/attachable.rb +15 -0
  39. data/lib/tekeya/feed/attachment.rb +19 -0
  40. data/lib/tekeya/feed/notification.rb +93 -0
  41. data/lib/tekeya/railtie.rb +18 -0
  42. data/lib/tekeya/version.rb +3 -0
  43. data/spec/fabricators/attachment_fabricator.rb +3 -0
  44. data/spec/fabricators/group_fabricator.rb +4 -0
  45. data/spec/fabricators/status_fabricator.rb +3 -0
  46. data/spec/fabricators/user_fabricator.rb +3 -0
  47. data/spec/orm/active_record.rb +14 -0
  48. data/spec/orm/mongoid.rb +6 -0
  49. data/spec/rails_app/Rakefile +7 -0
  50. data/spec/rails_app/app/active_record/group.rb +3 -0
  51. data/spec/rails_app/app/active_record/status.rb +3 -0
  52. data/spec/rails_app/app/active_record/user.rb +3 -0
  53. data/spec/rails_app/app/controllers/application_controller.rb +3 -0
  54. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  55. data/spec/rails_app/app/mongoid/group.rb +6 -0
  56. data/spec/rails_app/app/mongoid/status.rb +6 -0
  57. data/spec/rails_app/app/mongoid/user.rb +7 -0
  58. data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
  59. data/spec/rails_app/config.ru +4 -0
  60. data/spec/rails_app/config/application.rb +35 -0
  61. data/spec/rails_app/config/boot.rb +8 -0
  62. data/spec/rails_app/config/database.yml +21 -0
  63. data/spec/rails_app/config/environment.rb +5 -0
  64. data/spec/rails_app/config/environments/development.rb +18 -0
  65. data/spec/rails_app/config/environments/production.rb +33 -0
  66. data/spec/rails_app/config/environments/test.rb +33 -0
  67. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/rails_app/config/initializers/configure_mongoid.rb +6 -0
  69. data/spec/rails_app/config/initializers/inflections.rb +15 -0
  70. data/spec/rails_app/config/initializers/resque.rb +1 -0
  71. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  72. data/spec/rails_app/config/locales/en.yml +5 -0
  73. data/spec/rails_app/config/routes.rb +58 -0
  74. data/spec/rails_app/db/migrate/100_create_users.rb +9 -0
  75. data/spec/rails_app/db/migrate/101_create_groups.rb +11 -0
  76. data/spec/rails_app/db/migrate/102_create_statuses.rb +9 -0
  77. data/spec/rails_app/db/seeds.rb +7 -0
  78. data/spec/rails_app/public/404.html +26 -0
  79. data/spec/rails_app/public/422.html +26 -0
  80. data/spec/rails_app/public/500.html +25 -0
  81. data/spec/rails_app/public/favicon.ico +0 -0
  82. data/spec/rails_app/public/index.html +241 -0
  83. data/spec/rails_app/public/robots.txt +5 -0
  84. data/spec/rails_app/script/rails +6 -0
  85. data/spec/spec_helper.rb +78 -0
  86. data/spec/tekeya/activity_spec.rb +170 -0
  87. data/spec/tekeya/entity_spec.rb +158 -0
  88. data/spec/tekeya/notification_spec.rb +49 -0
  89. data/spec/tekeya_helper.rb +7 -0
  90. data/spec/tekeya_spec.rb +51 -0
  91. data/tekeya.gemspec +22 -0
  92. metadata +231 -0
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,78 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ end
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+
9
+ ENV["RAILS_ENV"] = "test"
10
+ TEKEYA_ORM = (ENV["TEKEYA_ORM"] || :active_record).to_sym
11
+
12
+ require 'rspec'
13
+ require 'tekeya'
14
+ require 'bundler'
15
+
16
+ Bundler.require :default, :development, :test
17
+
18
+ require 'database_cleaner'
19
+ require "#{File.dirname(__FILE__)}/tekeya_helper"
20
+ require "#{File.dirname(__FILE__)}/../lib/tekeya"
21
+ require "#{File.dirname(__FILE__)}/rails_app/config/environment"
22
+ require "#{File.dirname(__FILE__)}/orm/#{TEKEYA_ORM}"
23
+
24
+ # Requires supporting files with custom matchers and macros, etc,
25
+ # in ./support/ and its subdirectories.
26
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
27
+
28
+ RSpec.configure do |config|
29
+ Fabrication.configure do |config|
30
+ config.fabricator_path = 'fabricators'
31
+ config.path_prefix = File.dirname(__FILE__)
32
+ end
33
+
34
+ config.before(:each) do
35
+ DatabaseCleaner.clean
36
+ end
37
+
38
+ config.after(:each) do
39
+ Tekeya.relations.truncate
40
+ Tekeya.redis.flushall
41
+ end
42
+
43
+ config.before(:all) do
44
+ %w(tmp tmp/pids tmp/cache).each do |path|
45
+ FileUtils.mkdir_p "#{Dir.pwd}/#{path}"
46
+ end
47
+ end
48
+
49
+ REDIS_PID = File.join(File.dirname(__FILE__), '..', 'tmp','pids','redis-test.pid')
50
+ REDIS_CACHE_PATH = File.join(File.dirname(__FILE__), '..', 'tmp','cache')
51
+
52
+ config.before(:suite) do
53
+ redis_options = {
54
+ "daemonize" => 'yes',
55
+ "pidfile" => REDIS_PID,
56
+ "port" => 9736,
57
+ "timeout" => 300,
58
+ "save 900" => 1,
59
+ "save 300" => 1,
60
+ "save 60" => 10000,
61
+ "dbfilename" => "dump.rdb",
62
+ "dir" => REDIS_CACHE_PATH,
63
+ "loglevel" => "debug",
64
+ "logfile" => "stdout",
65
+ "databases" => 16
66
+ }.map { |k, v| "#{k} #{v}" }.join('\n')
67
+ `echo '#{redis_options}' | redis-server -`
68
+ end
69
+
70
+ config.after(:suite) do
71
+ %x{
72
+ cat #{REDIS_PID} | xargs kill -QUIT
73
+ rm -f #{REDIS_CACHE_PATH}dump.rdb
74
+ }
75
+
76
+ FileUtils.rm_r "#{File.dirname(__FILE__)}/rails_app/db/test.sqlite3" rescue nil
77
+ end
78
+ end
@@ -0,0 +1,170 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Tekeya" do
4
+ describe "Activity" do
5
+ before :each do
6
+ @user = Fabricate(:user)
7
+ @user2 = Fabricate(:user)
8
+ @user3 = Fabricate(:user)
9
+
10
+ @user2.track(@user)
11
+ @user3.track(@user)
12
+
13
+ # Normal Activities (1 & 2 should be grouped)
14
+ @act1 = @user.activities.liked Fabricate(:status), Fabricate(:status)
15
+ @act2 = @user.activities.liked Fabricate(:status)
16
+ @act3 = @user.activities.shared Fabricate(:status)
17
+
18
+ # Created after the grouping interval
19
+ @act4 = @user.activities.new activity_type: :liked, attachments: [Fabricate.build(:attachment)]
20
+ @act4.stub(:current_time_from_proper_timezone => @act1.created_at + 20.minutes)
21
+ @act4.save!
22
+
23
+ # Manually not grouped
24
+ @act5 = @user.activities.liked Fabricate(:status), group: false
25
+ end
26
+
27
+ it "should return the same aggregate key" do
28
+ @act1.activity_key.should == @act2.activity_key
29
+ end
30
+
31
+ it "should return different aggregate keys" do
32
+ @act1.activity_key.should_not == @act3.activity_key
33
+ end
34
+
35
+ it "should create an aggregate in redis" do
36
+ @act1.cached_in_redis?.should == true
37
+ @act2.cached_in_redis?.should == true
38
+ @act3.cached_in_redis?.should == true
39
+ @act4.cached_in_redis?.should == true
40
+ @act5.cached_in_redis?.should == true
41
+ end
42
+
43
+ it "should add the activity to the owner's profile feed and group activities of the same type within 15 min" do
44
+ id_array = @user.profile_feed.map(&:activity_id)
45
+ id_array.include?(@act1.id.to_s).should == true
46
+ id_array.include?(@act3.id.to_s).should == true
47
+ id_array.include?(@act4.id.to_s).should == true
48
+ id_array.include?(@act5.id.to_s).should == true
49
+ end
50
+
51
+ it "should not save the activity in the DB if its grouped with another" do
52
+ @act2.persisted?.should_not == true
53
+ end
54
+
55
+ it "should save the activity's attachments in the parent activity if its grouped" do
56
+ @act1.reload
57
+ (@act1.attachments & @act2.attachments).should == @act2.attachments
58
+ end
59
+
60
+ it "should fanout activities to the entity's trackers" do
61
+ id_array = (@user2.feed.map(&:activity_id) + @user3.feed.map(&:activity_id)).uniq
62
+ id_array.include?(@act1.id.to_s).should == true
63
+ id_array.include?(@act3.id.to_s).should == true
64
+ id_array.include?(@act4.id.to_s).should == true
65
+ id_array.include?(@act5.id.to_s).should == true
66
+ end
67
+
68
+ describe "invalid profile feed cache" do
69
+ it "should return profile activities from the DB when the profile cache is empty" do
70
+ ::Tekeya.redis.del(@user.profile_feed_key)
71
+ ::Tekeya.redis.del(@act1.activity_key)
72
+ ::Tekeya.redis.del(@act3.activity_key)
73
+ ::Tekeya.redis.del(@act4.activity_key)
74
+ ::Tekeya.redis.del(@act5.activity_key)
75
+
76
+ @act1.cached_in_redis?.should == false
77
+ @act3.cached_in_redis?.should == false
78
+ @act4.cached_in_redis?.should == false
79
+ @act5.cached_in_redis?.should == false
80
+
81
+ id_array = @user.profile_feed.map(&:activity_id)
82
+ id_array.include?(@act1.id.to_s).should == true
83
+ id_array.include?(@act3.id.to_s).should == true
84
+ id_array.include?(@act4.id.to_s).should == true
85
+ id_array.include?(@act5.id.to_s).should == true
86
+ end
87
+ end
88
+
89
+ describe "invalid feed cache" do
90
+ it "should return feed activities from the DB when the feed cache is empty" do
91
+ ::Tekeya.redis.del(@user2.feed_key)
92
+ ::Tekeya.redis.del(@user3.feed_key)
93
+
94
+ ::Tekeya.redis.zcard(@user2.feed_key).should == 0
95
+ ::Tekeya.redis.zcard(@user3.feed_key).should == 0
96
+
97
+ @user2.feed.count == 4
98
+ @user3.feed.count == 4
99
+ end
100
+ end
101
+
102
+ describe "activity deletion" do
103
+ before :each do
104
+ @act1.destroy
105
+ @act3.destroy
106
+ @act4.destroy
107
+ @act5.destroy
108
+ end
109
+
110
+ it "should remove the activity from the cache when its deleted from the db" do
111
+ @act1.cached_in_redis?.should_not == true
112
+ @act3.cached_in_redis?.should_not == true
113
+ @act4.cached_in_redis?.should_not == true
114
+ @act5.cached_in_redis?.should_not == true
115
+ end
116
+
117
+ it "should remove the activity from the profile cache when its deleted from the db" do
118
+ id_array = @user.profile_feed.map(&:activity_id)
119
+ id_array.include?(@act1.id.to_s).should_not == true
120
+ id_array.include?(@act3.id.to_s).should_not == true
121
+ id_array.include?(@act4.id.to_s).should_not == true
122
+ id_array.include?(@act5.id.to_s).should_not == true
123
+ end
124
+
125
+ it "should remove the activity from the trackers' feed when its deleted from the db" do
126
+ id_array = (@user2.feed.map(&:activity_id) + @user3.feed.map(&:activity_id)).uniq
127
+ id_array.include?(@act1.id.to_s).should_not == true
128
+ id_array.include?(@act3.id.to_s).should_not == true
129
+ id_array.include?(@act4.id.to_s).should_not == true
130
+ id_array.include?(@act5.id.to_s).should_not == true
131
+ end
132
+ end
133
+
134
+ describe "untracking" do
135
+ before :each do
136
+ @user2.untrack(@user)
137
+ end
138
+
139
+ it "should remove the feed of the untracked entity from the tracker's cache" do
140
+ id_array = @user2.feed.map(&:activity_id)
141
+ id_array.include?(@act1.id.to_s).should_not == true
142
+ id_array.include?(@act3.id.to_s).should_not == true
143
+ id_array.include?(@act4.id.to_s).should_not == true
144
+ id_array.include?(@act5.id.to_s).should_not == true
145
+
146
+ id_array = @user3.feed.map(&:activity_id)
147
+ id_array.include?(@act1.id.to_s).should == true
148
+ id_array.include?(@act3.id.to_s).should == true
149
+ id_array.include?(@act4.id.to_s).should == true
150
+ id_array.include?(@act5.id.to_s).should == true
151
+ end
152
+ end
153
+
154
+ describe "tracking" do
155
+ before :each do
156
+ @user4 = Fabricate(:user)
157
+
158
+ @user4.track(@user)
159
+ end
160
+
161
+ it "should copy the feed of the tracked entity into the tracker's feed" do
162
+ id_array = @user4.feed.map(&:activity_id)
163
+ id_array.include?(@act1.id.to_s).should == true
164
+ id_array.include?(@act3.id.to_s).should == true
165
+ id_array.include?(@act4.id.to_s).should == true
166
+ id_array.include?(@act5.id.to_s).should == true
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,158 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Tekeya" do
4
+ describe "Entity" do
5
+ before :each do
6
+ @user = Fabricate(:user)
7
+ @user2 = Fabricate(:user)
8
+ @group = Fabricate(:group)
9
+ end
10
+
11
+ it "should inherit all the relations and feed methods" do
12
+ # Public methods
13
+ User.method_defined?(:track).should == true
14
+ User.method_defined?(:tracking).should == true
15
+ User.method_defined?(:"tracks?").should == true
16
+ User.method_defined?(:untrack).should == true
17
+ User.method_defined?(:block).should == true
18
+ User.method_defined?(:blocked).should == true
19
+ User.method_defined?(:"blocks?").should == true
20
+ User.method_defined?(:unblock).should == true
21
+ User.method_defined?(:join).should == true
22
+ User.method_defined?(:groups).should == true
23
+ User.method_defined?(:"member_of?").should == true
24
+ User.method_defined?(:leave).should == true
25
+ User.method_defined?(:profile_feed).should == true
26
+ User.method_defined?(:feed).should == true
27
+ User.method_defined?(:profile_feed_key).should == true
28
+ User.method_defined?(:feed_key).should == true
29
+ # Private methods
30
+ User.private_method_defined?(:add_tekeya_relation).should == true
31
+ User.private_method_defined?(:delete_tekeya_relation).should == true
32
+ User.private_method_defined?(:tekeya_relations_of).should == true
33
+ User.private_method_defined?(:"tekeya_relation_exists?").should == true
34
+ end
35
+
36
+ describe "errors" do
37
+ it "should raise a non entity error when tracking or blocking a non entity" do
38
+ expect { @user.track(nil) }.to raise_error(Tekeya::Errors::TekeyaNonEntity)
39
+ expect { @user.block(nil) }.to raise_error(Tekeya::Errors::TekeyaNonEntity)
40
+ end
41
+
42
+ it "should raise a non group error if a non group is given when joining a non group" do
43
+ expect { @user.join(nil) }.to raise_error(Tekeya::Errors::TekeyaNonGroup)
44
+ end
45
+
46
+ it "should raise a relation already exists error when tracking, blocking or joining an already tracked, blocked or joined entity/group" do
47
+ @user.track(@user2)
48
+ expect { @user.track(@user2) }.to raise_error(Tekeya::Errors::TekeyaRelationAlreadyExists)
49
+ @user.block(@user2)
50
+ expect { @user.block(@user2) }.to raise_error(Tekeya::Errors::TekeyaRelationAlreadyExists)
51
+ @user.join(@group)
52
+ expect { @user.join(@group) }.to raise_error(Tekeya::Errors::TekeyaRelationAlreadyExists)
53
+ end
54
+
55
+ it "should raise a relation non existent error when untracking, unblocking or leaving an untracked, unblocked or unjoined entity/group" do
56
+ expect { @user.untrack(@user2) }.to raise_error(Tekeya::Errors::TekeyaRelationNonExistent)
57
+ expect { @user.unblock(@user2) }.to raise_error(Tekeya::Errors::TekeyaRelationNonExistent)
58
+ expect { @user.leave(@group) }.to raise_error(Tekeya::Errors::TekeyaRelationNonExistent)
59
+ end
60
+ end
61
+
62
+ describe "relations" do
63
+ it "should track another entity" do
64
+ @user.track(@user2).should == true
65
+ @user.tracks?(@user2).should == true
66
+ end
67
+
68
+ it "should untrack a tracked entity" do
69
+ @user.track(@user2)
70
+ @user.untrack(@user2).should == true
71
+ @user.tracks?(@user2).should_not == true
72
+ end
73
+
74
+ it "should block another entity/group" do
75
+ @user.block(@user2).should == true
76
+ @user.blocks?(@user2).should == true
77
+ @user.block(@group).should == true
78
+ @user.blocks?(@group).should == true
79
+ end
80
+
81
+ it "should unblock a blocked entity/group" do
82
+ @user.block(@user2)
83
+ @user.unblock(@user2).should == true
84
+ @user.blocks?(@user2).should_not == true
85
+
86
+ @user.block(@group)
87
+ @user.unblock(@group).should == true
88
+ @user.blocks?(@group).should_not == true
89
+ end
90
+
91
+ it "should join a group" do
92
+ @user.join(@group).should == true
93
+ @user.member_of?(@group).should == true
94
+ end
95
+
96
+ it "should leave a group" do
97
+ @user.join(@group)
98
+ @user.leave(@group).should == true
99
+ @user.member_of?(@group).should_not == true
100
+ end
101
+
102
+ describe "retrieval" do
103
+ before :each do
104
+ @user3 = Fabricate(:user)
105
+ @user.track(@user2)
106
+ @user.block(@user3)
107
+ @user.join(@group)
108
+ @user2.join(@group)
109
+ @user3.join(@group)
110
+ end
111
+
112
+ it "should return tracked entities" do
113
+ @user.tracking.include?(@user2).should == true
114
+ end
115
+
116
+ it "should return trackers" do
117
+ @user2.trackers.include?(@user).should == true
118
+ end
119
+
120
+ it "should return blocked entities" do
121
+ @user.blocked.include?(@user3).should == true
122
+ end
123
+
124
+ it "should return joined groups" do
125
+ @user.groups.include?(@group).should == true
126
+ end
127
+
128
+ it "should return group members" do
129
+ @group.members.should == [@user, @user2, @user3]
130
+ end
131
+ end
132
+
133
+ describe "blocking entities" do
134
+ it "should remove the tracking relation if it exists" do
135
+ @user.track(@user2)
136
+ @user2.track(@user)
137
+ @user.block(@user2)
138
+
139
+ @user.tracks?(@user2).should_not == true
140
+ @user2.tracks?(@user).should_not == true
141
+ end
142
+ end
143
+
144
+ describe "groups" do
145
+ it "should track the group automatically when an entity joins" do
146
+ @user.join(@group)
147
+ @user.tracks?(@group).should == true
148
+ end
149
+
150
+ it "should untrack the group automatically when an entity leaves" do
151
+ @user.join(@group)
152
+ @user.leave(@group)
153
+ @user.tracks?(@group).should_not == true
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Tekeya" do
4
+ describe "Notification" do
5
+ before :each do
6
+ @user = Fabricate(:user)
7
+ @user1 = Fabricate(:user)
8
+ end
9
+
10
+ describe "DSL" do
11
+ before :each do
12
+ @user1.track @user
13
+ @user.notifications.poked_by @user1
14
+
15
+ @user2 = Fabricate(:user)
16
+ @user3 = Fabricate(:user)
17
+ @user4 = Fabricate(:user)
18
+
19
+ @status = Fabricate(:status)
20
+ end
21
+
22
+ it "should notify the entity with the proper notification data" do
23
+ tracked_notification = @user.notifications.first
24
+
25
+ tracked_notification.notification_type.should == "tracked_by"
26
+ tracked_notification.subject.should == @user
27
+ tracked_notification.actors.map(&:attachable_id).include?(@user1.id).should == true
28
+
29
+ poked_notification = @user.notifications.last
30
+
31
+ poked_notification.notification_type.should == "poked_by"
32
+ poked_notification.subject.should == @user
33
+ poked_notification.actors.map(&:attachable_id).include?(@user1.id).should == true
34
+ end
35
+
36
+ it "should notify multiple entities" do
37
+ Tekeya::Notification.notify! [@user2, @user3, @user4], :posted, @status, @user
38
+
39
+ ((@user2.notifications == @user3.notifications) == (@user4.notifications == 1)).should == true
40
+ end
41
+
42
+ it "should return unread notifications correctly" do
43
+ @user.notifications.first.read!
44
+ @user.notifications.unread.count.should == 1
45
+ end
46
+ end
47
+
48
+ end
49
+ end