2018-03-31 19:33:32 +00:00
package testing
2018-03-30 21:16:51 +00:00
import (
2018-05-28 18:05:06 +00:00
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/peer"
cwtchserver "cwtch.im/cwtch/server"
2018-05-20 19:58:16 +00:00
"fmt"
"github.com/s-rah/go-ricochet"
"github.com/s-rah/go-ricochet/utils"
2018-04-27 19:20:33 +00:00
"io/ioutil"
2018-05-20 19:58:16 +00:00
"log"
2018-04-27 19:20:33 +00:00
"os"
2018-05-30 18:42:17 +00:00
"runtime"
2018-05-20 19:58:16 +00:00
"testing"
"time"
2018-03-30 21:16:51 +00:00
)
2018-04-27 19:20:33 +00:00
const (
keyfile = "./private_key"
)
var (
2018-05-20 19:58:16 +00:00
aliceLines = [ ] string { "Hello" , "My name is Alice" , "bye" }
bobLines = [ ] string { "Hi" , "My name is Bob." , "toodles" , "hello?" }
2018-04-27 19:20:33 +00:00
)
2018-05-20 19:58:16 +00:00
func checkAndGenPrivateKey ( privateKeyFile string ) ( generated bool ) {
if _ , err := os . Stat ( privateKeyFile ) ; os . IsNotExist ( err ) {
2018-04-27 19:20:33 +00:00
fmt . Println ( "generating new private key..." )
2018-05-28 18:05:06 +00:00
pk , err := utils . GeneratePrivateKey ( )
if err != nil {
2018-04-27 19:20:33 +00:00
log . Fatalf ( "error generating new private key: %v\n" , err )
}
2018-05-28 18:05:06 +00:00
err = ioutil . WriteFile ( privateKeyFile , [ ] byte ( utils . PrivateKeyToString ( pk ) ) , 0400 )
2018-04-27 19:20:33 +00:00
if err != nil {
log . Fatalf ( "error writing new private key to file %s: %v\n" , privateKeyFile , err )
}
return true
}
return false
}
2018-05-20 19:58:16 +00:00
func printAndVerifyTimeline ( t * testing . T , timeline [ ] model . Message ) error {
for _ , message := range timeline {
2018-04-27 19:20:33 +00:00
fmt . Printf ( "%v %v> %s [%t]\n" , message . Timestamp , message . PeerID , message . Message , message . Verified )
if ! message . Verified {
t . Errorf ( "Message '%s' from '%s' not verified!" , message . Message , message . PeerID )
}
}
return nil
}
func serverCheck ( serverAddr string ) bool {
rc , err := goricochet . Open ( serverAddr )
2018-05-30 18:42:17 +00:00
// Won't actaully free thread because rc.start() will wait for the uncalled rc.Process to read from errorChannel...
rc . Conn . Close ( )
2018-04-27 19:20:33 +00:00
if err == nil {
return true
}
return false
}
2018-03-30 21:16:51 +00:00
func TestCwtchPeerIntegration ( t * testing . T ) {
2018-04-27 19:20:33 +00:00
// Hide logging "noise"
log . SetOutput ( ioutil . Discard )
2018-05-30 18:42:17 +00:00
numGoRoutinesStart := runtime . NumGoroutine ( )
2018-04-27 19:20:33 +00:00
2018-05-28 18:36:04 +00:00
// ***** Cwtch Server managment *****
2018-05-30 18:42:17 +00:00
var server * cwtchserver . Server = nil
2018-04-27 19:20:33 +00:00
generatedKey := checkAndGenPrivateKey ( keyfile )
serverKey , err := utils . LoadPrivateKeyFromFile ( keyfile )
if err != nil {
2018-05-20 19:58:16 +00:00
t . Errorf ( "Could not load server's key from %v" , keyfile )
2018-04-27 19:20:33 +00:00
}
serverAddr , _ := utils . GetOnionAddress ( serverKey )
serverOnline := false
2018-05-20 19:58:16 +00:00
if ! generatedKey {
2018-04-27 19:20:33 +00:00
fmt . Printf ( "Checking if test server %v is online...\n" , serverAddr )
serverOnline = serverCheck ( serverAddr )
}
2018-05-20 19:58:16 +00:00
if ! serverOnline {
2018-04-27 19:20:33 +00:00
// launch app
2018-05-30 18:42:17 +00:00
server = new ( cwtchserver . Server )
2018-04-27 19:20:33 +00:00
fmt . Printf ( "No server found\nStarting cwtch server...\n" )
go server . Run ( keyfile )
// let tor get established
fmt . Printf ( "Establishing Tor hidden service: %v...\n" , serverAddr )
} else {
fmt . Printf ( "Found existing cwtch server %v, using for tests...\n" , serverAddr )
}
2018-05-30 18:42:17 +00:00
time . Sleep ( time . Second * 2 )
numGoRoutinesPostServer := runtime . NumGoroutine ( )
2018-05-28 18:36:04 +00:00
// ***** Peer setup *****
2018-04-27 19:20:33 +00:00
fmt . Println ( "Creating Alice..." )
2018-03-31 19:33:32 +00:00
alice := peer . NewCwtchPeer ( "Alice" )
2018-05-28 18:36:04 +00:00
go alice . Listen ( )
2018-04-27 19:20:33 +00:00
fmt . Println ( "Alice created:" , alice . Profile . Onion )
2018-05-28 18:36:04 +00:00
fmt . Println ( "Creating Bob..." )
bob := peer . NewCwtchPeer ( "Bob" )
go bob . Listen ( )
fmt . Println ( "Bob created:" , bob . Profile . Onion )
fmt . Println ( "Waiting for alice and bob to connection with onion network..." )
time . Sleep ( time . Second * 60 )
2018-05-30 18:42:17 +00:00
numGoRoutinesPostPeerStart := runtime . NumGoroutine ( )
2018-05-28 18:36:04 +00:00
// ***** Peering and group creation / invite *****
fmt . Println ( "Creating group on " , serverAddr , "..." )
groupId , _ , err := alice . Profile . StartGroup ( serverAddr )
fmt . Printf ( "Created group: %v!\n" , groupId )
2018-04-27 19:20:33 +00:00
if err != nil {
2018-05-20 19:58:16 +00:00
t . Errorf ( "Failed to start group: %v" , err )
2018-04-27 19:20:33 +00:00
return
}
2018-05-28 18:36:04 +00:00
fmt . Println ( "Peering Alice peering with bob..." )
alice . PeerWithOnion ( bob . Profile . Onion )
2018-04-27 19:20:33 +00:00
2018-05-28 18:36:04 +00:00
time . Sleep ( time . Second * 15 )
2018-04-27 19:20:33 +00:00
2018-05-28 18:36:04 +00:00
fmt . Println ( "Alice inviting Bob to group..." )
err = alice . InviteOnionToGroup ( bob . Profile . Onion , groupId )
if err != nil {
t . Fatalf ( "Error for Alice inviting Bob to group: %v" , err )
}
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
2018-05-28 18:36:04 +00:00
fmt . Println ( "Bob examining groups and accepting invites..." )
for _ , group := range bob . Profile . Groups {
fmt . Printf ( "Bob group: %v (Accepted: %v)\n" , group . GroupID , group . Accepted )
if group . Accepted == false {
fmt . Printf ( "Bob received and accepting group invite: %v\n" , group . GroupID )
bob . AcceptInvite ( group . GroupID )
}
}
time . Sleep ( time . Second * 3 )
2018-04-27 19:20:33 +00:00
2018-05-30 18:42:17 +00:00
numGoRoutinesPostPeer := runtime . NumGoroutine ( )
2018-05-28 18:36:04 +00:00
fmt . Println ( "Alice joining server..." )
alice . JoinServer ( serverAddr )
2018-04-27 19:20:33 +00:00
2018-05-28 18:36:04 +00:00
fmt . Println ( "Bob joining server..." )
2018-04-27 19:20:33 +00:00
bob . JoinServer ( serverAddr )
2018-05-20 19:58:16 +00:00
// Wait for them to join the server
2018-05-30 18:42:17 +00:00
time . Sleep ( time . Second * 40 )
numGouRoutinesPostServerConnect := runtime . NumGoroutine ( )
2018-05-28 18:36:04 +00:00
// ***** Conversation *****
2018-04-27 19:20:33 +00:00
fmt . Println ( "Starting conversation in group..." )
2018-04-27 19:20:33 +00:00
// Conversation
fmt . Println ( "Alice> " , aliceLines [ 0 ] )
2018-05-20 19:58:16 +00:00
err = alice . SendMessageToGroup ( groupId , aliceLines [ 0 ] )
if err != nil {
2018-05-28 18:36:04 +00:00
t . Fatalf ( "Alice failed to send a message to the group: %v" , err )
2018-05-20 19:58:16 +00:00
}
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
fmt . Println ( "Bob> " , bobLines [ 0 ] )
2018-05-20 19:58:16 +00:00
err = bob . SendMessageToGroup ( groupId , bobLines [ 0 ] )
if err != nil {
2018-05-28 18:36:04 +00:00
t . Fatalf ( "Bob failed to send a message to the group: %v" , err )
2018-05-20 19:58:16 +00:00
}
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
2018-04-27 19:20:33 +00:00
// "instant" - could be either order?
2018-04-27 19:20:33 +00:00
fmt . Println ( "Alice> " , aliceLines [ 1 ] )
alice . SendMessageToGroup ( groupId , aliceLines [ 1 ] )
fmt . Println ( "Bob> " , bobLines [ 1 ] )
bob . SendMessageToGroup ( groupId , bobLines [ 1 ] )
2018-05-20 19:58:16 +00:00
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
fmt . Println ( "Alice> " , aliceLines [ 2 ] )
alice . SendMessageToGroup ( groupId , aliceLines [ 2 ] )
// Todo: Alice disconnects
2018-05-20 19:58:16 +00:00
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
fmt . Println ( "Bob> " , bobLines [ 2 ] )
bob . SendMessageToGroup ( groupId , bobLines [ 2 ] )
2018-05-20 19:58:16 +00:00
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
// Todo: Alice reconects, gets missed messages (from bob)
2018-05-28 18:36:04 +00:00
// ***** Verify Test *****
2018-04-27 19:20:33 +00:00
// final syncing time...
2018-05-30 18:42:17 +00:00
time . Sleep ( time . Second * 15 )
2018-04-27 19:20:33 +00:00
alicesGroup := alice . Profile . GetGroupByGroupID ( groupId )
fmt . Printf ( "alice Groups:\n" )
for k := range alice . Profile . Groups {
fmt . Println ( " " + k )
}
if alicesGroup == nil {
t . Error ( "aliceGroup == nil" )
return
}
2018-04-27 19:20:33 +00:00
fmt . Printf ( "Alice TimeLine:\n" )
2018-04-27 19:20:33 +00:00
printAndVerifyTimeline ( t , alicesGroup . GetTimeline ( ) )
2018-04-27 19:20:33 +00:00
2018-04-27 19:20:33 +00:00
bobsGroup := bob . Profile . GetGroupByGroupID ( groupId )
fmt . Printf ( "bob Groups:\n" )
for k := range bob . Profile . Groups {
fmt . Println ( " " + k )
}
if bobsGroup == nil {
t . Error ( "bobGroup == nil" )
return
}
2018-04-27 19:20:33 +00:00
fmt . Printf ( "Bob TimeLine:\n" )
2018-04-27 19:20:33 +00:00
printAndVerifyTimeline ( t , bobsGroup . GetTimeline ( ) )
2018-04-27 19:20:33 +00:00
if len ( alicesGroup . Timeline . Messages ) != 6 {
t . Errorf ( "Alice's timeline does not have all messages" )
return
}
// check message 0,1 and 4,5 for content (2,3 could be out of order)
2018-05-20 19:58:16 +00:00
aliceGroupTimeline := alicesGroup . GetTimeline ( )
if aliceGroupTimeline [ 0 ] . Message != aliceLines [ 0 ] || aliceGroupTimeline [ 1 ] . Message != bobLines [ 0 ] ||
aliceGroupTimeline [ 4 ] . Message != aliceLines [ 2 ] || aliceGroupTimeline [ 5 ] . Message != bobLines [ 2 ] {
t . Errorf ( "Some of the messages did not have the expected content!" )
2018-04-27 19:20:33 +00:00
}
// Todo: shutdown users and server
2018-05-30 18:42:17 +00:00
fmt . Println ( "Shutting down Bob..." )
bob . Shutdown ( )
time . Sleep ( time . Second * 3 )
numGoRoutinesPostBob := runtime . NumGoroutine ( )
if server != nil {
fmt . Println ( "Shutting down server..." )
server . Shutdown ( )
time . Sleep ( time . Second * 3 )
}
numGoRoutinesPostServerShutdown := runtime . NumGoroutine ( )
fmt . Println ( "Shutting down Alice..." )
alice . Shutdown ( )
time . Sleep ( time . Second * 3 )
numGoRoutinesPostAlice := runtime . NumGoroutine ( )
fmt . Printf ( "numGoRoutinesStart: %v\nnumGoRoutinesPostServer: %v\nnumGoRoutinesPostPeerStart: %v\nnumGoRoutinesPostPeer: %v\nnumGouRoutinesPostServerConnect: %v\nnumGoRoutinesPostBob: %v\nnumGoRoutinesPostServerShutdown: %v\nnumGoRoutinesPostAlice: %v\n" ,
numGoRoutinesStart , numGoRoutinesPostServer , numGoRoutinesPostPeerStart , numGoRoutinesPostPeer , numGouRoutinesPostServerConnect ,
numGoRoutinesPostBob , numGoRoutinesPostServerShutdown , numGoRoutinesPostAlice )
if numGoRoutinesPostServer != numGoRoutinesPostAlice {
t . Errorf ( "Number of GoRoutines once server checks were completed (%v) does not match number of goRoutines after cleanup of peers and servers (%v), clean up failed, leak detected!" , numGoRoutinesPostServer , numGoRoutinesPostAlice )
}
2018-03-30 21:16:51 +00:00
}