Official cwtch.im peer and server implementations. https://cwtch.im
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

423 lines
14KB

  1. package testing
  2. import (
  3. app2 "cwtch.im/cwtch/app"
  4. "cwtch.im/cwtch/app/utils"
  5. "cwtch.im/cwtch/event"
  6. "cwtch.im/cwtch/event/bridge"
  7. "cwtch.im/cwtch/model"
  8. "cwtch.im/cwtch/peer"
  9. "cwtch.im/cwtch/protocol/connections"
  10. cwtchserver "cwtch.im/cwtch/server"
  11. "fmt"
  12. "git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
  13. "git.openprivacy.ca/openprivacy/libricochet-go/log"
  14. "golang.org/x/net/proxy"
  15. "os"
  16. "os/user"
  17. "path"
  18. "runtime"
  19. "runtime/pprof"
  20. "testing"
  21. "time"
  22. )
  23. const (
  24. serverKeyfile = "./../server/app/private_key"
  25. localKeyfile = "./private_key"
  26. )
  27. var (
  28. aliceLines = []string{"Hello, I'm Alice", "bye"}
  29. bobLines = []string{"Hi, my name is Bob.", "toodles", "welcome"}
  30. carolLines = []string{"Howdy, thanks!"}
  31. )
  32. func printAndCountVerifedTimeline(t *testing.T, timeline []model.Message) int {
  33. numVerified := 0
  34. for _, message := range timeline {
  35. fmt.Printf("%v %v> %s\n", message.Timestamp, message.PeerID, message.Message)
  36. numVerified++
  37. }
  38. return numVerified
  39. }
  40. func serverCheck(t *testing.T, serverAddr string) bool {
  41. torDialer, err := proxy.SOCKS5("tcp", "127.0.0.1:9050", nil, proxy.Direct)
  42. if err != nil {
  43. t.Logf("Could not get SOCKS5 proxy: %v", err)
  44. return false
  45. }
  46. // Doesn't seem to be a way to turn the default timeout of 2 minutes down
  47. conn, err := torDialer.Dial("tcp", serverAddr+".onion:9878")
  48. if err != nil {
  49. t.Logf("Could not dial %v: %v", serverAddr, err)
  50. return false
  51. }
  52. conn.Close()
  53. return true
  54. }
  55. func waitForPeerGroupConnection(t *testing.T, peer peer.CwtchPeer, groupID string) {
  56. for {
  57. fmt.Printf("%v checking group conection...\n", peer.GetName())
  58. state, ok := peer.GetGroupState(groupID)
  59. if ok {
  60. fmt.Printf("Waiting for Peer %v to join group %v - state: %v\n", peer.GetName(), groupID, state)
  61. if state == connections.FAILED {
  62. t.Fatalf("%v could not connect to %v", peer.GetOnion(), groupID)
  63. }
  64. if state != connections.SYNCED {
  65. fmt.Printf("peer %v %v waiting connect to group %v, currently: %v\n", peer.GetName(), peer.GetOnion(), groupID, connections.ConnectionStateName[state])
  66. time.Sleep(time.Second * 5)
  67. continue
  68. } else {
  69. fmt.Printf("peer %v %v CONNECTED to group %v\n", peer.GetName(), peer.GetOnion(), groupID)
  70. break
  71. }
  72. }
  73. }
  74. return
  75. }
  76. func waitForPeerPeerConnection(t *testing.T, peera peer.CwtchPeer, peerb peer.CwtchPeer) {
  77. for {
  78. state, ok := peera.GetPeerState(peerb.GetOnion())
  79. if ok {
  80. //log.Infof("Waiting for Peer %v to peer with peer: %v - state: %v\n", peera.GetProfile().Name, peerb.GetProfile().Name, state)
  81. if state == connections.FAILED {
  82. t.Fatalf("%v could not connect to %v", peera.GetOnion(), peerb.GetOnion())
  83. }
  84. if state != connections.AUTHENTICATED {
  85. fmt.Printf("peer %v waiting connect to peer %v, currently: %v\n", peera.GetOnion(), peerb.GetOnion(), connections.ConnectionStateName[state])
  86. time.Sleep(time.Second * 5)
  87. continue
  88. } else {
  89. fmt.Printf("%v CONNECTED and AUTHED to %v\n", peera.GetName(), peerb.GetName())
  90. break
  91. }
  92. }
  93. }
  94. return
  95. }
  96. func TestCwtchPeerIntegration(t *testing.T) {
  97. numGoRoutinesStart := runtime.NumGoroutine()
  98. log.AddEverythingFromPattern("connectivity")
  99. log.SetLevel(log.LevelDebug)
  100. log.ExcludeFromPattern("connection/connection")
  101. log.ExcludeFromPattern("outbound/3dhauthchannel")
  102. log.ExcludeFromPattern("event/eventmanager")
  103. log.ExcludeFromPattern("pipeBridge")
  104. log.ExcludeFromPattern("tapir")
  105. os.RemoveAll("tor")
  106. acn, err := connectivity.StartTor(".", "")
  107. if err != nil {
  108. t.Fatalf("Could not start Tor: %v", err)
  109. }
  110. // ***** Cwtch Server management *****
  111. var server *cwtchserver.Server
  112. serverOnline := false
  113. var serverAddr string
  114. if !serverOnline {
  115. // launch app with new key
  116. fmt.Println("No server found!")
  117. server = new(cwtchserver.Server)
  118. fmt.Println("Starting cwtch server...")
  119. os.Remove("server-test.json")
  120. config := cwtchserver.LoadConfig(".", "server-test.json")
  121. identity := config.Identity()
  122. serverAddr = identity.Hostname()
  123. go server.Run(acn, config)
  124. // let tor get established
  125. fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr)
  126. } else {
  127. fmt.Printf("Found existing cwtch server %v, using for tests...\n", serverAddr)
  128. }
  129. numGoRoutinesPostServer := runtime.NumGoroutine()
  130. app := app2.NewApp(acn, "./storage")
  131. usr, _ := user.Current()
  132. cwtchDir := path.Join(usr.HomeDir, ".cwtch")
  133. os.Mkdir(cwtchDir, 0700)
  134. os.RemoveAll(path.Join(cwtchDir, "testing"))
  135. os.Mkdir(path.Join(cwtchDir, "testing"), 0700)
  136. bridgeClient := bridge.NewPipeBridgeClient(path.Join(cwtchDir, "testing/clientPipe"), path.Join(cwtchDir, "testing/servicePipe"))
  137. bridgeService := bridge.NewPipeBridgeService(path.Join(cwtchDir, "testing/servicePipe"), path.Join(cwtchDir, "testing/clientPipe"))
  138. appClient := app2.NewAppClient("./storage", bridgeClient)
  139. appService := app2.NewAppService(acn, "./storage", bridgeService)
  140. numGoRoutinesPostAppStart := runtime.NumGoroutine()
  141. // ***** cwtchPeer setup *****
  142. fmt.Println("Creating Alice...")
  143. app.CreatePeer("alice", "asdfasdf")
  144. fmt.Println("Creating Bob...")
  145. app.CreatePeer("bob", "asdfasdf")
  146. fmt.Println("Creating Carol...")
  147. appClient.CreatePeer("carol", "asdfasdf")
  148. alice := utils.WaitGetPeer(app, "alice")
  149. fmt.Println("Alice created:", alice.GetOnion())
  150. alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite})
  151. bob := utils.WaitGetPeer(app, "bob")
  152. fmt.Println("Bob created:", bob.GetOnion())
  153. bob.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite})
  154. carol := utils.WaitGetPeer(appClient, "carol")
  155. fmt.Println("Carol created:", carol.GetOnion())
  156. carol.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite})
  157. app.LaunchPeers()
  158. appClient.LaunchPeers()
  159. fmt.Println("Waiting for Alice, Bob, and Carol to connect with onion network...")
  160. time.Sleep(time.Second * 60)
  161. numGoRoutinesPostPeerStart := runtime.NumGoroutine()
  162. // ***** Peering, server joining, group creation / invite *****
  163. fmt.Println("Alice joining server...")
  164. alice.JoinServer(serverAddr)
  165. fmt.Println("Alice peering with Bob...")
  166. alice.AddContact("Bob", bob.GetOnion(), false) // Add contact so we can track connection state
  167. alice.PeerWithOnion(bob.GetOnion())
  168. fmt.Println("Alice peering with Carol...")
  169. alice.AddContact("Carol", carol.GetOnion(), false)
  170. alice.PeerWithOnion(carol.GetOnion())
  171. fmt.Println("Creating group on ", serverAddr, "...")
  172. groupID, _, err := alice.StartGroup(serverAddr)
  173. fmt.Printf("Created group: %v!\n", groupID)
  174. if err != nil {
  175. t.Errorf("Failed to init group: %v", err)
  176. return
  177. }
  178. fmt.Println("Waiting for alice to join server...")
  179. waitForPeerGroupConnection(t, alice, groupID)
  180. fmt.Println("Waiting for alice and Bob to peer...")
  181. waitForPeerPeerConnection(t, alice, bob)
  182. fmt.Println("Alice inviting Bob to group...")
  183. err = alice.InviteOnionToGroup(bob.GetOnion(), groupID)
  184. if err != nil {
  185. t.Fatalf("Error for Alice inviting Bob to group: %v", err)
  186. }
  187. time.Sleep(time.Second * 5)
  188. fmt.Println("Bob examining groups and accepting invites...")
  189. for _, groupID := range bob.GetGroups() {
  190. group := bob.GetGroup(groupID)
  191. fmt.Printf("Bob group: %v (Accepted: %v)\n", group.GroupID, group.Accepted)
  192. if group.Accepted == false {
  193. fmt.Printf("Bob received and accepting group invite: %v\n", group.GroupID)
  194. bob.AcceptInvite(group.GroupID)
  195. }
  196. }
  197. numGoRoutinesPostServerConnect := runtime.NumGoroutine()
  198. // ***** Conversation *****
  199. fmt.Println("Starting conversation in group...")
  200. // Conversation
  201. fmt.Println("Alice> ", aliceLines[0])
  202. err = alice.SendMessageToGroup(groupID, aliceLines[0])
  203. if err != nil {
  204. t.Fatalf("Alice failed to send a message to the group: %v", err)
  205. }
  206. time.Sleep(time.Second * 10)
  207. fmt.Println("Bob> ", bobLines[0])
  208. err = bob.SendMessageToGroup(groupID, bobLines[0])
  209. if err != nil {
  210. t.Fatalf("Bob failed to send a message to the group: %v", err)
  211. }
  212. time.Sleep(time.Second * 10)
  213. fmt.Println("Alice> ", aliceLines[1])
  214. alice.SendMessageToGroup(groupID, aliceLines[1])
  215. time.Sleep(time.Second * 10)
  216. fmt.Println("Bob> ", bobLines[1])
  217. bob.SendMessageToGroup(groupID, bobLines[1])
  218. time.Sleep(time.Second * 10)
  219. fmt.Println("Alice inviting Carol to group...")
  220. err = alice.InviteOnionToGroup(carol.GetOnion(), groupID)
  221. if err != nil {
  222. t.Fatalf("Error for Alice inviting Carol to group: %v", err)
  223. }
  224. time.Sleep(time.Second * 10)
  225. fmt.Println("Carol examining groups and accepting invites...")
  226. for _, groupID := range carol.GetGroups() {
  227. group := carol.GetGroup(groupID)
  228. fmt.Printf("Carol group: %v (Accepted: %v)\n", group.GroupID, group.Accepted)
  229. if group.Accepted == false {
  230. fmt.Printf("Carol received and accepting group invite: %v\n", group.GroupID)
  231. carol.AcceptInvite(group.GroupID)
  232. }
  233. }
  234. fmt.Println("Shutting down Alice...")
  235. app.ShutdownPeer(alice.GetOnion())
  236. time.Sleep(time.Second * 5)
  237. numGoRoutinesPostAlice := runtime.NumGoroutine()
  238. fmt.Println("Carol joining server...")
  239. carol.JoinServer(serverAddr)
  240. waitForPeerGroupConnection(t, carol, groupID)
  241. numGoRotinesPostCarolConnect := runtime.NumGoroutine()
  242. fmt.Println("Bob> ", bobLines[2])
  243. bob.SendMessageToGroup(groupID, bobLines[2])
  244. time.Sleep(time.Second * 10)
  245. fmt.Println("Carol> ", carolLines[0])
  246. carol.SendMessageToGroup(groupID, carolLines[0])
  247. time.Sleep(time.Second * 10)
  248. // ***** Verify Test *****
  249. fmt.Println("Final syncing time...")
  250. time.Sleep(time.Second * 30)
  251. alicesGroup := alice.GetGroup(groupID)
  252. if alicesGroup == nil {
  253. t.Error("aliceGroup == nil")
  254. return
  255. }
  256. fmt.Printf("Alice's TimeLine:\n")
  257. aliceVerified := printAndCountVerifedTimeline(t, alicesGroup.GetTimeline())
  258. if aliceVerified != 4 {
  259. t.Errorf("Alice did not have 4 verified messages")
  260. }
  261. bobsGroup := bob.GetGroup(groupID)
  262. if bobsGroup == nil {
  263. t.Error("bobGroup == nil")
  264. return
  265. }
  266. fmt.Printf("Bob's TimeLine:\n")
  267. bobVerified := printAndCountVerifedTimeline(t, bobsGroup.GetTimeline())
  268. if bobVerified != 6 {
  269. t.Errorf("Bob did not have 5 verified messages")
  270. }
  271. carolsGroup := carol.GetGroup(groupID)
  272. fmt.Printf("Carol's TimeLine:\n")
  273. carolVerified := printAndCountVerifedTimeline(t, carolsGroup.GetTimeline())
  274. if carolVerified != 6 {
  275. t.Errorf("Carol did not have 3 verified messages")
  276. }
  277. if len(alicesGroup.GetTimeline()) != 4 {
  278. t.Errorf("Alice's timeline does not have all messages")
  279. } else {
  280. // check message 0,1,2,3
  281. aliceGroupTimeline := alicesGroup.GetTimeline()
  282. if aliceGroupTimeline[0].Message != aliceLines[0] || aliceGroupTimeline[1].Message != bobLines[0] ||
  283. aliceGroupTimeline[2].Message != aliceLines[1] || aliceGroupTimeline[3].Message != bobLines[1] {
  284. t.Errorf("Some of Alice's timeline messages did not have the expected content!")
  285. }
  286. }
  287. if len(bobsGroup.GetTimeline()) != 6 {
  288. t.Errorf("Bob's timeline does not have all messages")
  289. } else {
  290. // check message 0,1,2,3,4,5
  291. bobGroupTimeline := bobsGroup.GetTimeline()
  292. if bobGroupTimeline[0].Message != aliceLines[0] || bobGroupTimeline[1].Message != bobLines[0] ||
  293. bobGroupTimeline[2].Message != aliceLines[1] || bobGroupTimeline[3].Message != bobLines[1] ||
  294. bobGroupTimeline[4].Message != bobLines[2] || bobGroupTimeline[5].Message != carolLines[0] {
  295. t.Errorf("Some of Bob's timeline messages did not have the expected content!")
  296. }
  297. }
  298. if len(carolsGroup.GetTimeline()) != 6 {
  299. t.Errorf("Carol's timeline does not have all messages")
  300. } else {
  301. // check message 0,1,2,3,4,5
  302. carolGroupTimeline := carolsGroup.GetTimeline()
  303. if carolGroupTimeline[0].Message != aliceLines[0] || carolGroupTimeline[1].Message != bobLines[0] ||
  304. carolGroupTimeline[2].Message != aliceLines[1] || carolGroupTimeline[3].Message != bobLines[1] ||
  305. carolGroupTimeline[4].Message != bobLines[2] || carolGroupTimeline[5].Message != carolLines[0] {
  306. t.Errorf("Some of Carol's timeline messages did not have the expected content!")
  307. }
  308. }
  309. fmt.Println("Shutting down Bob...")
  310. app.ShutdownPeer(bob.GetOnion())
  311. time.Sleep(time.Second * 3)
  312. numGoRoutinesPostBob := runtime.NumGoroutine()
  313. if server != nil {
  314. fmt.Println("Shutting down server...")
  315. server.Shutdown()
  316. time.Sleep(time.Second * 3)
  317. }
  318. numGoRoutinesPostServerShutdown := runtime.NumGoroutine()
  319. fmt.Println("Shutting down Carol...")
  320. appClient.ShutdownPeer(carol.GetOnion())
  321. time.Sleep(time.Second * 3)
  322. numGoRoutinesPostCarol := runtime.NumGoroutine()
  323. fmt.Println("Shutting down apps...")
  324. fmt.Printf("app Shutdown: %v\n", runtime.NumGoroutine())
  325. app.Shutdown()
  326. fmt.Printf("appClientShutdown: %v\n", runtime.NumGoroutine())
  327. appClient.Shutdown()
  328. fmt.Printf("appServiceShutdown: %v\n", runtime.NumGoroutine())
  329. appService.Shutdown()
  330. fmt.Printf("bridgeClientShutdown: %v\n", runtime.NumGoroutine())
  331. bridgeClient.Shutdown()
  332. time.Sleep(2 * time.Second)
  333. fmt.Printf("brideServiceShutdown: %v\n", runtime.NumGoroutine())
  334. bridgeService.Shutdown()
  335. time.Sleep(2 * time.Second)
  336. fmt.Printf("Done shutdown: %v\n", runtime.NumGoroutine())
  337. numGoRoutinesPostAppShutdown := runtime.NumGoroutine()
  338. fmt.Println("Shutting down ACN...")
  339. acn.Close()
  340. time.Sleep(time.Second * 2) // Server ^^ has a 5 second loop attempting reconnect before exiting
  341. time.Sleep(time.Second * 30) // the network status plugin might keep goroutines alive for a minute before killing them
  342. numGoRoutinesPostACN := runtime.NumGoroutine()
  343. // Printing out the current goroutines
  344. // Very useful if we are leaking any.
  345. pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
  346. fmt.Printf("numGoRoutinesStart: %v\nnumGoRoutinesPostServer: %v\nnumGoRoutinesPostAppStart: %v\nnumGoRoutinesPostPeerStart: %v\nnumGoRoutinesPostPeerAndServerConnect: %v\n"+
  347. "numGoRoutinesPostAlice: %v\nnumGoRotinesPostCarolConnect: %v\nnumGoRoutinesPostBob: %v\nnumGoRoutinesPostServerShutdown: %v\nnumGoRoutinesPostCarol: %v\nnumGoRoutinesPostAppShutdown: %v\nnumGoRoutinesPostACN: %v\n",
  348. numGoRoutinesStart, numGoRoutinesPostServer, numGoRoutinesPostAppStart, numGoRoutinesPostPeerStart, numGoRoutinesPostServerConnect,
  349. numGoRoutinesPostAlice, numGoRotinesPostCarolConnect, numGoRoutinesPostBob, numGoRoutinesPostServerShutdown, numGoRoutinesPostCarol, numGoRoutinesPostAppShutdown, numGoRoutinesPostACN)
  350. if numGoRoutinesStart != numGoRoutinesPostACN {
  351. t.Errorf("Number of GoRoutines at start (%v) does not match number of goRoutines after cleanup of peers and servers (%v), clean up failed, leak detected!", numGoRoutinesStart, numGoRoutinesPostACN)
  352. }
  353. }