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
"os"
2018-05-30 18:42:17 +00:00
"runtime"
2018-05-20 19:58:16 +00:00
"testing"
"time"
2018-06-05 22:06:38 +00:00
"crypto/rsa"
"io/ioutil"
"log"
2018-03-30 21:16:51 +00:00
)
2018-04-27 19:20:33 +00:00
const (
2018-06-05 22:06:38 +00:00
serverKeyfile = "./../server/app/private_key"
localKeyfile = "./private_key"
2018-04-27 19:20:33 +00:00
)
var (
2018-06-05 22:06:38 +00:00
aliceLines = [ ] string { "Hello, I'm Alice" , "bye" }
bobLines = [ ] string { "Hi, my name is Bob." , "toodles" , "welcome" }
carolLines = [ ] string { "Howdy, thanks!" }
2018-04-27 19:20:33 +00:00
)
2018-06-05 22:06:38 +00:00
func loadOrGenPrivateKey ( t * testing . T ) ( pk * rsa . PrivateKey , generated bool ) {
if _ , err := os . Stat ( serverKeyfile ) ; 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-06-05 22:06:38 +00:00
t . Fatalf ( "error generating new private key: %v\n" , err )
2018-04-27 19:20:33 +00:00
}
2018-06-05 22:06:38 +00:00
err = ioutil . WriteFile ( localKeyfile , [ ] byte ( utils . PrivateKeyToString ( pk ) ) , 0400 )
2018-04-27 19:20:33 +00:00
if err != nil {
2018-06-05 22:06:38 +00:00
log . Fatalf ( "error writing new private key to file %s: %v\n" , localKeyfile , err )
2018-04-27 19:20:33 +00:00
}
2018-06-05 22:06:38 +00:00
return pk , true
2018-04-27 19:20:33 +00:00
}
2018-06-05 22:06:38 +00:00
fmt . Println ( "Found server key " + serverKeyfile + ", loading..." )
pk , err := utils . LoadPrivateKeyFromFile ( serverKeyfile )
if err != nil {
t . Fatalf ( "Could not load server's key from %v" , serverKeyfile )
}
return pk , false
2018-04-27 19:20:33 +00:00
}
2018-06-05 22:06:38 +00:00
func printAndCountVerifedTimeline ( t * testing . T , timeline [ ] model . Message ) int {
numVerified := 0
2018-05-20 19:58:16 +00:00
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 )
2018-06-05 22:06:38 +00:00
if message . Verified {
numVerified ++
2018-04-27 19:20:33 +00:00
}
}
2018-06-05 22:06:38 +00:00
return numVerified
2018-04-27 19:20:33 +00:00
}
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-06-05 22:06:38 +00:00
serverKey , generatedKey := loadOrGenPrivateKey ( t )
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" )
2018-06-05 22:06:38 +00:00
go server . Run ( localKeyfile )
2018-04-27 19:20:33 +00:00
// 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 )
2018-06-05 22:06:38 +00:00
fmt . Println ( "Creating Carol..." )
carol := peer . NewCwtchPeer ( "Carol" )
go carol . Listen ( )
fmt . Println ( "Carol created:" , carol . Profile . Onion )
fmt . Println ( "Waiting for Alice, Bob, and Carol to connection with onion network..." )
time . Sleep ( time . Second * 70 )
2018-05-30 18:42:17 +00:00
numGoRoutinesPostPeerStart := runtime . NumGoroutine ( )
2018-05-28 18:36:04 +00:00
2018-06-05 22:06:38 +00:00
// ***** Peering, server joining, group creation / invite *****
2018-05-28 18:36:04 +00:00
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-06-05 22:06:38 +00:00
t . Errorf ( "Failed to init group: %v" , err )
2018-04-27 19:20:33 +00:00
return
}
2018-06-05 22:06:38 +00:00
fmt . Println ( "Alice peering with Bob..." )
2018-05-28 18:36:04 +00:00
alice . PeerWithOnion ( bob . Profile . Onion )
2018-06-05 22:06:38 +00:00
fmt . Println ( "Alice peering with Carol..." )
alice . PeerWithOnion ( carol . Profile . Onion )
2018-04-27 19:20:33 +00:00
2018-06-05 22:06:38 +00:00
fmt . Println ( "Alice joining server..." )
alice . JoinServer ( serverAddr )
fmt . Println ( "Bob joining server..." )
bob . JoinServer ( serverAddr )
fmt . Println ( "Waiting for peerings and server joins..." )
time . Sleep ( time . Second * 60 )
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 )
}
}
2018-06-05 22:06:38 +00:00
time . Sleep ( time . Second * 5 )
2018-04-27 19:20:33 +00:00
2018-06-05 22:06:38 +00:00
numGoRoutinesPostServerConnect := runtime . NumGoroutine ( )
2018-05-30 18:42:17 +00:00
2018-06-05 22:06:38 +00:00
// ***** Fill up message history of server ******
2018-04-27 19:20:33 +00:00
2018-06-05 22:06:38 +00:00
/ *
// filler group will be used to fill up the servers message history a bit to stress test fetch later for carol
fillerGroupId , _ , err := alice . Profile . StartGroup ( serverAddr )
if err != nil {
t . Errorf ( "Failed to init filler group: %v" , err )
return
}
fmt . Println ( "Alice filling message history of server..." )
for i := 0 ; i < 100 ; i ++ {
go func ( x int ) {
time . Sleep ( time . Second * time . Duration ( x ) )
err := alice . SendMessageToGroup ( fillerGroupId , aliceLines [ 0 ] )
if err != nil {
fmt . Println ( "SEND" , x , "ERROR:" , err )
} else {
fmt . Println ( "SEND" , x , " SUCCESS!" )
}
} ( i )
}
2018-04-27 19:20:33 +00:00
2018-06-05 22:06:38 +00:00
time . Sleep ( time . Second * 110 )
* /
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
fmt . Println ( "Alice> " , aliceLines [ 1 ] )
alice . SendMessageToGroup ( groupId , aliceLines [ 1 ] )
2018-06-05 22:06:38 +00:00
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
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
2018-06-05 22:06:38 +00:00
fmt . Println ( "Alice inviting Carol to group..." )
err = alice . InviteOnionToGroup ( carol . Profile . Onion , groupId )
if err != nil {
t . Fatalf ( "Error for Alice inviting Carol to group: %v" , err )
}
2018-05-20 19:58:16 +00:00
time . Sleep ( time . Second * 10 )
2018-06-05 22:06:38 +00:00
fmt . Println ( "Carol examining groups and accepting invites..." )
for _ , group := range carol . Profile . Groups {
fmt . Printf ( "Carol group: %v (Accepted: %v)\n" , group . GroupID , group . Accepted )
if group . Accepted == false {
fmt . Printf ( "Carol received and accepting group invite: %v\n" , group . GroupID )
carol . AcceptInvite ( group . GroupID )
}
}
fmt . Println ( "Shutting down Alice..." )
alice . Shutdown ( )
time . Sleep ( time . Second * 5 )
numGoRoutinesPostAlice := runtime . NumGoroutine ( )
fmt . Println ( "Carol joining server..." )
carol . JoinServer ( serverAddr )
time . Sleep ( time . Second * 60 )
numGoRotinesPostCarolConnect := runtime . NumGoroutine ( )
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
2018-06-05 22:06:38 +00:00
fmt . Println ( "Carol> " , carolLines [ 0 ] )
carol . SendMessageToGroup ( groupId , carolLines [ 0 ] )
time . Sleep ( time . Second * 10 )
2018-04-27 19:20:33 +00:00
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 )
if alicesGroup == nil {
t . Error ( "aliceGroup == nil" )
return
}
2018-04-27 19:20:33 +00:00
2018-06-05 22:06:38 +00:00
fmt . Printf ( "Alice's TimeLine:\n" )
aliceVerified := printAndCountVerifedTimeline ( t , alicesGroup . GetTimeline ( ) )
if aliceVerified != 4 {
t . Errorf ( "Alice did not have 4 verified messages" )
}
2018-04-27 19:20:33 +00:00
2018-04-27 19:20:33 +00:00
bobsGroup := bob . Profile . GetGroupByGroupID ( groupId )
if bobsGroup == nil {
t . Error ( "bobGroup == nil" )
return
}
2018-06-05 22:06:38 +00:00
fmt . Printf ( "Bob's TimeLine:\n" )
bobVerified := printAndCountVerifedTimeline ( t , bobsGroup . GetTimeline ( ) )
if bobVerified != 5 {
t . Errorf ( "Bob did not have 5 verified messages" )
}
carolsGroup := carol . Profile . GetGroupByGroupID ( groupId )
fmt . Printf ( "Carol's TimeLine:\n" )
carolVerified := printAndCountVerifedTimeline ( t , carolsGroup . GetTimeline ( ) )
if carolVerified != 3 {
t . Errorf ( "Carol did not have 3 verified messages" )
}
2018-04-27 19:20:33 +00:00
2018-06-05 22:06:38 +00:00
if len ( alicesGroup . GetTimeline ( ) ) != 4 {
2018-04-27 19:20:33 +00:00
t . Errorf ( "Alice's timeline does not have all messages" )
return
}
2018-06-05 22:06:38 +00:00
if len ( bobsGroup . GetTimeline ( ) ) != 6 {
t . Errorf ( "Bob's timeline does not have all messages" )
}
// check message 0,1,2,3
2018-05-20 19:58:16 +00:00
aliceGroupTimeline := alicesGroup . GetTimeline ( )
if aliceGroupTimeline [ 0 ] . Message != aliceLines [ 0 ] || aliceGroupTimeline [ 1 ] . Message != bobLines [ 0 ] ||
2018-06-05 22:06:38 +00:00
aliceGroupTimeline [ 2 ] . Message != aliceLines [ 1 ] || aliceGroupTimeline [ 3 ] . Message != bobLines [ 1 ] {
t . Errorf ( "Some of Alice's timeline messages did not have the expected content!" )
}
// check message 0,1,2,3,4,5
bobGroupTimeline := bobsGroup . GetTimeline ( )
if bobGroupTimeline [ 0 ] . Message != aliceLines [ 0 ] || bobGroupTimeline [ 1 ] . Message != bobLines [ 0 ] ||
bobGroupTimeline [ 2 ] . Message != aliceLines [ 1 ] || bobGroupTimeline [ 3 ] . Message != bobLines [ 1 ] ||
bobGroupTimeline [ 4 ] . Message != bobLines [ 2 ] || bobGroupTimeline [ 5 ] . Message != carolLines [ 0 ] {
t . Errorf ( "Some of Bob's timeline messages did not have the expected content!" )
}
if len ( carolsGroup . GetTimeline ( ) ) != 6 {
t . Errorf ( "Carol's timeline does not have all messages" )
}
// check message 0,1,2,3,4,5
carolGroupTimeline := carolsGroup . GetTimeline ( )
if carolGroupTimeline [ 0 ] . Message != aliceLines [ 0 ] || carolGroupTimeline [ 1 ] . Message != bobLines [ 0 ] ||
carolGroupTimeline [ 2 ] . Message != aliceLines [ 1 ] || carolGroupTimeline [ 3 ] . Message != bobLines [ 1 ] ||
carolGroupTimeline [ 4 ] . Message != bobLines [ 2 ] || carolGroupTimeline [ 5 ] . Message != carolLines [ 0 ] {
t . Errorf ( "Some of Carol's timeline messages did not have the expected content!" )
2018-04-27 19:20:33 +00:00
}
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 ( )
2018-06-05 22:06:38 +00:00
fmt . Println ( "Shuttind down Carol..." )
carol . Shutdown ( )
2018-05-30 18:42:17 +00:00
time . Sleep ( time . Second * 3 )
2018-06-05 22:06:38 +00:00
numGoRoutinesPostCarol := runtime . NumGoroutine ( )
2018-05-30 18:42:17 +00:00
2018-06-05 22:06:38 +00:00
fmt . Printf ( "numGoRoutinesStart: %v\nnumGoRoutinesPostServer: %v\nnumGoRoutinesPostPeerStart: %v\nnumGoRoutinesPostPeerAndServerConnect: %v\n" +
"numGoRoutinesPostAlice: %v\nnumGoRotinesPostCarolConnect: %v\nnumGoRoutinesPostBob: %v\nnumGoRoutinesPostServerShutdown: %v\nnumGoRoutinesPostCarol: %v\n" ,
numGoRoutinesStart , numGoRoutinesPostServer , numGoRoutinesPostPeerStart , numGoRoutinesPostServerConnect ,
numGoRoutinesPostAlice , numGoRotinesPostCarolConnect , numGoRoutinesPostBob , numGoRoutinesPostServerShutdown , numGoRoutinesPostCarol )
2018-05-30 18:42:17 +00:00
2018-06-05 22:06:38 +00:00
if numGoRoutinesPostServer != numGoRoutinesPostCarol {
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 , numGoRoutinesPostCarol )
2018-05-30 18:42:17 +00:00
}
2018-03-30 21:16:51 +00:00
}