// TestGetFilesJSON verifies that /api/files returns proper JSON output func TestGetFilesJSON(t *testing.T) { log.Println("TestGetFilesJSON()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate mock data.FileRecord file := data.FileRecord{ InfoHash: "deadbeef", Verified: true, } // Save mock file if !file.Save() { t.Fatalf("Failed to save mock file") } // Load mock file to fetch ID file = file.Load(file.InfoHash, "info_hash") if file == (data.FileRecord{}) { t.Fatalf("Failed to load mock file") } // Request output JSON from API for this file var file2 data.FileRecord err := json.Unmarshal(getFilesJSON(file.ID), &file2) if err != nil { t.Fatalf("Failed to unmarshal result JSON for single file") } // Verify objects are the same if file.ID != file2.ID { t.Fatalf("ID, expected %d, got %d", file.ID, file2.ID) } // Request output JSON from API for all files var allFiles []data.FileRecord err = json.Unmarshal(getFilesJSON(-1), &allFiles) if err != nil { t.Fatalf("Failed to unmarshal result JSON for all files") } // Verify known file is in result set found := false for _, f := range allFiles { if f.ID == file.ID { found = true } } if !found { t.Fatalf("Expected file not found in all files result set") } // Delete mock file if !file.Delete() { t.Fatalf("Failed to delete mock file") } }
// TestWhitelistRecord verifies that WhitelistRecord creation, methods, save, load, and delete work properly func TestWhitelistRecord(t *testing.T) { log.Println("TestWhitelistRecord()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock WhitelistRecord whitelist := WhitelistRecord{ Client: "goat_test", Approved: true, } // Save mock whitelist if err := whitelist.Save(); err != nil { t.Fatalf("Failed to save mock whitelist: %s", err.Error()) } // Load mock whitelist to fetch ID whitelist, err = whitelist.Load(whitelist.Client, "client") if whitelist == (WhitelistRecord{}) || err != nil { t.Fatalf("Failed to load mock whitelist: %s", err.Error()) } // Delete mock whitelist if err := whitelist.Delete(); err != nil { t.Fatalf("Failed to delete mock whitelist: %s", err.Error()) } }
// TestUDPAnnounce verifies that the UDP tracker announce output format is correct func TestUDPAnnounce(t *testing.T) { log.Println("TestUDPAnnounce()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate mock data.FileRecord file := data.FileRecord{ InfoHash: "6465616462656566", Verified: true, } // Save mock file if !file.Save() { t.Fatalf("Failed to save mock file") } // Generate fake announce query query := url.Values{} query.Set("info_hash", "deadbeef") query.Set("ip", "127.0.0.1") query.Set("port", "5000") query.Set("uploaded", "0") query.Set("downloaded", "0") query.Set("left", "0") query.Set("numwant", "50") // Create a UDP tracker, trigger an announce tracker := UDPTracker{TransID: uint32(1234)} res := tracker.Announce(query, file) // Decode response announce := new(udp.AnnounceResponse) err := announce.UnmarshalBinary(res) if err != nil { t.Fatalf("Failed to decode UDP announce response") } log.Println(announce) // Verify correct action if announce.Action != 1 { t.Fatalf("Incorrect UDP action, expected 1") } // Encode response, verify same as before announceBuf, err := announce.MarshalBinary() if err != nil { t.Fatalf("Failed to encode UDP announce response") } if !bytes.Equal(res, announceBuf) { t.Fatalf("Byte slices are not identical") } // Delete mock file if !file.Delete() { t.Fatalf("Failed to delete mock file") } }
// TestAPIKey verifies that APIKey creation, save, load, and delete work properly func TestAPIKey(t *testing.T) { log.Println("TestAPIKey()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate mock APIKey key := APIKey{ UserID: 1, Key: "deadbeef", Salt: "test", } // Verify key can be saved if !key.Save() { t.Fatalf("Failed to save keyLog") } // Verify key can be loaded using matching key key2 := key.Load(key.Key, "key") if key2 == (APIKey{}) { t.Fatal("Failed to load APIKey") } // Verify key is the same as previous one if key.Salt != key2.Salt { t.Fatalf("key.Salt, expected %s, got %s", key.Salt, key2.Salt) } // Verify key can be deleted if !key2.Delete() { t.Fatalf("Failed to delete APIKey") } }
// TestHTTPRouter verifies that the main HTTP router is working properly func TestHTTPRouter(t *testing.T) { log.Println("TestHTTPRouter()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock data.FileRecord file := data.FileRecord{ InfoHash: "6465616462656566303030303030303030303030", Verified: true, } // Save mock file if err := file.Save(); err != nil { t.Fatalf("Failed to save mock file: %s", err.Error()) } // Generate mock data.FileRecord file2 := data.FileRecord{ InfoHash: "6265656664656164", Verified: true, } // Save mock file if err := file2.Save(); err != nil { t.Fatalf("Failed to save mock file: %s", err.Error()) } // Iterate all HTTP tests for _, test := range httpTests { // Generate mock HTTP request r, err := http.NewRequest("GET", "http://localhost:8080"+test.url, nil) r.Header.Set("User-Agent", "goat_test") if err != nil { t.Fatalf("Failed to create HTTP request") } // Capture HTTP writer response with recorder w := httptest.NewRecorder() // Invoke HTTP router parseHTTP(w, r) log.Println("TEST:", test.url) log.Println(w.Body.String()) } // Delete mock file2 err = file.Delete() err2 := file2.Delete() if err != nil || err2 != nil { t.Fatalf("Failed to delete mock file : %s %s", err.Error(), err2.Error()) } }
// TestScrapeLog verifies that scrape log creation, save, load, and delete work properly func TestScrapeLog(t *testing.T) { log.Println("TestScrapeLog()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate fake scrape query query := url.Values{} query.Set("info_hash", "deadbeef000000000000") query.Set("ip", "127.0.0.1") // Generate struct from query scrape := new(ScrapeLog) err = scrape.FromValues(query) if err != nil { t.Fatalf("Failed to create scrape from values: %s", err.Error()) } // Verify proper hex encode of info hash if scrape.InfoHash != "6465616462656566303030303030303030303030" { t.Fatalf("InfoHash, expected \"6465616462656566303030303030303030303030\", got %s", scrape.InfoHash) } // Verify same IP if scrape.IP != "127.0.0.1" { t.Fatalf("IP, expected \"127.0.0.1\", got %s", scrape.IP) } // Verify scrape can be saved if err := scrape.Save(); err != nil { t.Fatalf("Failed to save ScrapeLog: %s", err.Error()) } // Verify scrape can be loaded using hex info hash scrape2, err := scrape.Load("6465616462656566303030303030303030303030", "info_hash") if scrape2 == (ScrapeLog{}) || err != nil { t.Fatal("Failed to load ScrapeLog: %s", err.Error()) } // Verify scrape is the same as previous one if scrape.InfoHash != scrape2.InfoHash { t.Fatalf("scrape.InfoHash, expected %s, got %s", scrape.InfoHash, scrape2.InfoHash) } // Verify scrape can be deleted if err := scrape2.Delete(); err != nil { t.Fatalf("Failed to delete ScrapeLog: %s", err.Error()) } }
// TestPostLogin verifies that /api/login returns proper JSON output func TestPostLogin(t *testing.T) { log.Println("TestPostLogin()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock data.UserRecord mockUser := new(data.UserRecord) if err := mockUser.Create("test", "test", 100); err != nil { t.Fatalf("Failed to create mock user: %s", err.Error()) } // Save mock user if err := mockUser.Save(); err != nil { t.Fatalf("Failed to save mock user: %s", err.Error()) } // Load mock user to fetch ID user, err := mockUser.Load(mockUser.Username, "username") if user == (data.UserRecord{}) || err != nil { t.Fatalf("Failed to load mock user: %s", err.Error()) } // Perform login request for this user res, err := postLogin(user) if err != nil { t.Fatalf("Failed to retrieve login JSON: %s", err.Error()) } log.Println(string(res)) // Unmarshal output JSON var key data.JSONAPIKey err = json.Unmarshal(res, &key) if err != nil { t.Fatalf("Failed to unmarshal login JSON: %s", err.Error()) } // Verify same user ID from API if user.ID != key.UserID { t.Fatalf("Mismatched user IDs, got %d, expected %d", key.UserID, user.ID) } // Delete mock user if err := user.Delete(); err != nil { t.Fatalf("Failed to delete mock user: %s", err.Error()) } }
// TestFileRecord verifies that FileRecord creation, methods, save, load, and delete work properly func TestFileRecord(t *testing.T) { log.Println("TestFileRecord()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock FileRecord file := FileRecord{ InfoHash: "deadbeef", Verified: true, } // Save mock file if err := file.Save(); err != nil { t.Fatalf("Failed to save mock file: %s", err.Error()) } // Load mock file to fetch ID file, err = file.Load(file.InfoHash, "info_hash") if file == (FileRecord{}) || err != nil { t.Fatalf("Failed to load mock file: %s", err.Error()) } // Verify completed is functional if _, err := file.Completed(); err != nil { t.Fatalf("Failed to fetch file completed") } // Verify seeders is functional if _, err := file.Seeders(); err != nil { t.Fatalf("Failed to fetch file seeders") } // Verify leechers is functional if _, err := file.Leechers(); err != nil { t.Fatalf("Failed to fetch file leechers") } // Delete mock file if err := file.Delete(); err != nil { t.Fatalf("Failed to delete mock file: %s", err.Error()) } }
// TestHTTPAnnounce verifies that the HTTP tracker announce output format is correct func TestHTTPAnnounce(t *testing.T) { log.Println("TestHTTPAnnounce()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock data.FileRecord file := data.FileRecord{ InfoHash: "6465616462656566303030303030303030303030", Verified: true, } // Save mock file if err := file.Save(); err != nil { t.Fatalf("Failed to save mock file: %s", err.Error()) } // Generate fake announce query query := url.Values{} query.Set("info_hash", "deadbeef") query.Set("ip", "127.0.0.1") query.Set("port", "5000") query.Set("uploaded", "0") query.Set("downloaded", "0") query.Set("left", "0") // Create a HTTP tracker, trigger an announce tracker := HTTPTracker{} res := tracker.Announce(query, file) log.Println(string(res)) // Unmarshal response announce := AnnounceResponse{} if err := bencode.Unmarshal(bytes.NewReader(res), &announce); err != nil { t.Fatalf("Failed to unmarshal bencode announce response") } // Delete mock file if err := file.Delete(); err != nil { t.Fatalf("Failed to delete mock file: %s", err.Error()) } }
// TestScrapeLog verifies that scrape log creation, save, load, and delete work properly func TestScrapeLog(t *testing.T) { log.Println("TestScrapeLog()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate fake scrape query query := url.Values{} query.Set("info_hash", "deadbeef") query.Set("ip", "127.0.0.1") // Generate struct from query scrape := new(ScrapeLog).FromValues(query) // Verify proper hex encode of info hash if scrape.InfoHash != "6465616462656566" { t.Fatalf("InfoHash, expected \"6465616462656566\", got %s", scrape.InfoHash) } // Verify same IP if scrape.IP != "127.0.0.1" { t.Fatalf("IP, expected \"127.0.0.1\", got %s", scrape.IP) } // Verify scrape can be saved if !scrape.Save() { t.Fatalf("Failed to save ScrapeLog") } // Verify scrape can be loaded using hex info hash scrape2 := scrape.Load("6465616462656566", "info_hash") if scrape2 == (ScrapeLog{}) { t.Fatal("Failed to load ScrapeLog") } // Verify scrape is the same as previous one if scrape.InfoHash != scrape2.InfoHash { t.Fatalf("scrape.InfoHash, expected %s, got %s", scrape.InfoHash, scrape2.InfoHash) } // Verify scrape can be deleted if !scrape2.Delete() { t.Fatalf("Failed to delete ScrapeLog") } }
// TestFileRecord verifies that FileRecord creation, methods, save, load, and delete work properly func TestFileRecord(t *testing.T) { log.Println("TestFileRecord()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate mock FileRecord file := FileRecord{ InfoHash: "deadbeef", Verified: true, } // Save mock file if !file.Save() { t.Fatalf("Failed to save mock file") } // Load mock file to fetch ID file = file.Load(file.InfoHash, "info_hash") if file == (FileRecord{}) { t.Fatalf("Failed to load mock file") } // Verify positive number of completed on file if file.Completed() < 0 { t.Fatalf("Failed to fetch file completed") } // Verify positive number of seeders on file if file.Seeders() < 0 { t.Fatalf("Failed to fetch file seeders") } // Verify positive number of leechers on file if file.Leechers() < 0 { t.Fatalf("Failed to fetch file leechers") } // Delete mock file if !file.Delete() { t.Fatalf("Failed to delete mock file") } }
// TestUserRecord verifies that user creation, save, load, and delete work properly func TestUserRecord(t *testing.T) { log.Println("TestUserRecord()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Create a user user := new(UserRecord) if err := user.Create("test", "test", 100); err != nil { t.Fatalf("Failed to create UserRecord") } // Verify proper passkey length if len(user.Passkey) != 40 { t.Fatalf("user.Passkey is %d characters, expected 40", len(user.Passkey)) } // Verify user can be saved if err := user.Save(); err != nil { t.Fatalf("Failed to save UserRecord: %s", err.Error()) } // Verify user can be loaded using username user2, err := user.Load("test", "username") if user2 == (UserRecord{}) || err != nil { t.Fatal("Failed to load UserRecord: %s", err.Error()) } // Verify user is the same as previous one if user.Passkey != user2.Passkey { t.Fatalf("user.Passkey, expected %s, got %s", user.Passkey, user2.Passkey) } // Verify user can be deleted if err := user2.Delete(); err != nil { t.Fatalf("Failed to delete UserRecord: %s", err.Error()) } }
// TestFileUserRecord verifies that FileUserRecord creation, methods, save, load, and delete work properly func TestFileUserRecord(t *testing.T) { log.Println("TestFileUserRecord()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock FileUserRecord fileUser := FileUserRecord{ FileID: 1, UserID: 1, IP: "127.0.0.1", Active: true, Completed: true, Announced: 10, Uploaded: 5000, Downloaded: 5000, Left: 0, Time: time.Now().Unix(), } // Save mock fileUser if err := fileUser.Save(); err != nil { t.Fatalf("Failed to save mock fileUser: %s", err.Error()) } // Load mock fileUser fileUser, err = fileUser.Load(fileUser.FileID, fileUser.UserID, fileUser.IP) if fileUser == (FileUserRecord{}) || err != nil { t.Fatalf("Failed to load mock fileUser: %s", err.Error()) } // Delete mock fileUser if err := fileUser.Delete(); err != nil { t.Fatalf("Failed to delete mock fileUser: %s", err.Error()) } }
// TestAPIKey verifies that APIKey creation, save, load, and delete work properly func TestAPIKey(t *testing.T) { log.Println("TestAPIKey()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock APIKey key := new(APIKey) if err := key.Create(1); err != nil { t.Fatalf("Failed to create mock APIKey: %s", err.Error()) } // Verify key can be saved if err := key.Save(); err != nil { t.Fatalf("Failed to save APIKey: %s", err.Error()) } // Verify key can be loaded using matching pubkey key2, err := key.Load(key.Pubkey, "pubkey") if err != nil || key2 == (APIKey{}) { t.Fatal("Failed to load APIKey: %s", err.Error()) } // Verify key is the same as previous one if key.Pubkey != key2.Pubkey { t.Fatalf("key.Pubkey, expected %s, got %s", key.Pubkey, key2.Pubkey) } // Verify key can be deleted if err := key2.Delete(); err != nil { t.Fatalf("Failed to delete APIKey: %s", err.Error()) } }
// TestUDPRouter verifies that the main UDP router is working properly func TestUDPRouter(t *testing.T) { log.Println("TestUDPRouter()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock data.FileRecord file := data.FileRecord{ InfoHash: "6465616462656566303030303030303030303030", Verified: true, } // Save mock file if err := file.Save(); err != nil { t.Fatalf("Failed to save mock file: %s", err.Error()) } // Fake UDP address addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") if err != nil { t.Fatalf("Failed to create fake UDP address") } // Connect packet with handshake connect := udp.Packet{udpInitID, 0, 1234} connectBuf, err := connect.MarshalBinary() if err != nil { t.Fatalf("Failed to create UDP connect packet") } // Perform connection handshake res, err := parseUDP(connectBuf, addr) if err != nil { errRes := new(udp.ErrorResponse) err2 := errRes.UnmarshalBinary(res) if err2 != nil { t.Fatalf(err.Error()) } log.Println("ERROR:", errRes.Error) t.Fatalf(err.Error()) } // Retrieve response, get new connection ID, which will be expected by router connRes := new(udp.ConnectResponse) err = connRes.UnmarshalBinary(res) if err != nil { t.Fatalf(err.Error()) } // Create announce request announce := udp.AnnounceRequest{ ConnID: connRes.ConnID, Action: 1, TransID: connRes.TransID, InfoHash: []byte("deadbeef000000000000"), PeerID: []byte("00001111222233334444"), Downloaded: 0, Left: 0, Uploaded: 0, IP: 0, Key: 1234, Port: 5000, } // Get announce bytes announceBuf, err := announce.MarshalBinary() if err != nil { t.Fatalf(err.Error()) } // Send announce to UDP router res, err = parseUDP(announceBuf, addr) if err != nil { errRes := new(udp.ErrorResponse) err2 := errRes.UnmarshalBinary(res) if err2 != nil { t.Fatalf(err.Error()) } log.Println("ERROR:", errRes.Error) t.Fatalf(err.Error()) } // Get UDP announce response announceRes := new(udp.AnnounceResponse) err = announceRes.UnmarshalBinary(res) if err != nil { errRes := new(udp.ErrorResponse) err2 := errRes.UnmarshalBinary(res) if err2 != nil { t.Fatalf(err.Error()) } log.Println("ERROR:", errRes.Error) t.Fatalf(err.Error()) } log.Println(announceRes) // Create scrape request scrape := udp.ScrapeRequest{ ConnID: connRes.ConnID, Action: 2, TransID: connRes.TransID, InfoHashes: [][]byte{[]byte("deadbeef000000000000")}, } // Get scrape bytes scrapeBuf, err := scrape.MarshalBinary() if err != nil { t.Fatalf(err.Error()) } // Send scrape to UDP router res, err = parseUDP(scrapeBuf, addr) if err != nil { errRes := new(udp.ErrorResponse) err2 := errRes.UnmarshalBinary(res) if err2 != nil { t.Fatalf(err.Error()) } log.Println("ERROR:", errRes.Error) t.Fatalf(err.Error()) } // Get UDP scrape response scrapeRes := new(udp.ScrapeResponse) err = scrapeRes.UnmarshalBinary(res) if err != nil { errRes := new(udp.ErrorResponse) err2 := errRes.UnmarshalBinary(res) if err2 != nil { t.Fatalf(err.Error()) } log.Println("ERROR:", errRes.Error) t.Fatalf(err.Error()) } log.Println(scrapeRes) // Delete mock file if err := file.Delete(); err != nil { t.Fatalf("Failed to delete mock file: %s", err.Error()) } }
// TestAuthenticator verifies that the Basic and HMAC authenticators work properly func TestAuthenticator(t *testing.T) { log.Println("TestBasicAuthenticator()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock user user := new(data.UserRecord) if err := user.Create("test", "test", 10); err != nil { t.Fatalf("Failed to create mock user: %s", err.Error()) } // Save mock user if err := user.Save(); err != nil { t.Fatalf("Failed to save mock user: %s", err.Error()) } // Load user to get ID user2, err := user.Load("test", "username") if err != nil || (user2 == data.UserRecord{}) { t.Fatalf("Failed to load mock user: %s", err.Error()) } // Generate mock HTTP request r, err := http.NewRequest("POST", "http://localhost:8080/api/login", nil) if err != nil { t.Fatalf("Failed to generate HTTP request: %s", err.Error()) } headers := map[string][]string{ "Authorization": {"Basic " + base64.URLEncoding.EncodeToString([]byte("test:test"))}, } r.Header = headers // Capture HTTP response with recorder w := httptest.NewRecorder() // Perform HTTP Basic authentication var apiAuth APIAuthenticator apiAuth = new(BasicAuthenticator) // Attempt Basic authentication clientErr, serverErr := apiAuth.Auth(r) if clientErr != nil { t.Fatalf("Failed to authenticate: client: %s", clientErr.Error()) } if serverErr != nil { t.Fatalf("Failed to authenticate: server: %s", serverErr.Error()) } // Invoke API router Router(w, r, user2) // Read HTTP response body body, err := ioutil.ReadAll(w.Body) if err != nil { t.Fatalf("Failed to read HTTP response body: %s", err.Error()) } // Unmarshal result JSON var login data.JSONAPIKey if err := json.Unmarshal(body, &login); err != nil { t.Fatalf("Failed to unmarshal login JSON: %s", err.Error()) } // Generate API signature nonce := "abcdef" method := "GET" resource := "/api/status" signature, err := apiSignature(login.UserID, nonce, method, resource, login.Secret) if err != nil { t.Fatalf("Failed to generate API signature: %s", err.Error()) } log.Println("signature:", signature) // Generate mock HTTP request r, err = http.NewRequest(method, "http://localhost:8080"+resource, nil) if err != nil { t.Fatalf("Failed to generate HTTP request: %s", err.Error()) } headers = map[string][]string{ "Authorization": {"Basic " + base64.URLEncoding.EncodeToString([]byte(login.Pubkey+":"+nonce+"/"+signature))}, } r.Header = headers // Capture HTTP response with recorder w = httptest.NewRecorder() // Attempt HMAC authentication apiAuth = new(HMACAuthenticator) clientErr, serverErr = apiAuth.Auth(r) if clientErr != nil { t.Fatalf("Failed to authenticate: client: %s", clientErr.Error()) } if serverErr != nil { t.Fatalf("Failed to authenticate: server: %s", serverErr.Error()) } // Invoke API router Router(w, r, user2) // Read HTTP response body body, err = ioutil.ReadAll(w.Body) if err != nil { t.Fatalf("Failed to read HTTP response body: %s", err.Error()) } log.Println(string(body)) // Delete mock user if err := user2.Delete(); err != nil { t.Fatalf("Failed to delete mock user: %s", err.Error()) } }
// TestAnnounceLog verifies that announce log creation, save, load, and delete work properly func TestAnnounceLog(t *testing.T) { log.Println("TestAnnounceLog()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate fake announce query query := url.Values{} query.Set("info_hash", "deadbeef") query.Set("ip", "127.0.0.1") query.Set("port", "5000") query.Set("uploaded", "0") query.Set("downloaded", "0") query.Set("left", "0") // Generate struct from query announce := new(AnnounceLog).FromValues(query) // Verify proper hex encode of info hash if announce.InfoHash != "6465616462656566" { t.Fatalf("InfoHash, expected \"6465616462656566\", got %s", announce.InfoHash) } // Verify same IP if announce.IP != "127.0.0.1" { t.Fatalf("IP, expected \"127.0.0.1\", got %s", announce.IP) } // Verify proper port integer conversion if announce.Port != 5000 { t.Fatalf("Port, expected 5000, got %d", announce.Port) } // Verify proper uploaded integer conversion if announce.Uploaded != 0 { t.Fatalf("Uploaded, expected 0, got %d", announce.Uploaded) } // Verify proper downloaded integer conversion if announce.Downloaded != 0 { t.Fatalf("Downloaded, expected 0, got %d", announce.Downloaded) } // Verify proper left integer conversion if announce.Left != 0 { t.Fatalf("Left, expected 0, got %d", announce.Left) } // Verify announce can be saved if !announce.Save() { t.Fatalf("Failed to save AnnounceLog") } // Verify announce can be loaded using hex info hash announce2 := announce.Load("6465616462656566", "info_hash") if announce2 == (AnnounceLog{}) { t.Fatal("Failed to load AnnounceLog") } // Verify announce is the same as previous one if announce.InfoHash != announce2.InfoHash { t.Fatalf("announce.InfoHash, expected %s, got %s", announce.InfoHash, announce2.InfoHash) } // Verify announce can be deleted if !announce2.Delete() { t.Fatalf("Failed to delete AnnounceLog") } }
// Manager is responsible for coordinating the application func Manager(killChan chan bool, exitChan chan int) { // Capture startup time common.Static.StartTime = time.Now().Unix() // Set up logging flags log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.Println("Starting " + App + " " + Version) // Grab initial server status stat := common.GetServerStatus() if stat == (common.ServerStatus{}) { log.Println("Could not print get startup status") } else { log.Printf("%s - %s_%s (%d CPU) [pid: %d]", stat.Hostname, stat.Platform, stat.Architecture, stat.NumCPU, stat.PID) } // Load configuration config := common.LoadConfig() if config == (common.Conf{}) { panic("Cannot load configuration, panicking") } common.Static.Config = config // Check for sane announce interval (10 minutes or more) if common.Static.Config.Interval <= 600 { panic("Announce interval must be at least 600 seconds, panicking") } // Attempt database connection if !data.DBPing() { panic(fmt.Errorf("cannot connect to database %s; panicking", data.DBName())) } log.Println("Database", data.DBName(), ": OK") // If configured, attempt redis connection if common.Static.Config.Redis.Enabled { if !data.RedisPing() { panic("Cannot connect to Redis, panicking") } log.Println("Redis : OK") } // Start cron manager go cronManager() // Set up graceful shutdown channels httpSendChan := make(chan bool) httpRecvChan := make(chan bool) httpsSendChan := make(chan bool) httpsRecvChan := make(chan bool) udpSendChan := make(chan bool) udpRecvChan := make(chan bool) // Set up HTTP(S) route http.HandleFunc("/", parseHTTP) // Launch listeners as configured if common.Static.Config.HTTP { go listenHTTP(httpSendChan, httpRecvChan) log.Println("HTTP listener launched on port " + strconv.Itoa(common.Static.Config.Port)) } if common.Static.Config.SSL.Enabled { go listenHTTPS(httpsSendChan, httpsRecvChan) log.Println("HTTPS listener launched on port " + strconv.Itoa(common.Static.Config.SSL.Port)) } if common.Static.Config.UDP { go listenUDP(udpSendChan, udpRecvChan) log.Println("UDP listener launched on port " + strconv.Itoa(common.Static.Config.Port)) } // Wait for shutdown signal for { select { case <-killChan: // Trigger a graceful shutdown log.Println("Triggering graceful shutdown, press Ctrl+C again to force halt") // If program hangs for more than 10 seconds, trigger a force halt go func() { <-time.After(10 * time.Second) log.Println("Timeout reached, triggering force halt") if err := syscall.Kill(os.Getpid(), syscall.SIGTERM); err != nil { log.Println(err.Error()) } }() // Stop listeners if common.Static.Config.HTTP { log.Println("Stopping HTTP listener") httpSendChan <- true <-httpRecvChan } if common.Static.Config.SSL.Enabled { log.Println("Stopping HTTPS listener") httpsSendChan <- true <-httpsRecvChan } if common.Static.Config.UDP { log.Println("Stopping UDP listener") udpSendChan <- true <-udpRecvChan } log.Println("Closing database connection") data.DBCloseFunc() // Report that program should exit gracefully exitChan <- 0 } } }
// TestBasicAuthenticator verifies that BasicAuthenticator.Auth works properly func TestBasicAuthenticator(t *testing.T) { log.Println("TestBasicAuthenticator()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate mock user user := data.UserRecord{ Username: "******", Passkey: "abcdef0123456789", TorrentLimit: 10, } // Save mock user if !user.Save() { t.Fatalf("Failed to save mock user") } // Load mock user to fetch ID user = user.Load(user.Username, "username") if user == (data.UserRecord{}) { t.Fatalf("Failed to load mock user") } // Generate an API key and salt pass := "******" salt := "test" sha := sha1.New() sha.Write([]byte(pass + salt)) hash := fmt.Sprintf("%x", sha.Sum(nil)) // Generate mock API key key := data.APIKey{ UserID: user.ID, Key: hash, Salt: salt, } // Save mock API key if !key.Save() { t.Fatalf("Failed to save mock data.APIKey") } // Load mock data.APIKey to fetch ID key = key.Load(key.Key, "key") if key == (data.APIKey{}) { t.Fatalf("Failed to load mock data.APIKey") } // Generate mock HTTP request r := http.Request{} headers := map[string][]string{ "Authorization": {"Basic " + base64.URLEncoding.EncodeToString([]byte(user.Username+":"+pass))}, } r.Header = headers // Perform authentication request auth := new(BasicAuthenticator).Auth(&r) if !auth { t.Fatalf("Failed to authenticate using BasicAuthenticator") } // Delete mock user if !user.Delete() { t.Fatalf("Failed to delete mock user") } // Delete mock API key if !key.Delete() { t.Fatalf("Failed to delete mock data.APIKey") } }
// TestAnnounceLog verifies that announce log creation, save, load, and delete work properly func TestAnnounceLog(t *testing.T) { log.Println("TestAnnounceLog()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate fake announce query query := url.Values{} query.Set("info_hash", "deadbeef000000000000") query.Set("ip", "127.0.0.1") query.Set("port", "5000") query.Set("uploaded", "0") query.Set("downloaded", "0") query.Set("left", "0") // Generate struct from query announce := new(AnnounceLog) err = announce.FromValues(query) if err != nil { t.Fatalf(err.Error()) } // Verify proper hex encode of info hash if announce.InfoHash != "6465616462656566303030303030303030303030" { t.Fatalf("InfoHash, expected \"6465616462656566303030303030303030303030\", got %s", announce.InfoHash) } // Verify same IP if announce.IP != "127.0.0.1" { t.Fatalf("IP, expected \"127.0.0.1\", got %s", announce.IP) } // Verify proper port integer conversion if announce.Port != 5000 { t.Fatalf("Port, expected 5000, got %d", announce.Port) } // Verify proper uploaded integer conversion if announce.Uploaded != 0 { t.Fatalf("Uploaded, expected 0, got %d", announce.Uploaded) } // Verify proper downloaded integer conversion if announce.Downloaded != 0 { t.Fatalf("Downloaded, expected 0, got %d", announce.Downloaded) } // Verify proper left integer conversion if announce.Left != 0 { t.Fatalf("Left, expected 0, got %d", announce.Left) } // Verify announce can be saved if err := announce.Save(); err != nil { t.Fatalf("Failed to save AnnounceLog: %s", err.Error()) } // Verify announce can be loaded using hex info hash announce2, err := new(AnnounceLog).Load("6465616462656566303030303030303030303030", "info_hash") if err != nil || announce2 == (AnnounceLog{}) { t.Fatal("Failed to load AnnounceLog: %s", err.Error()) } // Verify announce can be deleted if err := announce2.Delete(); err != nil { t.Fatalf("Failed to delete AnnounceLog: %s", err.Error()) } }
// TestGetUsersJSON verifies that /api/users returns proper JSON output func TestGetUsersJSON(t *testing.T) { log.Println("TestGetUsersJSON()") // Load config config, err := common.LoadConfig() if err != nil { t.Fatalf("Could not load configuration: %s", err.Error()) } common.Static.Config = config // Generate mock data.UserRecord mockUser := new(data.UserRecord) if err := mockUser.Create("test", "test", 100); err != nil { t.Fatalf("Failed to create mock user: %s", err.Error()) } // Save mock user if err := mockUser.Save(); err != nil { t.Fatalf("Failed to save mock user: %s", err.Error()) } // Load mock user to fetch ID user, err := mockUser.Load(mockUser.Username, "username") if user == (data.UserRecord{}) || err != nil { t.Fatalf("Failed to load mock user: %s", err.Error()) } // Request output JSON from API for this user res, err := getUsersJSON(user.ID) if err != nil { t.Fatalf("Failed to retrieve users JSON: %s", err.Error()) } // Unmarshal output JSON var user2 data.UserRecord err = json.Unmarshal(res, &user2) if err != nil { t.Fatalf("Failed to unmarshal result JSON for single user: %s", err.Error()) } // Verify objects are the same if user.ID != user2.ID { t.Fatalf("ID, expected %d, got %d", user.ID, user2.ID) } // Request output JSON from API for all users res, err = getUsersJSON(-1) if err != nil { t.Fatalf("Failed to retrieve all users JSON: %s", err.Error()) } // Unmarshal all output JSON var allUsers []data.JSONUserRecord err = json.Unmarshal(res, &allUsers) if err != nil { t.Fatalf("Failed to unmarshal result JSON for all users: %s", err.Error()) } // Verify known user is in result set found := false for _, f := range allUsers { if f.ID == user.ID { found = true } } if !found { t.Fatalf("Expected user not found in all users result set") } // Delete mock user if err := user.Delete(); err != nil { t.Fatalf("Failed to delete mock user: %s", err.Error()) } }