vines 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/LICENSE +19 -0
  2. data/README +34 -0
  3. data/Rakefile +55 -0
  4. data/bin/vines +95 -0
  5. data/conf/certs/README +32 -0
  6. data/conf/certs/ca-bundle.crt +3987 -0
  7. data/conf/config.rb +114 -0
  8. data/lib/vines.rb +155 -0
  9. data/lib/vines/command/bcrypt.rb +12 -0
  10. data/lib/vines/command/cert.rb +49 -0
  11. data/lib/vines/command/init.rb +58 -0
  12. data/lib/vines/command/ldap.rb +35 -0
  13. data/lib/vines/command/restart.rb +12 -0
  14. data/lib/vines/command/schema.rb +24 -0
  15. data/lib/vines/command/start.rb +28 -0
  16. data/lib/vines/command/stop.rb +18 -0
  17. data/lib/vines/config.rb +191 -0
  18. data/lib/vines/contact.rb +99 -0
  19. data/lib/vines/daemon.rb +78 -0
  20. data/lib/vines/error.rb +150 -0
  21. data/lib/vines/jid.rb +56 -0
  22. data/lib/vines/kit.rb +23 -0
  23. data/lib/vines/router.rb +125 -0
  24. data/lib/vines/stanza.rb +55 -0
  25. data/lib/vines/stanza/iq.rb +50 -0
  26. data/lib/vines/stanza/iq/auth.rb +18 -0
  27. data/lib/vines/stanza/iq/disco_info.rb +25 -0
  28. data/lib/vines/stanza/iq/disco_items.rb +23 -0
  29. data/lib/vines/stanza/iq/error.rb +16 -0
  30. data/lib/vines/stanza/iq/ping.rb +16 -0
  31. data/lib/vines/stanza/iq/query.rb +10 -0
  32. data/lib/vines/stanza/iq/result.rb +16 -0
  33. data/lib/vines/stanza/iq/roster.rb +153 -0
  34. data/lib/vines/stanza/iq/session.rb +22 -0
  35. data/lib/vines/stanza/iq/vcard.rb +58 -0
  36. data/lib/vines/stanza/message.rb +41 -0
  37. data/lib/vines/stanza/presence.rb +119 -0
  38. data/lib/vines/stanza/presence/error.rb +23 -0
  39. data/lib/vines/stanza/presence/probe.rb +38 -0
  40. data/lib/vines/stanza/presence/subscribe.rb +66 -0
  41. data/lib/vines/stanza/presence/subscribed.rb +64 -0
  42. data/lib/vines/stanza/presence/unavailable.rb +15 -0
  43. data/lib/vines/stanza/presence/unsubscribe.rb +57 -0
  44. data/lib/vines/stanza/presence/unsubscribed.rb +50 -0
  45. data/lib/vines/storage.rb +216 -0
  46. data/lib/vines/storage/couchdb.rb +119 -0
  47. data/lib/vines/storage/ldap.rb +59 -0
  48. data/lib/vines/storage/local.rb +66 -0
  49. data/lib/vines/storage/redis.rb +108 -0
  50. data/lib/vines/storage/sql.rb +174 -0
  51. data/lib/vines/store.rb +51 -0
  52. data/lib/vines/stream.rb +198 -0
  53. data/lib/vines/stream/client.rb +131 -0
  54. data/lib/vines/stream/client/auth.rb +94 -0
  55. data/lib/vines/stream/client/auth_restart.rb +33 -0
  56. data/lib/vines/stream/client/bind.rb +58 -0
  57. data/lib/vines/stream/client/bind_restart.rb +25 -0
  58. data/lib/vines/stream/client/closed.rb +13 -0
  59. data/lib/vines/stream/client/ready.rb +15 -0
  60. data/lib/vines/stream/client/start.rb +27 -0
  61. data/lib/vines/stream/client/tls.rb +37 -0
  62. data/lib/vines/stream/component.rb +53 -0
  63. data/lib/vines/stream/component/handshake.rb +25 -0
  64. data/lib/vines/stream/component/ready.rb +24 -0
  65. data/lib/vines/stream/component/start.rb +19 -0
  66. data/lib/vines/stream/http.rb +111 -0
  67. data/lib/vines/stream/http/http_request.rb +22 -0
  68. data/lib/vines/stream/http/http_state.rb +139 -0
  69. data/lib/vines/stream/http/http_states.rb +53 -0
  70. data/lib/vines/stream/parser.rb +78 -0
  71. data/lib/vines/stream/server.rb +126 -0
  72. data/lib/vines/stream/server/auth.rb +13 -0
  73. data/lib/vines/stream/server/auth_restart.rb +19 -0
  74. data/lib/vines/stream/server/final_restart.rb +20 -0
  75. data/lib/vines/stream/server/outbound/auth.rb +31 -0
  76. data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
  77. data/lib/vines/stream/server/outbound/auth_result.rb +28 -0
  78. data/lib/vines/stream/server/outbound/final_features.rb +27 -0
  79. data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
  80. data/lib/vines/stream/server/outbound/start.rb +20 -0
  81. data/lib/vines/stream/server/outbound/tls.rb +30 -0
  82. data/lib/vines/stream/server/outbound/tls_result.rb +31 -0
  83. data/lib/vines/stream/server/ready.rb +20 -0
  84. data/lib/vines/stream/server/start.rb +13 -0
  85. data/lib/vines/stream/server/tls.rb +13 -0
  86. data/lib/vines/stream/state.rb +55 -0
  87. data/lib/vines/token_bucket.rb +46 -0
  88. data/lib/vines/user.rb +124 -0
  89. data/lib/vines/version.rb +5 -0
  90. data/lib/vines/xmpp_server.rb +25 -0
  91. data/test/config_test.rb +396 -0
  92. data/test/error_test.rb +59 -0
  93. data/test/ext/nokogiri.rb +14 -0
  94. data/test/jid_test.rb +71 -0
  95. data/test/kit_test.rb +21 -0
  96. data/test/router_test.rb +60 -0
  97. data/test/stanza/iq/roster_test.rb +198 -0
  98. data/test/stanza/iq/session_test.rb +30 -0
  99. data/test/stanza/iq/vcard_test.rb +159 -0
  100. data/test/stanza/message_test.rb +124 -0
  101. data/test/stanza/presence/subscribe_test.rb +75 -0
  102. data/test/storage/couchdb_test.rb +102 -0
  103. data/test/storage/ldap_test.rb +207 -0
  104. data/test/storage/local_test.rb +54 -0
  105. data/test/storage/redis_test.rb +75 -0
  106. data/test/storage/sql_test.rb +55 -0
  107. data/test/storage/storage_tests.rb +134 -0
  108. data/test/storage_test.rb +90 -0
  109. data/test/stream/client/auth_test.rb +127 -0
  110. data/test/stream/client/ready_test.rb +47 -0
  111. data/test/stream/component/handshake_test.rb +46 -0
  112. data/test/stream/component/ready_test.rb +105 -0
  113. data/test/stream/component/start_test.rb +41 -0
  114. data/test/stream/parser_test.rb +121 -0
  115. data/test/stream/server/outbound/auth_test.rb +77 -0
  116. data/test/stream/server/ready_test.rb +100 -0
  117. data/test/token_bucket_test.rb +24 -0
  118. data/test/user_test.rb +64 -0
  119. metadata +318 -0
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+
3
+ module Nokogiri
4
+ module XML
5
+ class Node
6
+ # Override equality testing so we can use MiniTest::Mock#expect with
7
+ # Nokogiri::XML::Node arguments. Node's default behavior considers
8
+ # all nodes unequal.
9
+ def ==(node)
10
+ self.to_s == node.to_s
11
+ end
12
+ end
13
+ end
14
+ end
data/test/jid_test.rb ADDED
@@ -0,0 +1,71 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'test/unit'
5
+
6
+ class JidTest < Test::Unit::TestCase
7
+ def test_nil_and_empty_jids
8
+ [nil, ''].each do |text|
9
+ assert_nothing_raised { Vines::JID.new(text) }
10
+ jid = Vines::JID.new(text)
11
+ assert_nil jid.node
12
+ assert_nil jid.resource
13
+ assert_equal '', jid.domain
14
+ assert_equal '', jid.to_s
15
+ assert_equal '', jid.bare.to_s
16
+ end
17
+ end
18
+
19
+ def test_jid_too_long_error
20
+ assert_nothing_raised { Vines::JID.new('n' * 1023) }
21
+ assert_raises(ArgumentError) { Vines::JID.new('n' * 1024) }
22
+ assert_raises(ArgumentError) { Vines::JID.new('n', 'd' * 1024) }
23
+ assert_raises(ArgumentError) { Vines::JID.new('n', 'd', 'r' * 1024) }
24
+ assert_nothing_raised { Vines::JID.new('n' * 1023, 'd' * 1023, 'r' * 1023) }
25
+ end
26
+
27
+ def test_domain_only
28
+ jid = Vines::JID.new('wonderland.lit')
29
+ assert_equal 'wonderland.lit', jid.to_s
30
+ assert_equal 'wonderland.lit', jid.domain
31
+ assert_nil jid.node
32
+ assert_nil jid.resource
33
+ assert_equal jid, jid.bare
34
+ end
35
+
36
+ def test_bare_jid
37
+ jid = Vines::JID.new('alice', 'wonderland.lit')
38
+ assert_equal 'alice@wonderland.lit', jid.to_s
39
+ assert_equal 'wonderland.lit', jid.domain
40
+ assert_equal 'alice', jid.node
41
+ assert_nil jid.resource
42
+ assert_equal jid, jid.bare
43
+ end
44
+
45
+ def test_parsed_bare_jid
46
+ jid = Vines::JID.new('alice@wonderland.lit')
47
+ assert_equal 'alice@wonderland.lit', jid.to_s
48
+ assert_equal 'wonderland.lit', jid.domain
49
+ assert_equal 'alice', jid.node
50
+ assert_nil jid.resource
51
+ assert_equal jid, jid.bare
52
+ end
53
+
54
+ def test_full_jid
55
+ jid = Vines::JID.new('alice', 'wonderland.lit', 'tea')
56
+ assert_equal 'alice@wonderland.lit/tea', jid.to_s
57
+ assert_equal 'wonderland.lit', jid.domain
58
+ assert_equal 'alice', jid.node
59
+ assert_equal 'tea', jid.resource
60
+ assert_not_equal jid, jid.bare
61
+ end
62
+
63
+ def test_parsed_full_jid
64
+ jid = Vines::JID.new('alice@wonderland.lit/tea')
65
+ assert_equal 'alice@wonderland.lit/tea', jid.to_s
66
+ assert_equal 'wonderland.lit', jid.domain
67
+ assert_equal 'alice', jid.node
68
+ assert_equal 'tea', jid.resource
69
+ assert_not_equal jid, jid.bare
70
+ end
71
+ end
data/test/kit_test.rb ADDED
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'test/unit'
5
+
6
+ class KitTest < Test::Unit::TestCase
7
+ def test_hmac
8
+ assert_equal(128, Vines::Kit.hmac('secret', 'username').length)
9
+ assert_equal(Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s1', 'u1'))
10
+ assert_not_equal(Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s2', 'u1'))
11
+ assert_not_equal(Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s1', 'u2'))
12
+ end
13
+
14
+ def test_uuid
15
+ ids = Array.new(1000) { Vines::Kit.uuid }
16
+ assert(ids.all? {|id| !id.nil? })
17
+ assert(ids.all? {|id| id.length == 36 })
18
+ assert(ids.all? {|id| id.match(/\w{8}-\w{4}-[4]\w{3}-[89ab]\w{3}-\w{12}/) })
19
+ assert_equal(ids.length, ids.uniq.length)
20
+ end
21
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'minitest/mock'
5
+ require 'test/unit'
6
+
7
+ class RouterTest < Test::Unit::TestCase
8
+ def setup
9
+ @router = Vines::Router.new
10
+ end
11
+
12
+ def test_non_routable_stanza_is_local
13
+ stanza = MiniTest::Mock.new
14
+ stanza.expect(:name, 'auth')
15
+ assert @router.local?(stanza)
16
+ assert stanza.verify
17
+ end
18
+
19
+ def test_stanza_missing_to_is_local
20
+ stanza = MiniTest::Mock.new
21
+ stanza.expect(:name, 'message')
22
+ stanza.expect(:[], nil, ['to'])
23
+ assert @router.local?(stanza)
24
+ assert stanza.verify
25
+ end
26
+
27
+ def test_stanza_with_local_jid_is_local
28
+ config = MiniTest::Mock.new
29
+ config.expect(:vhost?, true, ['wonderland.lit'])
30
+ stream = MiniTest::Mock.new
31
+ stream.expect(:config, config)
32
+ @router << stream
33
+
34
+ stanza = MiniTest::Mock.new
35
+ stanza.expect(:name, 'message')
36
+ stanza.expect(:[], 'alice@wonderland.lit', ['to'])
37
+ assert @router.local?(stanza)
38
+
39
+ assert stanza.verify
40
+ assert stream.verify
41
+ assert config.verify
42
+ end
43
+
44
+ def test_stanza_with_remote_jid_is_not_local
45
+ config = MiniTest::Mock.new
46
+ config.expect(:vhost?, false, ['wonderland.lit'])
47
+ stream = MiniTest::Mock.new
48
+ stream.expect(:config, config)
49
+ @router << stream
50
+
51
+ stanza = MiniTest::Mock.new
52
+ stanza.expect(:name, 'message')
53
+ stanza.expect(:[], 'alice@wonderland.lit', ['to'])
54
+ assert !@router.local?(stanza)
55
+
56
+ assert stanza.verify
57
+ assert stream.verify
58
+ assert config.verify
59
+ end
60
+ end
@@ -0,0 +1,198 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'ext/nokogiri'
5
+ require 'minitest/mock'
6
+ require 'test/unit'
7
+
8
+ class RosterTest < Test::Unit::TestCase
9
+ def setup
10
+ @stream = MiniTest::Mock.new
11
+ end
12
+
13
+ def test_roster_get_with_empty_roster
14
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit')
15
+ expected = node(%q{<iq id="42" type="result"><query xmlns="jabber:iq:roster"/></iq>})
16
+ @stream.expect(:write, nil, [expected])
17
+ @stream.expect(:requested_roster!, nil)
18
+ @stream.expect(:user, alice)
19
+
20
+ node = node(%q{<iq id="42" type="get"><query xmlns='jabber:iq:roster'/></iq>})
21
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
22
+ stanza.process
23
+ assert @stream.verify
24
+ end
25
+
26
+ def test_roster_get_with_non_empty_roster
27
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit')
28
+ alice.roster << Vines::Contact.new(:jid => 'hatter@wonderland.lit')
29
+ alice.roster << Vines::Contact.new(:jid => 'cat@wonderland.lit', :groups => ['Friends', 'Cats'])
30
+
31
+ expected = node(%q{
32
+ <iq id="42" type="result">
33
+ <query xmlns="jabber:iq:roster">
34
+ <item jid="cat@wonderland.lit" subscription="none">
35
+ <group>Cats</group>
36
+ <group>Friends</group>
37
+ </item>
38
+ <item jid="hatter@wonderland.lit" subscription="none"/>
39
+ </query>
40
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
41
+
42
+ @stream.expect(:write, nil, [expected])
43
+ @stream.expect(:requested_roster!, nil)
44
+ @stream.expect(:user, alice)
45
+
46
+ node = node(%q{<iq id="42" type="get"><query xmlns='jabber:iq:roster'/></iq>})
47
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
48
+ stanza.process
49
+ assert @stream.verify
50
+ end
51
+
52
+ def test_roster_set_with_invalid_to_address
53
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
54
+ @stream.expect(:user, alice)
55
+
56
+ node = node(%q{
57
+ <iq id="42" type="set" to="romeo@verona.lit">
58
+ <query xmlns="jabber:iq:roster"/>
59
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
60
+
61
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
62
+ assert_raise(Vines::StanzaErrors::Forbidden) { stanza.process }
63
+ assert @stream.verify
64
+ end
65
+
66
+ def test_roster_set_with_no_items
67
+ node = node(%q{
68
+ <iq id="42" type="set">
69
+ <query xmlns="jabber:iq:roster"/>
70
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
71
+
72
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
73
+ assert_raise(Vines::StanzaErrors::BadRequest) { stanza.process }
74
+ assert @stream.verify
75
+ end
76
+
77
+ def test_roster_set_with_two_items
78
+ node = node(%q{
79
+ <iq id="42" type="set">
80
+ <query xmlns="jabber:iq:roster">
81
+ <item jid="hatter@wonderland.lit"/>
82
+ <item jid="cat@wonderland.lit"/>
83
+ </query>
84
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
85
+
86
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
87
+ assert_raise(Vines::StanzaErrors::BadRequest) { stanza.process }
88
+ assert @stream.verify
89
+ end
90
+
91
+ def test_roster_set_missing_jid
92
+ node = node(%q{
93
+ <iq id="42" type="set">
94
+ <query xmlns="jabber:iq:roster">
95
+ <item name="Mad Hatter"/>
96
+ </query>
97
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
98
+
99
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
100
+ assert_raise(Vines::StanzaErrors::BadRequest) { stanza.process }
101
+ assert @stream.verify
102
+ end
103
+
104
+ def test_roster_set_with_duplicate_groups
105
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
106
+ @stream.expect(:user, alice)
107
+
108
+ node = node(%q{
109
+ <iq id="42" type="set">
110
+ <query xmlns="jabber:iq:roster">
111
+ <item jid="hatter@wonderland.lit" name="Mad Hatter">
112
+ <group>Friends</group>
113
+ <group>Friends</group>
114
+ </item>
115
+ </query>
116
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
117
+
118
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
119
+ assert_raise(Vines::StanzaErrors::BadRequest) { stanza.process }
120
+ assert @stream.verify
121
+ end
122
+
123
+ def test_roster_set_with_empty_group
124
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
125
+ @stream.expect(:user, alice)
126
+
127
+ node = node(%q{
128
+ <iq id="42" type="set">
129
+ <query xmlns="jabber:iq:roster">
130
+ <item jid="hatter@wonderland.lit" name="Mad Hatter">
131
+ <group></group>
132
+ </item>
133
+ </query>
134
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
135
+
136
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
137
+ assert_raise(Vines::StanzaErrors::NotAcceptable) { stanza.process }
138
+ assert @stream.verify
139
+ end
140
+
141
+ def test_roster_set_sends_results
142
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
143
+ storage = MiniTest::Mock.new
144
+ storage.expect(:save_user, nil, [alice])
145
+
146
+ recipient = MiniTest::Mock.new
147
+ recipient.expect(:user, alice)
148
+ def recipient.nodes; @nodes; end
149
+ def recipient.write(node)
150
+ @nodes ||= []
151
+ @nodes << node
152
+ end
153
+
154
+ router = MiniTest::Mock.new
155
+ router.expect(:interested_resources, [recipient], [alice.jid])
156
+
157
+ @stream.expect(:user, alice)
158
+ @stream.expect(:update_user_streams, nil, [alice])
159
+ @stream.expect(:router, router)
160
+ @stream.expect(:domain, 'wonderland.lit')
161
+ @stream.expect(:storage, storage, ['wonderland.lit'])
162
+ expected = node(%q{<iq id="42" type="result"/>})
163
+ @stream.expect(:write, nil, [expected])
164
+
165
+ node = node(%q{
166
+ <iq id="42" type="set">
167
+ <query xmlns="jabber:iq:roster">
168
+ <item jid="hatter@wonderland.lit" name="Mad Hatter">
169
+ <group>Friends</group>
170
+ </item>
171
+ </query>
172
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
173
+
174
+ stanza = Vines::Stanza::Iq::Roster.new(node, @stream)
175
+ stanza.process
176
+ assert_nothing_raised { stanza.process }
177
+ assert @stream.verify
178
+ assert storage.verify
179
+ assert router.verify
180
+
181
+ expected = node(%q{
182
+ <iq type="set" to="alice@wonderland.lit/tea">
183
+ <query xmlns="jabber:iq:roster">
184
+ <item jid="hatter@wonderland.lit" name="Mad Hatter" subscription="none">
185
+ <group>Friends</group>
186
+ </item>
187
+ </query>
188
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
189
+ recipient.nodes[0].remove_attribute('id') # id is random
190
+ assert_equal expected, recipient.nodes[0]
191
+ end
192
+
193
+ private
194
+
195
+ def node(xml)
196
+ Nokogiri::XML(xml).root
197
+ end
198
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'ext/nokogiri'
5
+ require 'minitest/mock'
6
+ require 'test/unit'
7
+
8
+ class SessionTest < Test::Unit::TestCase
9
+ def test_session
10
+ stream = MiniTest::Mock.new
11
+ stream.expect(:domain, 'wonderland.lit')
12
+ expected = node(%q{<iq from="wonderland.lit" id="42" type="result"/>})
13
+ stream.expect(:write, nil, [expected])
14
+
15
+ node = node(
16
+ %q{<iq id="42" to="wonderland.lit" type="set">
17
+ <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>
18
+ </iq>})
19
+
20
+ stanza = Vines::Stanza::Iq::Session.new(node, stream)
21
+ stanza.process
22
+ assert stream.verify
23
+ end
24
+
25
+ private
26
+
27
+ def node(xml)
28
+ Nokogiri::XML(xml).root
29
+ end
30
+ end
@@ -0,0 +1,159 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'ext/nokogiri'
5
+ require 'minitest/mock'
6
+ require 'test/unit'
7
+
8
+ class VcardTest < Test::Unit::TestCase
9
+ def setup
10
+ @stream = MiniTest::Mock.new
11
+ end
12
+
13
+ def test_vcard_get_on_remote_jid_routes
14
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
15
+ node = node(%q{<iq id="42" to="romeo@verona.lit" type="get"><vCard xmlns="vcard-temp"/></iq>})
16
+
17
+ router = MiniTest::Mock.new
18
+ router.expect(:local?, false, [node])
19
+ router.expect(:route, nil, [node])
20
+
21
+ @stream.expect(:user, alice)
22
+ @stream.expect(:router, router)
23
+
24
+ stanza = Vines::Stanza::Iq::Vcard.new(node, @stream)
25
+ stanza.process
26
+ assert @stream.verify
27
+ assert router.verify
28
+ end
29
+
30
+ def test_vcard_get_missing_to_address
31
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
32
+ node = node(%q{<iq id="42" type="get"><vCard xmlns="vcard-temp"/></iq>})
33
+
34
+ router = MiniTest::Mock.new
35
+ router.expect(:local?, true, [node])
36
+
37
+ card = node(%q{<vCard xmlns="vcard-temp"><FN>Alice in Wonderland</FN></vCard>})
38
+
39
+ storage = MiniTest::Mock.new
40
+ storage.expect(:find_vcard, card, [alice.jid.bare])
41
+
42
+ @stream.expect(:user, alice)
43
+ @stream.expect(:router, router)
44
+ @stream.expect(:domain, 'wonderland.lit')
45
+ @stream.expect(:storage, storage, ['wonderland.lit'])
46
+ expected = node(%q{
47
+ <iq id="42" to="alice@wonderland.lit/tea" type="result">
48
+ <vCard xmlns="vcard-temp">
49
+ <FN>Alice in Wonderland</FN>
50
+ </vCard>
51
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
52
+ @stream.expect(:write, nil, [expected])
53
+
54
+ stanza = Vines::Stanza::Iq::Vcard.new(node, @stream)
55
+ stanza.process
56
+ assert @stream.verify
57
+ assert router.verify
58
+ assert storage.verify
59
+ end
60
+
61
+ def test_vcard_get_another_user_includes_from_address
62
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
63
+ node = node(%q{<iq id="42" to="hatter@wonderland.lit" type="get"><vCard xmlns="vcard-temp"/></iq>})
64
+
65
+ router = MiniTest::Mock.new
66
+ router.expect(:local?, true, [node])
67
+
68
+ card = node(%q{<vCard xmlns="vcard-temp"><FN>Mad Hatter</FN></vCard>})
69
+
70
+ storage = MiniTest::Mock.new
71
+ storage.expect(:find_vcard, card, [Vines::JID.new('hatter@wonderland.lit')])
72
+
73
+ @stream.expect(:user, alice)
74
+ @stream.expect(:router, router)
75
+ @stream.expect(:domain, 'wonderland.lit')
76
+ @stream.expect(:storage, storage, ['wonderland.lit'])
77
+ expected = node(%q{
78
+ <iq from="hatter@wonderland.lit" id="42" to="alice@wonderland.lit/tea" type="result">
79
+ <vCard xmlns="vcard-temp">
80
+ <FN>Mad Hatter</FN>
81
+ </vCard>
82
+ </iq>}.strip.gsub(/\n|\s{2,}/, ''))
83
+ @stream.expect(:write, nil, [expected])
84
+
85
+ stanza = Vines::Stanza::Iq::Vcard.new(node, @stream)
86
+ stanza.process
87
+ assert @stream.verify
88
+ assert router.verify
89
+ assert storage.verify
90
+ end
91
+
92
+ def test_missing_vcard_get_returns_item_not_found
93
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
94
+ node = node(%q{<iq id="42" type="get"><vCard xmlns="vcard-temp"/></iq>})
95
+
96
+ router = MiniTest::Mock.new
97
+ router.expect(:local?, true, [node])
98
+
99
+ storage = MiniTest::Mock.new
100
+ storage.expect(:find_vcard, nil, [alice.jid.bare])
101
+
102
+ @stream.expect(:user, alice)
103
+ @stream.expect(:router, router)
104
+ @stream.expect(:domain, 'wonderland.lit')
105
+ @stream.expect(:storage, storage, ['wonderland.lit'])
106
+
107
+ stanza = Vines::Stanza::Iq::Vcard.new(node, @stream)
108
+ assert_raise(Vines::StanzaErrors::ItemNotFound) { stanza.process }
109
+ assert @stream.verify
110
+ assert router.verify
111
+ assert storage.verify
112
+ end
113
+
114
+ def test_vcard_set_on_another_user_returns_forbidden
115
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
116
+ node = node(%q{<iq id="42" to="hatter@wonderland.lit" type="set"><vCard xmlns="vcard-temp"><FN>Alice</FN></vCard></iq>})
117
+
118
+ router = MiniTest::Mock.new
119
+ router.expect(:local?, true, [node])
120
+
121
+ @stream.expect(:user, alice)
122
+ @stream.expect(:router, router)
123
+
124
+ stanza = Vines::Stanza::Iq::Vcard.new(node, @stream)
125
+ assert_raise(Vines::StanzaErrors::Forbidden) { stanza.process }
126
+ assert @stream.verify
127
+ end
128
+
129
+ def test_vcard_set_returns_result
130
+ alice = Vines::User.new(:jid => 'alice@wonderland.lit/tea')
131
+ node = node(%q{<iq id="42" type="set"><vCard xmlns="vcard-temp"><FN>Alice</FN></vCard></iq>})
132
+ card = node(%q{<vCard xmlns="vcard-temp"><FN>Alice</FN></vCard>})
133
+
134
+ router = MiniTest::Mock.new
135
+ router.expect(:local?, true, [node])
136
+
137
+ storage = MiniTest::Mock.new
138
+ storage.expect(:save_vcard, nil, [alice.jid, card])
139
+
140
+ @stream.expect(:user, alice)
141
+ @stream.expect(:router, router)
142
+ @stream.expect(:domain, 'wonderland.lit')
143
+ @stream.expect(:storage, storage, ['wonderland.lit'])
144
+ expected = node(%q{<iq id="42" to="alice@wonderland.lit/tea" type="result"/>})
145
+ @stream.expect(:write, nil, [expected])
146
+
147
+ stanza = Vines::Stanza::Iq::Vcard.new(node, @stream)
148
+ stanza.process
149
+ assert @stream.verify
150
+ assert router.verify
151
+ assert storage.verify
152
+ end
153
+
154
+ private
155
+
156
+ def node(xml)
157
+ Nokogiri::XML(xml).root
158
+ end
159
+ end