Matrix/workloadGenerator.go
2020-11-27 05:52:27 +01:00

638 lines
16 KiB
Go

package main
import (
"bytes"
"crypto/tls"
"encoding/base64"
"encoding/csv"
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"strconv"
"strings"
"time"
"git.nutfactory.org/hoernschen/Matrix/entities/event"
"git.nutfactory.org/hoernschen/Matrix/entities/general"
"git.nutfactory.org/hoernschen/Matrix/entities/room"
"git.nutfactory.org/hoernschen/Matrix/entities/user"
"git.nutfactory.org/hoernschen/Matrix/utils"
)
var BaseLineTest = false
var systemParamsIndex = 0
type SystemParams struct {
Id string
BytesToSend int
MessagesPerSecond float32
Distribution map[string][]string
Packetloss int
MinutesNotAvailable int
Consensus bool
AuthentificationCheck bool
Signing bool
Encryption bool
}
var httpString string
var users = []map[string][]string{
map[string][]string{
"143.93.38.208": []string{
"user1",
"user2",
"user3",
"user4",
},
},
map[string][]string{
"143.93.38.207": []string{
"user1",
"user2",
"user3",
"user4",
},
"143.93.38.208": []string{
"user1",
},
"143.93.38.209": []string{
"user1",
},
},
map[string][]string{
"143.93.38.207": []string{
"user1",
"user2",
"user3",
"user4",
},
"143.93.38.208": []string{
"user1",
"user2",
"user3",
"user4",
},
"143.93.38.209": []string{
"user1",
"user2",
"user3",
"user4",
},
},
map[string][]string{
"localhost": []string{
"user1",
"user2",
"user3",
"user4",
},
},
}
/*
var servers = []string{
"143.93.38.207",
"143.93.38.208",
"143.93.38.209",
}
*/
var servers = []string{
"localhost",
}
var systemParams = []SystemParams{
SystemParams{
Id: "111111111",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[3],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
/*
SystemParams{
Id: "011111111",
BytesToSend: 8,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "211111111",
BytesToSend: 512,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "101111111",
BytesToSend: 280,
MessagesPerSecond: 0.1,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "121111111",
BytesToSend: 280,
MessagesPerSecond: 10.0,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "110111111",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[0],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "112111111",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[2],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "111011111",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 0,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "111211111",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 20,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "111121111",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 1,
Consensus: true,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "111110111",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: false,
AuthentificationCheck: true,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "111111011",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: false,
Signing: true,
Encryption: true,
},
SystemParams{
Id: "111111101",
BytesToSend: 280,
MessagesPerSecond: 1.0,
Distribution: users[1],
Packetloss: 1,
MinutesNotAvailable: 0,
Consensus: true,
AuthentificationCheck: true,
Signing: false,
Encryption: true,
},
*/
}
var userIds []string
var accessTokens map[string]string
var roomId string
func getCSVWriter(filename string) (writer *csv.Writer) {
file, err := os.Create(fmt.Sprintf("%s %s.csv", strconv.FormatInt(time.Now().Unix(), 10), filename))
if err != nil {
log.Fatalf("Error Creating CSV: %s", err)
}
defer file.Close()
writer = csv.NewWriter(file)
return
}
func main() {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
httpString = "https"
iteration := 0
if BaseLineTest {
file, err := os.Create(fmt.Sprintf("%s Baseline Measurement.csv", strconv.FormatInt(time.Now().Unix(), 10)))
if err != nil {
log.Fatalf("Error Creating CSV: %s", err)
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
err = writer.Write([]string{"Iteration", "Start", "End"})
if err != nil {
log.Fatalf("Error in Writing CSV: %s", err)
}
for iteration < 10 {
log.Printf("Iteration: %s", strconv.Itoa(iteration))
start := time.Now().Unix()
time.Sleep(2 * time.Minute)
end := time.Now().Unix()
iteration++
err = writer.Write([]string{strconv.Itoa(iteration), strconv.FormatInt(start, 10), strconv.FormatInt(end, 10)})
if err != nil {
log.Fatalf("Error in Writing CSV: %s", err)
}
}
} else {
for _, systemParam := range systemParams {
file, err := os.Create(fmt.Sprintf("%s %s Measurement Matrix.csv", strconv.FormatInt(time.Now().Unix(), 10), systemParam.Id))
if err != nil {
log.Fatalf("Error Creating CSV: %s", err)
}
writer := csv.NewWriter(file)
err = writer.Write([]string{"Iteration", "Start", "End", "Actions Send"})
if err != nil {
log.Fatalf("Error in Writing CSV: %s", err)
}
millisecondsToWait := 1000 / systemParam.MessagesPerSecond
iteration = 0
for iteration < 30 {
err := setUp(systemParam)
if err != nil {
log.Fatalf("Error in SetUp: %s", err)
}
b := make([]byte, systemParam.BytesToSend)
_, err = rand.Read(b)
message := base64.RawStdEncoding.EncodeToString(b)
start := time.Now()
end := start.Add(2 * time.Minute).Unix()
log.Printf("Id: %s - Iteration: %s - Start: %s - End: %s", systemParam.Id, strconv.Itoa(iteration), strconv.FormatInt(start.Unix(), 10), strconv.FormatInt(end, 10))
actionsSend := 0
for time.Now().Unix() < end {
time.Sleep(time.Duration(millisecondsToWait) * time.Millisecond)
err = sendMessage(message)
if err != nil {
log.Fatalf("Error sending Message %s", err)
}
actionsSend++
}
iteration++
err = writer.Write([]string{strconv.Itoa(iteration), strconv.FormatInt(start.Unix(), 10), strconv.FormatInt(end, 10), strconv.Itoa(actionsSend)})
if err != nil {
log.Fatalf("Error in Writing CSV: %s", err)
}
time.Sleep(1 * time.Second)
err = reset()
if err != nil {
log.Fatalf("Error in Reset: %s", err)
}
time.Sleep(1 * time.Second)
}
writer.Flush()
file.Close()
}
}
}
func sendMessage(message string) (err error) {
userIndex := rand.Intn(3)
userId := userIds[userIndex]
accessToken := accessTokens[userId]
err, txnId := utils.CreateUUID()
if err != nil {
return
}
requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/rooms/%s/send/m.room.message/%s", httpString, strings.Split(userId, ":")[1], roomId, txnId)
request := event.SendMessageRequest{
MessageType: "m.text",
Body: message,
}
reqBody, err := json.Marshal(request)
if err != nil {
return
}
client := &http.Client{}
var req *http.Request
req, err = http.NewRequest(http.MethodPut, requestUrl, bytes.NewBuffer(reqBody))
if err != nil {
return
}
req.Header["Content-Type"] = []string{"application/json"}
req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)}
res, err := client.Do(req)
if err != nil {
return
}
if res.StatusCode != http.StatusOK {
handleError(res)
}
return
}
func setParams(systemParamsToUse SystemParams) (err error) {
serverNotAvailableIndex := 1
for i, server := range servers {
minutesNotAvailable := 0
if serverNotAvailableIndex == i {
minutesNotAvailable = systemParamsToUse.MinutesNotAvailable
}
requestUrl := fmt.Sprintf("%s://%s/setparams", httpString, server)
request := general.SetParamBody{
Packetloss: systemParamsToUse.Packetloss,
UnavailableTill: time.Now().Add(time.Duration(minutesNotAvailable) * time.Minute).Unix(),
Consensus: systemParamsToUse.Consensus,
AuthentificationCheck: systemParamsToUse.AuthentificationCheck,
Signing: systemParamsToUse.Signing,
Encryption: systemParamsToUse.Encryption,
}
var reqBody []byte
reqBody, err = json.Marshal(request)
if err != nil {
return
}
client := &http.Client{Timeout: 10 * time.Second}
var req *http.Request
req, err = http.NewRequest(http.MethodGet, requestUrl, bytes.NewBuffer(reqBody))
if err != nil {
return
}
req.Header["Content-Type"] = []string{"application/json"}
var res *http.Response
res, err = client.Do(req)
if err != nil {
return
}
if res.StatusCode != http.StatusOK {
handleError(res)
}
}
return
}
func setUp(systemParamsToUse SystemParams) (err error) {
accessTokens = make(map[string]string)
err = createUsers(systemParamsToUse.Distribution)
if err != nil {
log.Printf("Error in User-Creation: %s", err)
return
}
// Create Room
err = createRoom(userIds[0])
if err != nil {
log.Printf("Error in Room-Creation: %s", err)
return
}
// Join to Room
err = joinRoom(userIds[1:])
if err != nil {
log.Printf("Error joining Room: %s", err)
return
}
err = setParams(systemParamsToUse)
return
}
func reset() (err error) {
roomId = ""
userIds = []string{}
accessTokens = make(map[string]string)
for _, server := range servers {
requestUrl := fmt.Sprintf("%s://%s/reset", httpString, server)
client := &http.Client{Timeout: 10 * time.Second}
var req *http.Request
req, err = http.NewRequest(http.MethodGet, requestUrl, bytes.NewBuffer(nil))
if err != nil {
return
}
req.Header["Content-Type"] = []string{"application/json"}
var res *http.Response
res, err = client.Do(req)
if err != nil {
return
}
if res.StatusCode != http.StatusOK {
handleError(res)
}
}
return
}
func createRoom(userId string) (err error) {
accessToken := accessTokens[userId]
requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/createRoom", httpString, strings.Split(userId, ":")[1])
request := room.CreateRoomRequest{
Visibility: "public",
Name: "Testraum",
Topic: "Raum für die Energieeffizienz-Tests",
RoomVersion: "1",
CreationContent: room.CreationContent{
Federated: true,
},
Preset: "public_chat",
IsDirect: true,
}
reqBody, err := json.Marshal(request)
if err != nil {
return
}
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody))
if err != nil {
return
}
req.Header["Content-Type"] = []string{"application/json"}
req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)}
res, err := client.Do(req)
if err != nil {
return
}
if res.StatusCode != http.StatusOK {
handleError(res)
} else {
response := room.CreateRoomResponse{}
decoder := json.NewDecoder(res.Body)
err = decoder.Decode(&response)
if err != nil {
return
}
roomId = response.RoomId
log.Printf("Room created: %s", roomId)
}
return
}
func joinRoom(userIdsToJoin []string) (err error) {
for _, userId := range userIdsToJoin {
err = joinRoomUser(userId)
if err != nil {
return
}
//time.Sleep(time.Duration(1) * time.Second)
}
return
}
func joinRoomUser(userId string) (err error) {
log.Printf("Join %s to %s", userId, roomId)
accessToken := accessTokens[userId]
requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/rooms/%s/join", httpString, strings.Split(userId, ":")[1], roomId)
request := room.JoinRoomUserRequest{}
reqBody, err := json.Marshal(request)
if err != nil {
return
}
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody))
if err != nil {
return
}
req.Header["Content-Type"] = []string{"application/json"}
req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)}
res, err := client.Do(req)
if err != nil {
return
}
if res.StatusCode != http.StatusOK {
handleError(res)
} else {
response := room.JoinRoomUserResponse{}
decoder := json.NewDecoder(res.Body)
err = decoder.Decode(&response)
if err != nil {
return
}
roomId = response.RoomId
log.Printf("%s joined Room", userId)
}
return
}
func createUsers(serverUserMap map[string][]string) (err error) {
for server, usersToCreate := range serverUserMap {
for _, userToCreate := range usersToCreate {
var userId string
var accessToken string
userId, accessToken, err = createUser(userToCreate, server)
if err != nil {
return
}
if userId != "" && accessToken != "" {
log.Printf("%s created - AccessToken: %s", userId, accessToken)
accessTokens[userId] = accessToken
userIds = append(userIds, userId)
}
}
}
return
}
func createUser(userToCreate string, homeserver string) (userId string, accessToken string, err error) {
requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/register", httpString, homeserver)
request := user.RegisterRequest{
Auth: user.AuthentificationData{
LoginType: "m.login.password",
},
Username: userToCreate,
Password: "password",
DeviceName: fmt.Sprintf("%s's device", userToCreate),
}
reqBody, err := json.Marshal(request)
if err != nil {
return
}
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody))
if err != nil {
return
}
req.Header["Content-Type"] = []string{"application/json"}
res, err := client.Do(req)
if err != nil {
return
}
if res.StatusCode != http.StatusOK {
handleError(res)
} else {
response := user.RegisterResponse{}
decoder := json.NewDecoder(res.Body)
err = decoder.Decode(&response)
if err != nil {
return
}
userId = response.UserId
accessToken = response.AccessToken
}
return
}
func handleError(res *http.Response) {
utils.HandleHTTPError(res)
}