Files
openfsd/test/fsd_client_logic_test.go
Reese Norris 57d54d6705 v0.1.0-alpha
Changes:
- Implement bootstrapping library for managing several concurrent internal services
- Refactor concurrency model for connections/logical clients and their associated I/O
- Refactor server context singleton
- Refactor error handling
    - Most errors are now gracefully sent to the FSD client directly encoded as an $ER packet,
      enhancing visibility and debugging
    - Most errors are now rightfully treated as non-fatal
- Refactor package/dependency graph
- Refactor calling conventions/interfaces for many packages
- Refactor database package
- Refactor post office

Features:
- Add VATSIM-esque HTTP/JSON "data feed"
- Add ephemeral in-memory database option
- Add user management REST API
- Add improved web interface
- Add MySQL support (drop SQLite support)
2024-10-07 12:50:39 -07:00

1073 lines
29 KiB
Go

package test
import (
"bufio"
"bytes"
"context"
"encoding/json"
"errors"
"github.com/renorris/openfsd/auth"
"github.com/renorris/openfsd/bootstrap"
"github.com/renorris/openfsd/database"
"github.com/renorris/openfsd/protocol"
"github.com/renorris/openfsd/servercontext"
"github.com/stretchr/testify/assert"
"io"
"net"
"net/http"
"os"
"strconv"
"strings"
"sync"
"testing"
"time"
)
type clientStruct struct {
callsign string
cid int
password string
clientID uint16
clientName string
majorVersion int
minorVersion int
sysUID int
initialChallenge string
networkRating int
protocolRevsion int
simulatorType int
realName string
preliminaryTestPackets []protocol.PDU // Packets to send after logging in, but before the next browser logs in
preliminaryWantPackets []protocol.PDU // Expected packets to receive before the next browser logs in
testPackets []protocol.PDU // Packets to send in normal post-login state
wantPackets []protocol.PDU // Expected packets to receive
}
// TestFSDClientLogic focuses on post-login logic
func TestFSDClientLogic(t *testing.T) {
if err := os.Setenv("IN_MEMORY_DB", "true"); err != nil {
t.Fatal(err)
}
// Start the server
ctx, cancelCtx := context.WithCancel(context.Background())
b := bootstrap.NewDefaultBootstrap()
if err := b.Start(ctx); err != nil {
t.Fatal(err)
}
// Add test user
user1 := database.FSDUserRecord{
Email: "example@mail.com",
FirstName: "Test User 1",
LastName: "Test User 1 Lastname",
Password: "54321",
FSDPassword: "12345",
NetworkRating: protocol.NetworkRatingOBS,
PilotRating: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
var err error
user1.CID, err = user1.Insert(servercontext.DB())
assert.Nil(t, err)
user2 := database.FSDUserRecord{
Email: "example@mail.com",
FirstName: "Test User 2",
LastName: "Test User 2 Lastname",
Password: "54321",
FSDPassword: "12345",
NetworkRating: protocol.NetworkRatingOBS,
PilotRating: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
user2.CID, err = user2.Insert(servercontext.DB())
assert.Nil(t, err)
user3 := database.FSDUserRecord{
Email: "example@mail.com",
FirstName: "Test User 3",
LastName: "Test User 3 Lastname",
Password: "54321",
FSDPassword: "12345",
NetworkRating: protocol.NetworkRatingSUP,
PilotRating: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
user3.CID, err = user3.Insert(servercontext.DB())
assert.Nil(t, err)
tests := []struct {
testName string
clients []clientStruct
}{
{
testName: "Ping ($PI) request",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.PingPDU{
From: "N123",
To: protocol.ServerCallsign,
Timestamp: "1234567890",
},
},
wantPackets: []protocol.PDU{
&protocol.PongPDU{
From: protocol.ServerCallsign,
To: "N123",
Timestamp: "1234567890",
},
},
},
},
},
{
testName: "IP request ($CQCLIENT:SERVER:IP)",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.ClientQueryPDU{
From: "N123",
To: protocol.ServerCallsign,
QueryType: protocol.ClientQueryPublicIP,
Payload: "",
},
},
wantPackets: []protocol.PDU{
&protocol.ClientQueryResponsePDU{
From: protocol.ServerCallsign,
To: "N123",
QueryType: protocol.ClientQueryPublicIP,
Payload: "127.0.0.1",
},
},
},
},
},
{
testName: "Fast pilot position broadcast",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N123",
SquawkCode: "1200",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
&protocol.PingPDU{
From: "N123",
To: protocol.ServerCallsign,
Timestamp: "1234567890",
},
},
preliminaryWantPackets: []protocol.PDU{
&protocol.PongPDU{
From: protocol.ServerCallsign,
To: "N123",
Timestamp: "1234567890",
},
},
testPackets: []protocol.PDU{},
wantPackets: []protocol.PDU{
&protocol.AddPilotPDU{
From: "N124",
To: protocol.ServerCallsign,
CID: user2.CID,
Token: "",
NetworkRating: 1,
ProtocolRevision: protocol.ProtoRevisionVatsim2022,
SimulatorType: 2,
RealName: "Foo Bar",
},
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N124",
SquawkCode: "1201",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
&protocol.FastPilotPositionPDU{
Type: protocol.FastPilotPositionTypeFast,
From: "N124",
Lat: 45,
Lng: 45,
AltitudeTrue: 10,
AltitudeAgl: 10,
Pitch: 0,
Heading: 0,
Bank: 0,
PositionalVelocityVector: protocol.VelocityVector{
X: 10,
Y: 10,
Z: 10,
},
RotationalVelocityVector: protocol.VelocityVector{
X: 10,
Y: 10,
Z: 10,
},
NoseGearAngle: 15,
},
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N124",
SquawkCode: "1201",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
},
},
{
callsign: "N124",
cid: user2.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "Foo Bar",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N124",
SquawkCode: "1201",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
&protocol.FastPilotPositionPDU{
Type: protocol.FastPilotPositionTypeFast,
From: "N124",
Lat: 45,
Lng: 45,
AltitudeTrue: 10,
AltitudeAgl: 10,
Pitch: 0,
Heading: 0,
Bank: 0,
PositionalVelocityVector: protocol.VelocityVector{
X: 10,
Y: 10,
Z: 10,
},
RotationalVelocityVector: protocol.VelocityVector{
X: 10,
Y: 10,
Z: 10,
},
NoseGearAngle: 15,
},
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N124",
SquawkCode: "1201",
NetworkRating: 1,
Lat: -45.0,
Lng: -45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
&protocol.FastPilotPositionPDU{
Type: protocol.FastPilotPositionTypeFast,
From: "N124",
Lat: -45,
Lng: -45,
AltitudeTrue: 10,
AltitudeAgl: 10,
Pitch: 0,
Heading: 0,
Bank: 0,
PositionalVelocityVector: protocol.VelocityVector{
X: 10,
Y: 10,
Z: 10,
},
RotationalVelocityVector: protocol.VelocityVector{
X: 10,
Y: 10,
Z: 10,
},
NoseGearAngle: 15,
},
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N124",
SquawkCode: "1201",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
},
wantPackets: []protocol.PDU{},
},
},
},
{
testName: "Pilot position broadcast",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N123",
SquawkCode: "1200",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{},
wantPackets: []protocol.PDU{
&protocol.AddPilotPDU{
From: "N124",
To: protocol.ServerCallsign,
CID: user2.CID,
Token: "",
NetworkRating: 1,
ProtocolRevision: protocol.ProtoRevisionVatsim2022,
SimulatorType: 2,
RealName: "Foo Bar",
},
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N124",
SquawkCode: "1200",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
},
},
{
callsign: "N124",
cid: user2.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "Foo Bar",
preliminaryTestPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.PilotPositionPDU{
SquawkingModeC: false,
Identing: false,
From: "N124",
SquawkCode: "1200",
NetworkRating: 1,
Lat: 45.0,
Lng: 45.0,
TrueAltitude: 50,
PressureAltitude: 50,
GroundSpeed: 0,
Pitch: 0,
Heading: 0,
Bank: 0,
},
},
wantPackets: []protocol.PDU{},
},
},
},
{
testName: "Client Query Real Name ($CQN123:N124:RN)",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{},
wantPackets: []protocol.PDU{
&protocol.AddPilotPDU{
From: "N124",
To: protocol.ServerCallsign,
CID: user2.CID,
Token: "",
NetworkRating: 1,
ProtocolRevision: protocol.ProtoRevisionVatsim2022,
SimulatorType: 2,
RealName: "Foo Bar",
},
&protocol.ClientQueryPDU{
From: "N124",
To: "N123",
QueryType: protocol.ClientQueryRealName,
Payload: "",
},
},
},
{
callsign: "N124",
cid: user2.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "Foo Bar",
preliminaryTestPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.ClientQueryPDU{
From: "N124",
To: "N123",
QueryType: protocol.ClientQueryRealName,
Payload: "",
},
},
wantPackets: []protocol.PDU{},
},
},
},
{
testName: "Client Query Real Name Response ($CRN124:N123:RN:Foo Bar)",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
testPackets: []protocol.PDU{},
wantPackets: []protocol.PDU{
&protocol.AddPilotPDU{
From: "N124",
To: protocol.ServerCallsign,
CID: user2.CID,
Token: "",
NetworkRating: 1,
ProtocolRevision: protocol.ProtoRevisionVatsim2022,
SimulatorType: 2,
RealName: "Foo Bar",
},
&protocol.ClientQueryResponsePDU{
From: "N124",
To: "N123",
QueryType: protocol.ClientQueryRealName,
Payload: "Foo Bar",
},
},
},
{
callsign: "N124",
cid: user2.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "Foo Bar",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.ClientQueryResponsePDU{
From: "N124",
To: "N123",
QueryType: protocol.ClientQueryRealName,
Payload: "Foo Bar",
},
},
wantPackets: []protocol.PDU{},
},
},
},
{
testName: "Authentication challenge ($ZC)",
clients: []clientStruct{
{
callsign: "N123",
cid: user2.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "30984979d8caed23",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.AuthChallengePDU{
From: "N123",
To: protocol.ServerCallsign,
Challenge: "de6acb8e",
},
},
wantPackets: []protocol.PDU{
&protocol.AuthChallengeResponsePDU{
From: protocol.ServerCallsign,
To: "N123",
ChallengeResponse: "f8ee97157f66455ed6108fccef6ccf5f",
},
},
},
},
},
{
testName: "kill ($!!)",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{},
wantPackets: []protocol.PDU{
&protocol.AddPilotPDU{
From: "SUP",
To: protocol.ServerCallsign,
CID: user3.CID,
Token: "",
NetworkRating: protocol.NetworkRatingSUP,
ProtocolRevision: protocol.ProtoRevisionVatsim2022,
SimulatorType: 2,
RealName: "Supervisor",
},
&protocol.KillRequestPDU{
From: "SUP",
To: "N123",
Reason: "ur banned",
},
},
},
{
callsign: "SUP",
cid: user3.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: protocol.NetworkRatingSUP,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "Supervisor",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.KillRequestPDU{
From: "SUP",
To: "N123",
Reason: "ur banned",
},
},
wantPackets: []protocol.PDU{},
},
},
},
{
testName: "kill not allowed",
clients: []clientStruct{
{
callsign: "N123",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{},
wantPackets: []protocol.PDU{
&protocol.AddPilotPDU{
From: "N124",
To: protocol.ServerCallsign,
CID: user2.CID,
Token: "",
NetworkRating: protocol.NetworkRatingOBS,
ProtocolRevision: protocol.ProtoRevisionVatsim2022,
SimulatorType: 2,
RealName: "Foo Bar",
},
&protocol.TextMessagePDU{
From: "N124",
To: "N123",
Message: "hello",
},
},
},
{
callsign: "N124",
cid: user2.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: protocol.NetworkRatingOBS,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "Foo Bar",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.KillRequestPDU{
From: "N124",
To: "N123",
Reason: "ur banned",
},
&protocol.TextMessagePDU{
From: "N124",
To: "N123",
Message: "hello",
},
},
wantPackets: []protocol.PDU{},
},
},
},
{
testName: "Delete pilot broadcast",
clients: []clientStruct{
{
callsign: "DEL",
cid: user1.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: 1,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "John Doe",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{},
wantPackets: []protocol.PDU{
&protocol.AddPilotPDU{
From: "N124",
To: protocol.ServerCallsign,
CID: user2.CID,
Token: "",
NetworkRating: protocol.NetworkRatingOBS,
ProtocolRevision: protocol.ProtoRevisionVatsim2022,
SimulatorType: 2,
RealName: "Foo Bar",
},
&protocol.DeletePilotPDU{
From: "N124",
CID: user2.CID,
},
},
},
{
callsign: "N124",
cid: user2.CID,
password: "12345",
clientID: 35044,
clientName: "vPilot",
majorVersion: 3,
minorVersion: 8,
sysUID: -99999,
initialChallenge: "abcdef",
networkRating: protocol.NetworkRatingOBS,
protocolRevsion: protocol.ProtoRevisionVatsim2022,
simulatorType: 2,
realName: "Foo Bar",
preliminaryTestPackets: []protocol.PDU{},
preliminaryWantPackets: []protocol.PDU{},
testPackets: []protocol.PDU{
&protocol.DeletePilotPDU{
From: "N124",
CID: user2.CID,
},
},
wantPackets: []protocol.PDU{},
},
},
},
}
// Run tests
for _, tc := range tests {
t.Run(tc.testName, func(t *testing.T) {
var doneWg sync.WaitGroup
// Spawn each browser
for _, client := range tc.clients {
c := client
doneWg.Add(1)
var loggedIn sync.WaitGroup
loggedIn.Add(1)
go func() {
defer doneWg.Done()
// Log in the browser.
// Test cases are meant to be executed after the browser has logged in.
// Load a JWT token first
var token string
var err error
token, err = getJWTToken(c.cid, c.password)
assert.Nil(t, err)
conn, err := net.Dial("tcp4", servercontext.Config().FSDListenAddress)
assert.Nil(t, err)
err = conn.SetReadDeadline(time.Now().Add(2 * time.Second))
assert.Nil(t, err)
defer func() {
closeErr := conn.Close()
assert.Nil(t, closeErr)
}()
reader := bufio.NewReader(conn)
serverIdent, err := reader.ReadString('\n')
assert.Nil(t, err)
assert.NotEmpty(t, serverIdent)
assert.True(t, strings.HasPrefix(serverIdent, "$DISERVER:CLIENT:"))
clientIdentPDU := protocol.ClientIdentificationPDU{
From: c.callsign,
To: protocol.ServerCallsign,
ClientID: c.clientID,
ClientName: c.clientName,
MajorVersion: c.majorVersion,
MinorVersion: c.minorVersion,
CID: c.cid,
SysUID: c.sysUID,
InitialChallenge: c.initialChallenge,
}
addPilotPDU := protocol.AddPilotPDU{
From: c.callsign,
To: protocol.ServerCallsign,
CID: c.cid,
Token: token,
NetworkRating: protocol.NetworkRating(c.networkRating),
ProtocolRevision: c.protocolRevsion,
SimulatorType: c.simulatorType,
RealName: c.realName,
}
_, err = conn.Write([]byte(clientIdentPDU.Serialize()))
assert.Nil(t, err)
_, err = conn.Write([]byte(addPilotPDU.Serialize()))
assert.Nil(t, err)
motdMsg, err := reader.ReadString('\n')
assert.Nil(t, err)
assert.NotEmpty(t, motdMsg)
motdReceivedPDU := protocol.TextMessagePDU{}
err = motdReceivedPDU.Parse(motdMsg)
assert.Nil(t, err)
expectedMOTD := protocol.TextMessagePDU{
From: protocol.ServerCallsign,
To: c.callsign,
Message: servercontext.Config().MOTD,
}
assert.Equal(t, expectedMOTD.Serialize(), motdReceivedPDU.Serialize())
// Send post-login packets before signalling that we're done logging in
for _, packet := range c.preliminaryTestPackets {
_, writeErr := conn.Write([]byte(packet.Serialize()))
assert.Nil(t, writeErr)
}
// Verify post-login returned packets are correct
for _, packet := range c.preliminaryWantPackets {
deadlineErr := conn.SetReadDeadline(time.Now().Add(30 * time.Second))
assert.Nil(t, deadlineErr)
recvPacket, recvErr := reader.ReadString('\n')
assert.Nil(t, recvErr)
assert.Equal(t, packet.Serialize(), recvPacket)
}
// Signal we're done logging in
loggedIn.Done()
// Send test packets
for _, packet := range c.testPackets {
_, writeErr := conn.Write([]byte(packet.Serialize()))
assert.Nil(t, writeErr)
}
// Verify returned packets are correct
for _, packet := range c.wantPackets {
deadlineErr := conn.SetReadDeadline(time.Now().Add(30 * time.Second))
assert.Nil(t, deadlineErr)
recvPacket, recvErr := reader.ReadString('\n')
assert.Nil(t, recvErr)
assert.Equal(t, packet.Serialize(), recvPacket)
}
}()
// Wait for the preceding client to finish logging in before spawning another
loggedIn.Wait()
}
// Wait for all goroutines to return
doneWg.Wait()
})
}
// Close context
cancelCtx()
// Wait for bootstrap done
<-b.Done
}
func getJWTToken(cid int, password string) (token string, err error) {
reqPayload := auth.FSDJWTRequest{
CID: strconv.Itoa(cid),
Password: password,
}
var reqPayloadBytes []byte
if reqPayloadBytes, err = json.Marshal(reqPayload); err != nil {
return
}
var addr *net.TCPAddr
if addr, err = net.ResolveTCPAddr("tcp4", servercontext.Config().HTTPListenAddress); err != nil {
return
}
var resp *http.Response
if resp, err = http.Post("http://localhost:"+strconv.Itoa(addr.Port)+"/api/v1/fsd-jwt", "application/json", bytes.NewReader(reqPayloadBytes)); err != nil {
return
}
if resp.StatusCode != 200 {
err = errors.New("HTTP status " + resp.Status)
return
}
var respBody []byte
if respBody, err = io.ReadAll(resp.Body); err != nil {
return
}
var respPayload auth.FSDJWTResponse
if err = json.Unmarshal(respBody, &respPayload); err != nil {
return
}
if !respPayload.Success {
err = errors.New("response payload unsuccessful " + respPayload.ErrorMsg)
return
}
return respPayload.Token, nil
}