Created
September 20, 2022 15:17
-
-
Save yanisurbis/d47e6559d7dcb8957c77cd30d27e94d2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"net" | |
"os" | |
"os/exec" | |
"strings" | |
"sync" | |
"time" | |
"bytes" | |
"math/rand" | |
) | |
const AddressWithPort = "localhost:10823" | |
const PathToExecutable = "./gfclient_download" | |
type TestCase struct { | |
id int | |
description string | |
filePath string | |
handler func(*sync.WaitGroup, net.Conn, *TestCase) | |
assert func(string, error, *TestCase) | |
} | |
func contains(x string, y string) { | |
if !strings.Contains(x, y) { | |
log.Fatalf("should contain %s\n", y) | |
} | |
} | |
func failIfNot(v bool, msg string) { | |
if !v { | |
log.Fatalf(msg) | |
} | |
} | |
func filePathSentByServer(path string) string { | |
return ".." + path | |
} | |
func filePathReceivedByClient(path string) string { | |
return "../received_by_client" + path | |
} | |
func compareSentAndReceivedFiles(path string) { | |
bytesSentFile, err := os.ReadFile(filePathSentByServer(path)) | |
if err != nil { | |
log.Fatal("failed to open a file, ", err) | |
} | |
bytesReceivedFile, err := os.ReadFile(filePathReceivedByClient(path)) | |
if err != nil { | |
log.Fatal("failed to open a file, ", err) | |
} | |
if bytes.Compare(bytesSentFile, bytesReceivedFile) != 0 { | |
log.Fatalf("Files %s should be equal", path) | |
} | |
} | |
func startSeverUsingHandler( | |
wg *sync.WaitGroup, | |
testCase *TestCase) { | |
listen, err := net.Listen("tcp", AddressWithPort) | |
if err != nil { | |
log.Fatal(err) | |
os.Exit(1) | |
} | |
go runProgram(wg, testCase) | |
fmt.Printf("testing: %s\n", testCase.description) | |
conn, err := listen.Accept() | |
if err != nil { | |
log.Fatal(err) | |
} | |
go testCase.handler(wg, conn, testCase) | |
listen.Close() | |
fmt.Printf("Ok\n\n") | |
} | |
func DEBUG_HANDLER( | |
wg *sync.WaitGroup, | |
testCase *TestCase) { | |
listen, err := net.Listen("tcp", AddressWithPort) | |
if err != nil { | |
log.Fatal(err) | |
os.Exit(1) | |
} | |
fmt.Printf("testing: %s\n", testCase.description) | |
for { | |
conn, err := listen.Accept() | |
if err != nil { | |
log.Fatal(err) | |
} | |
//go func(conn net.Conn) { | |
// <-time.After(time.Duration(3) * time.Second) | |
// fmt.Println("Closing connection...") | |
// defer conn.Close() | |
//}(conn) | |
go testCase.handler(wg, conn, testCase) | |
} | |
} | |
func runProgram(wg *sync.WaitGroup, tc *TestCase) { | |
var cmd *exec.Cmd | |
if tc.filePath != "" { | |
cmd = exec.Command(PathToExecutable, "-f", tc.filePath) | |
} else { | |
cmd = exec.Command(PathToExecutable) | |
} | |
cmd.Dir = ".." | |
stdout, err := cmd.Output() | |
if err != nil { | |
fmt.Println(err.Error()) | |
return | |
} | |
//fmt.Print(string(stdout)) | |
tc.assert(string(stdout), err, tc) | |
wg.Done() | |
} | |
func main() { | |
cases := []TestCase{ | |
{ | |
id: 0, | |
description: "basic case", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// respond | |
conn.Write([]byte("GETFILE OK 6\r\n\r\nabcdef")) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: OK") | |
contains(out, "Received 6 of 6 bytes") | |
failIfNot(err == nil, "StdErr should be empty") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "send wrong delimeter", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// respond | |
conn.Write([]byte("GETFILE ")) | |
conn.Write([]byte("OK 6\n\na")) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: INVALID") | |
contains(out, "Received 0 of 0 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "don't send full body before closing", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// respond | |
conn.Write([]byte("GETFILE ")) | |
conn.Write([]byte("OK 6\r\n\r\na")) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: OK") | |
contains(out, "Received 1 of 6 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "don't send full header", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// respond | |
conn.Write([]byte("GETFILE OK")) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: INVALID") | |
contains(out, "Received 0 of 0 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "send ERROR back", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// respond | |
conn.Write([]byte("GETFILE ERROR\r\n\r\n")) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: ERROR") | |
contains(out, "Received 0 of 0 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "send FILE_NOT_FOUND back", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// respond | |
conn.Write([]byte("GETFILE FILE_NOT_FOUND\r\n\r\n")) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: FILE_NOT_FOUND") | |
contains(out, "Received 0 of 0 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "broken header", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// respond | |
conn.Write([]byte("GETFILE xasdfasdf 123\r\n\r\n")) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: INVALID") | |
contains(out, "Received 0 of 0 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "small file in one chunk", | |
filePath: "/test_files/digits.txt", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fileAsByteArray, err := os.ReadFile(filePathSentByServer(tc.filePath)) | |
if err != nil { | |
log.Fatal("failed to open a file, ", err) | |
} | |
// respond | |
conn.Write([]byte(fmt.Sprintf("GETFILE OK %d\r\n\r\n", len(fileAsByteArray)))) | |
conn.Write(fileAsByteArray) | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: OK") | |
compareSentAndReceivedFiles(tc.filePath) | |
}, | |
}, | |
{ | |
id: 0, | |
description: "don't fully send header, don't close a socket", | |
filePath: "", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
conn.Write([]byte("GETFILE OK")) | |
<-time.After(time.Duration(1) * time.Second) | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: INVALID") | |
contains(out, "Received 0 of 0 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "don't fully send body, don't close a socket", | |
filePath: "/test_files/digits.txt", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fileAsByteArray, err := os.ReadFile(filePathSentByServer(tc.filePath)) | |
if err != nil { | |
log.Fatal("failed to open a file, ", err) | |
} | |
// respond | |
conn.Write([]byte(fmt.Sprintf("GETFILE OK %d\r\n\r\n", len(fileAsByteArray)))) | |
conn.Write(fileAsByteArray[:3]) | |
<-time.After(time.Duration(1) * time.Second) | |
// close conn | |
//conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: OK") | |
contains(out, "Received 3 of 10 bytes") | |
}, | |
}, | |
{ | |
id: 0, | |
description: "small file in one chunk, don't close a socket", | |
filePath: "/test_files/digits.txt", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fileAsByteArray, err := os.ReadFile(filePathSentByServer(tc.filePath)) | |
if err != nil { | |
log.Fatal("failed to open a file, ", err) | |
} | |
// respond | |
conn.Write([]byte(fmt.Sprintf("GETFILE OK %d\r\n\r\n", len(fileAsByteArray)))) | |
conn.Write(fileAsByteArray) | |
<-time.After(time.Duration(1) * time.Second) | |
// close conn | |
//conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: OK") | |
compareSentAndReceivedFiles(tc.filePath) | |
}, | |
}, | |
{ | |
id: 0, | |
description: "big file in mulitple chunks", | |
filePath: "/test_files/the_idiot.txt", | |
handler: func(wg *sync.WaitGroup, conn net.Conn, tc *TestCase) { | |
buffer := make([]byte, 1024) | |
_, err := conn.Read(buffer) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fileAsByteArray, err := os.ReadFile(filePathSentByServer(tc.filePath)) | |
if err != nil { | |
log.Fatal("failed to open a file, ", err) | |
} | |
// respond | |
conn.Write([]byte(fmt.Sprintf("GETFILE OK %d\r\n\r\n", len(fileAsByteArray)))) | |
length := len(fileAsByteArray) | |
for i := 0; i < length; i++ { | |
n := rand.Intn(64000) | |
if length - i < n { | |
n = length - i | |
} | |
conn.Write(fileAsByteArray[i: i + n + 1]) | |
i += n | |
} | |
// close conn | |
conn.Close() | |
wg.Done() | |
}, | |
assert: func(out string, err error, tc *TestCase) { | |
contains(out, "Status: OK") | |
compareSentAndReceivedFiles(tc.filePath) | |
}, | |
}, | |
} | |
var wg sync.WaitGroup | |
fmt.Println("start testing!\n") | |
for _, c := range cases { | |
wg.Add(2) | |
go startSeverUsingHandler(&wg, &c) | |
// Isolate a specific test before uncommenting the line below | |
//go DEBUG_HANDLER(&wg, &c) | |
wg.Wait() | |
} | |
fmt.Println("success!") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment