1package xmpp 2 3import ( 4 "encoding/xml" 5 "fmt" 6 "io" 7 "time" 8 9 "github.com/coyim/coyim/xmpp/data" 10 . "gopkg.in/check.v1" 11) 12 13type DiscoveryXMPPSuite struct{} 14 15var _ = Suite(&DiscoveryXMPPSuite{}) 16 17func (s *DiscoveryXMPPSuite) Test_SendDiscoveryInfoRequest(c *C) { 18 mockOut := &mockConnIOReaderWriter{} 19 conn := conn{ 20 out: mockOut, 21 jid: "juliet@example.com/chamber", 22 } 23 conn.inflights = make(map[data.Cookie]inflight) 24 25 reply, cookie, err := conn.sendDiscoveryInfo("example.com") 26 c.Assert(err, IsNil) 27 c.Assert(string(mockOut.write), Matches, "<iq xmlns='jabber:client' to='example.com' from='juliet@example.com/chamber' type='get' id='.+'><query xmlns=\"http://jabber.org/protocol/disco#info\"></query></iq>") 28 c.Assert(reply, NotNil) 29 c.Assert(cookie, NotNil) 30} 31 32func (s *DiscoveryXMPPSuite) Test_ReceiveDiscoveryResult(c *C) { 33 // See: XEP-0030, Section: 3.1 Basic Protocol, Example: 2 34 fromServer := ` 35<iq xmlns='jabber:client' type='result' 36 from='plays.shakespeare.lit' 37 to='romeo@montague.net/orchard' 38 id='100000'> 39 <query xmlns='http://jabber.org/protocol/disco#info'> 40 <identity 41 category='conference' 42 type='text' 43 name='Play-Specific Chatrooms'/> 44 <identity 45 category='directory' 46 type='chatroom' 47 name='Play-Specific Chatrooms'/> 48 <feature var='http://jabber.org/protocol/disco#info'/> 49 <feature var='http://jabber.org/protocol/disco#items'/> 50 </query> 51</iq> 52` 53 reply := make(chan data.Stanza, 1) 54 mockIn := &mockConnIOReaderWriter{read: []byte(fromServer)} 55 conn := conn{ 56 in: xml.NewDecoder(mockIn), 57 inflights: map[data.Cookie]inflight{ 58 0x100000: inflight{ 59 to: "plays.shakespeare.lit", 60 replyChan: reply, 61 }, 62 }, 63 } 64 65 _, err := conn.Next() 66 c.Assert(err, Equals, io.EOF) 67 68 iq, ok := (<-reply).Value.(*data.ClientIQ) 69 c.Assert(ok, Equals, true) 70 71 discoveryReply, err := parseDiscoveryInfoReply(iq) 72 c.Assert(err, IsNil) 73 74 c.Assert(discoveryReply, DeepEquals, &data.DiscoveryInfoQuery{ 75 XMLName: xml.Name{Space: "http://jabber.org/protocol/disco#info", Local: "query"}, 76 Identities: []data.DiscoveryIdentity{ 77 data.DiscoveryIdentity{ 78 XMLName: xml.Name{Space: "http://jabber.org/protocol/disco#info", Local: "identity"}, 79 Category: "conference", 80 Type: "text", 81 Name: "Play-Specific Chatrooms"}, 82 data.DiscoveryIdentity{ 83 XMLName: xml.Name{Space: "http://jabber.org/protocol/disco#info", Local: "identity"}, 84 Category: "directory", 85 Type: "chatroom", 86 Name: "Play-Specific Chatrooms"}, 87 }, 88 Features: []data.DiscoveryFeature{ 89 data.DiscoveryFeature{ 90 XMLName: xml.Name{Space: "http://jabber.org/protocol/disco#info", Local: "feature"}, 91 Var: "http://jabber.org/protocol/disco#info", 92 }, 93 data.DiscoveryFeature{ 94 XMLName: xml.Name{Space: "http://jabber.org/protocol/disco#info", Local: "feature"}, 95 Var: "http://jabber.org/protocol/disco#items", 96 }, 97 }, 98 }) 99 100 _, ok = conn.inflights[0x100000] 101 c.Assert(ok, Equals, false) 102} 103 104func (s *DiscoveryXMPPSuite) Test_HasSupportTo(c *C) { 105 // See: XEP-0030, Section: 3.1 Basic Protocol, Example: 2 106 fromServer := ` 107<iq xmlns='jabber:client' type='result' 108 from='plays.shakespeare.lit' 109 to='romeo@montague.net/orchard' 110 id='%s'> 111 <query xmlns='http://jabber.org/protocol/disco#info'> 112 <feature var='jabber:iq:privacy'/> 113 <feature var='http://jabber.org/protocol/disco#items'/> 114 </query> 115</iq> 116` 117 mockOut := &mockConnIOReaderWriter{} 118 119 conn := conn{ 120 in: xml.NewDecoder(nil), 121 out: mockOut, 122 inflights: make(map[data.Cookie]inflight), 123 124 jid: "romeo@montague.net/orchard", 125 } 126 127 done := make(chan bool, 1) 128 go func() { 129 ok := conn.HasSupportTo("plays.shakespeare.lit", "jabber:iq:privacy") 130 c.Assert(ok, Equals, true) 131 done <- true 132 }() 133 134 <-time.After(1 * time.Millisecond) 135 136 var iq data.ClientIQ 137 c.Assert(string(mockOut.Written()), Matches, "<iq xmlns='jabber:client' to='plays.shakespeare.lit' from='romeo@montague.net/orchard' type='get' id='.+'><query xmlns=\"http://jabber.org/protocol/disco#info\"></query></iq>") 138 139 err := xml.Unmarshal(mockOut.Written(), &iq) 140 c.Assert(err, IsNil) 141 142 mockIn := &mockConnIOReaderWriter{read: []byte(fmt.Sprintf(fromServer, iq.ID))} 143 conn.in = xml.NewDecoder(mockIn) 144 145 _, err = conn.Next() 146 c.Assert(err, Equals, io.EOF) 147 <-done 148} 149 150func (s *DiscoveryXMPPSuite) Test_VerificationString_failsIfThereAreDuplicateIdentities(c *C) { 151 reply := &data.DiscoveryInfoQuery{ 152 Identities: []data.DiscoveryIdentity{ 153 data.DiscoveryIdentity{ 154 Lang: "en", 155 Category: "stuff", 156 Type: "thing", 157 Name: "something", 158 }, 159 data.DiscoveryIdentity{ 160 Lang: "en", 161 Category: "stuff", 162 Type: "thing", 163 Name: "something", 164 }, 165 }, 166 } 167 168 _, err := VerificationString(reply) 169 c.Assert(err.Error(), Equals, "duplicate discovery identity") 170} 171 172func (s *DiscoveryXMPPSuite) Test_VerificationString_failsIfThereAreDuplicateFeatures(c *C) { 173 reply := &data.DiscoveryInfoQuery{ 174 Features: []data.DiscoveryFeature{ 175 data.DiscoveryFeature{ 176 Var: "foo", 177 }, 178 data.DiscoveryFeature{ 179 Var: "foo", 180 }, 181 }, 182 } 183 184 _, err := VerificationString(reply) 185 c.Assert(err.Error(), Equals, "duplicate discovery feature") 186} 187 188func (s *DiscoveryXMPPSuite) Test_VerificationString_failsIfThereAreDuplicateFormTypes(c *C) { 189 reply := &data.DiscoveryInfoQuery{ 190 Forms: []data.Form{ 191 data.Form{ 192 Type: "foo", 193 Fields: []data.FormFieldX{ 194 data.FormFieldX{ 195 Var: "FORM_TYPE", 196 Type: "Foo", 197 Values: []string{"foo"}, 198 }, 199 }, 200 }, 201 data.Form{ 202 Type: "foo", 203 Fields: []data.FormFieldX{ 204 data.FormFieldX{ 205 Var: "FORM_TYPE", 206 Type: "Foo", 207 Values: []string{"foo"}, 208 }, 209 }, 210 }, 211 }, 212 } 213 214 _, err := VerificationString(reply) 215 c.Assert(err.Error(), Equals, "multiple forms of the same type") 216} 217 218func (s *DiscoveryXMPPSuite) Test_VerificationString_failsIfThereAreNoValues(c *C) { 219 reply := &data.DiscoveryInfoQuery{ 220 Forms: []data.Form{ 221 data.Form{ 222 Type: "foo", 223 }, 224 data.Form{ 225 Type: "foo", 226 Fields: []data.FormFieldX{ 227 data.FormFieldX{ 228 Var: "FORM_TYPE2", 229 Type: "Foo", 230 }, 231 }, 232 }, 233 data.Form{ 234 Type: "foo", 235 Fields: []data.FormFieldX{ 236 data.FormFieldX{ 237 Var: "FORM_TYPE", 238 Type: "Foo", 239 }, 240 }, 241 }, 242 data.Form{ 243 Type: "foo", 244 Fields: []data.FormFieldX{ 245 data.FormFieldX{ 246 Var: "FORM_TYPE", 247 Type: "Foo", 248 }, 249 }, 250 }, 251 }, 252 } 253 254 _, err := VerificationString(reply) 255 c.Assert(err.Error(), Equals, "form does not have a single FORM_TYPE value") 256} 257 258func (s *DiscoveryXMPPSuite) Test_DiscoveryReply_returnsSupportedValues(c *C) { 259 rep := DiscoveryReply("foo@bar.com") 260 c.Assert(rep, DeepEquals, 261 data.DiscoveryInfoQuery{ 262 XMLName: xml.Name{Space: "", Local: ""}, 263 Node: "", 264 Identities: []data.DiscoveryIdentity{ 265 data.DiscoveryIdentity{ 266 XMLName: xml.Name{Space: "", Local: ""}, 267 Lang: "", 268 Category: "client", 269 Type: "pc", 270 Name: "foo@bar.com"}}, 271 Features: []data.DiscoveryFeature{ 272 {Var: "http://jabber.org/protocol/disco#info"}, 273 {Var: "urn:xmpp:bob"}, 274 {Var: "urn:xmpp:ping"}, 275 {Var: "http://jabber.org/protocol/caps"}, 276 {Var: "jabber:iq:version"}, 277 {Var: "vcard-temp"}, 278 {Var: "jabber:x:data"}, 279 {Var: "http://jabber.org/protocol/si"}, 280 {Var: "http://jabber.org/protocol/si/profile/file-transfer"}, 281 {Var: "http://jabber.org/protocol/si/profile/directory-transfer"}, 282 // {Var: "http://jabber.org/protocol/si/profile/encrypted-data-transfer"}, 283 {Var: "http://jabber.org/protocol/bytestreams"}, 284 }, 285 Forms: []data.Form(nil)}) 286} 287