mirror of
https://github.com/dragonheim/gagent.git
synced 2025-04-25 11:08:59 -07:00
feat: Adding very preliminar and broken test harness.
This commit is contained in:
parent
ac8c225752
commit
7f9a5777bd
14 changed files with 678 additions and 10 deletions
|
@ -1,13 +1,16 @@
|
||||||
{
|
{
|
||||||
"genesis_time": "2021-10-25:00:00.000000000Z",
|
"timestamp": "2021-10-25:00:00.000000000Z",
|
||||||
"chainid": "gagent_ledger",
|
"chainid": "gagent_ledger",
|
||||||
"agent": {
|
"agent": {
|
||||||
|
"status": "complete",
|
||||||
"client": "7e9d13fe-5151-5876-66c0-20ca03e8fca4",
|
"client": "7e9d13fe-5151-5876-66c0-20ca03e8fca4",
|
||||||
"shasum": "a76f7c3c7bc0f94b4f8aa63c605f8534db5675bb05d761f4461127fcadbf32d4",
|
"shasum": "a76f7c3c7bc0f94b4f8aa63c605f8534db5675bb05d761f4461127fcadbf32d4",
|
||||||
"status": "complete"
|
"hints": {},
|
||||||
|
"script": "",
|
||||||
|
"answer": ""
|
||||||
},
|
},
|
||||||
"clients": {
|
"clients": {
|
||||||
"client": "7e9d13fe-5151-5876-66c0-20ca03e8fca4"
|
"clientID": "7e9d13fe-5151-5876-66c0-20ca03e8fca4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -300,7 +300,8 @@ func init() {
|
||||||
if config.MonitorPort != 0 {
|
if config.MonitorPort != 0 {
|
||||||
go func() {
|
go func() {
|
||||||
log.Printf("[INFO] Starting Prometheus metrics exporter on port %d\n", config.MonitorPort)
|
log.Printf("[INFO] Starting Prometheus metrics exporter on port %d\n", config.MonitorPort)
|
||||||
log.Fatal(http.ListenAndServe(string(config.ListenAddr)+":"+strconv.Itoa(config.MonitorPort), nil))
|
err := http.ListenAndServe(string(config.ListenAddr)+":"+strconv.Itoa(config.MonitorPort), nil)
|
||||||
|
log.Printf("[ERROR] Prometheus metrics exporter returned: %s\n", err)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
autorestart.WatchFilename = config.File
|
autorestart.WatchFilename = config.File
|
||||||
|
|
71
cmd/gagent/main_test.go
Normal file
71
cmd/gagent/main_test.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package main_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
main "github.com/dragonheim/gagent/cmd/gagent"
|
||||||
|
gstructs "github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This function will create a temporary config file for testing purposes
|
||||||
|
func createTestConfigFile() (string, error) {
|
||||||
|
tmpfile, err := ioutil.TempFile("", "test_config_*.hcl")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
content := []byte(`mode = "setup"
|
||||||
|
listen_addr = "0.0.0.0"
|
||||||
|
monitor_port = 8888
|
||||||
|
client_port = 35572
|
||||||
|
router_port = 35570
|
||||||
|
worker_port = 35571
|
||||||
|
`)
|
||||||
|
if _, err := tmpfile.Write(content); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := tmpfile.Close(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpfile.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(t *testing.T) {
|
||||||
|
t.Run("Test setup mode with temp config file", func(t *testing.T) {
|
||||||
|
tmpConfig, err := createTestConfigFile()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create temp config file: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tmpConfig)
|
||||||
|
|
||||||
|
config := gstructs.GagentConfig{
|
||||||
|
File: tmpConfig,
|
||||||
|
Mode: "setup",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the main function with the temporary config
|
||||||
|
main.Run(config)
|
||||||
|
|
||||||
|
// Check if the config has been set up correctly
|
||||||
|
expectedConfig := gstructs.GagentConfig{
|
||||||
|
Mode: "setup",
|
||||||
|
ListenAddr: "0.0.0.0",
|
||||||
|
MonitorPort: 8888,
|
||||||
|
ClientPort: 35572,
|
||||||
|
RouterPort: 35570,
|
||||||
|
WorkerPort: 35571,
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Mode != expectedConfig.Mode ||
|
||||||
|
config.ListenAddr != expectedConfig.ListenAddr ||
|
||||||
|
config.MonitorPort != expectedConfig.MonitorPort ||
|
||||||
|
config.ClientPort != expectedConfig.ClientPort ||
|
||||||
|
config.RouterPort != expectedConfig.RouterPort ||
|
||||||
|
config.WorkerPort != expectedConfig.WorkerPort {
|
||||||
|
t.Fatalf("Expected config %+v, got %+v", expectedConfig, config)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
3
go.mod
3
go.mod
|
@ -12,6 +12,7 @@ require (
|
||||||
github.com/pebbe/zmq4 v1.2.9
|
github.com/pebbe/zmq4 v1.2.9
|
||||||
github.com/prometheus/client_golang v1.14.0
|
github.com/prometheus/client_golang v1.14.0
|
||||||
github.com/slayer/autorestart v0.0.0-20170706172547-5ebd91f955ae
|
github.com/slayer/autorestart v0.0.0-20170706172547-5ebd91f955ae
|
||||||
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/zclconf/go-cty v1.13.0
|
github.com/zclconf/go-cty v1.13.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,11 +21,13 @@ require (
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/kr/pretty v0.2.0 // indirect
|
github.com/kr/pretty v0.2.0 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/client_model v0.3.0 // indirect
|
github.com/prometheus/client_model v0.3.0 // indirect
|
||||||
github.com/prometheus/common v0.42.0 // indirect
|
github.com/prometheus/common v0.42.0 // indirect
|
||||||
github.com/prometheus/procfs v0.9.0 // indirect
|
github.com/prometheus/procfs v0.9.0 // indirect
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -12,7 +12,9 @@ github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/I
|
||||||
github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
|
github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
@ -41,6 +43,7 @@ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTS
|
||||||
github.com/pebbe/zmq4 v1.2.9 h1:JlHcdgq6zpppNR1tH0wXJq0XK03pRUc4lBlHTD7aj/4=
|
github.com/pebbe/zmq4 v1.2.9 h1:JlHcdgq6zpppNR1tH0wXJq0XK03pRUc4lBlHTD7aj/4=
|
||||||
github.com/pebbe/zmq4 v1.2.9/go.mod h1:nqnPueOapVhE2wItZ0uOErngczsJdLOGkebMxaO8r48=
|
github.com/pebbe/zmq4 v1.2.9/go.mod h1:nqnPueOapVhE2wItZ0uOErngczsJdLOGkebMxaO8r48=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||||
|
@ -52,7 +55,11 @@ github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB
|
||||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||||
github.com/slayer/autorestart v0.0.0-20170706172547-5ebd91f955ae h1:hnJJroq/kooxO2jUKDc8KXxj8tilWvOlD0hzDDv05ss=
|
github.com/slayer/autorestart v0.0.0-20170706172547-5ebd91f955ae h1:hnJJroq/kooxO2jUKDc8KXxj8tilWvOlD0hzDDv05ss=
|
||||||
github.com/slayer/autorestart v0.0.0-20170706172547-5ebd91f955ae/go.mod h1:p+QQKBy7tS+myk+y3sgnAKx4gUtD/Q9Z6KEd77cLzWY=
|
github.com/slayer/autorestart v0.0.0-20170706172547-5ebd91f955ae/go.mod h1:p+QQKBy7tS+myk+y3sgnAKx4gUtD/Q9Z6KEd77cLzWY=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0=
|
github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0=
|
||||||
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
|
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -66,5 +73,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||||
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
||||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
65
internal/chaindb/chaindb_test.go
Normal file
65
internal/chaindb/chaindb_test.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package chaindb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gstructs "github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const testChainDBPath = "test_chaindb.hcl"
|
||||||
|
|
||||||
|
func TestGagentDb(t *testing.T) {
|
||||||
|
// Create a new GagentDb
|
||||||
|
db := NewGagentDb()
|
||||||
|
|
||||||
|
// Add a row to the database
|
||||||
|
row := &GagentDbRow{
|
||||||
|
DBName: "testDB",
|
||||||
|
Agent: gstructs.AgentDetails{
|
||||||
|
Client: "testAgent",
|
||||||
|
Shasum: "v1.0.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
db.AddRow(row)
|
||||||
|
|
||||||
|
// Check if the row was added correctly
|
||||||
|
if len(db.ChainRow) != 1 {
|
||||||
|
t.Errorf("Expected length of ChainRow to be 1, but got %d", len(db.ChainRow))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the timestamp was set correctly
|
||||||
|
if db.ChainRow[0].Timestamp.After(time.Now()) {
|
||||||
|
t.Error("Timestamp is incorrectly set in the future")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the database to an HCL file
|
||||||
|
err := db.WriteHCL(testChainDBPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error writing HCL file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the database from the HCL file
|
||||||
|
loadedDb := NewGagentDb()
|
||||||
|
err = loadedDb.LoadHCL(testChainDBPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error loading HCL file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the loaded database is the same as the original one
|
||||||
|
if !bytes.Equal(loadedDb.ChainRow[0].DbCurrHash[:], db.ChainRow[0].DbCurrHash[:]) {
|
||||||
|
t.Error("Loaded database has a different current hash than the original one")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(loadedDb.ChainRow[0].DbPrevHash[:], db.ChainRow[0].DbPrevHash[:]) {
|
||||||
|
t.Error("Loaded database has a different previous hash than the original one")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up the test HCL file
|
||||||
|
err = os.Remove(testChainDBPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error cleaning up test HCL file: %v", err)
|
||||||
|
}
|
||||||
|
}
|
152
internal/client/client_test.go
Normal file
152
internal/client/client_test.go
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
gstructs "github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
zmq "github.com/pebbe/zmq4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mockSocket struct {
|
||||||
|
sendMessageError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockSocket) Close() error { return nil }
|
||||||
|
func (m *mockSocket) Bind(endpoint string) error { return nil }
|
||||||
|
func (m *mockSocket) Connect(endpoint string) error { return nil }
|
||||||
|
func (m *mockSocket) SetIdentity(identity string) error { return nil }
|
||||||
|
func (m *mockSocket) SendMessage(parts ...interface{}) (int, error) { return 0, m.sendMessageError }
|
||||||
|
func (m *mockSocket) RecvMessage(flags zmq.Flag) ([]string, error) { return nil, nil }
|
||||||
|
func (m *mockSocket) RecvMessageBytes(flags zmq.Flag) ([][]byte, error) { return nil, nil }
|
||||||
|
func (m *mockSocket) RecvMessageString(flags zmq.Flag) ([]string, error) { return nil, nil }
|
||||||
|
func (m *mockSocket) SetSubscribe(filter string) error { return nil }
|
||||||
|
func (m *mockSocket) SetUnsubscribe(filter string) error { return nil }
|
||||||
|
func (m *mockSocket) Send(msg string, flags zmq.Flag) (int, error) { return 0, nil }
|
||||||
|
func (m *mockSocket) SendBytes(msg []byte, flags zmq.Flag) (int, error) { return 0, nil }
|
||||||
|
func (m *mockSocket) SendFrame(msg []byte, flags zmq.Flag) (int, error) { return 0, nil }
|
||||||
|
func (m *mockSocket) SendMultipart(parts [][]byte, flags zmq.Flag) (int, error) { return 0, nil }
|
||||||
|
func (m *mockSocket) Recv(flags zmq.Flag) (string, error) { return "", nil }
|
||||||
|
func (m *mockSocket) RecvBytes(flags zmq.Flag) ([]byte, error) { return nil, nil }
|
||||||
|
func (m *mockSocket) RecvFrame(flags zmq.Flag) ([]byte, error) { return nil, nil }
|
||||||
|
func (m *mockSocket) RecvMultipart(flags zmq.Flag) ([][]byte, error) { return nil, nil }
|
||||||
|
func (m *mockSocket) SetOption(option zmq.SocketOption, value interface{}) error { return nil }
|
||||||
|
func (m *mockSocket) GetOption(option zmq.SocketOption) (interface{}, error) { return nil, nil }
|
||||||
|
func (m *mockSocket) Events() zmq.State { return 0 }
|
||||||
|
func (m *mockSocket) String() string { return "" }
|
||||||
|
|
||||||
|
func TestGetTagsFromHints(t *testing.T) {
|
||||||
|
agent := gstructs.AgentDetails{
|
||||||
|
Script: []byte(`*set GHINT[split "tag1,tag2,tag3",]`),
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedHints := []string{"tag1", "tag2", "tag3"}
|
||||||
|
hints := getTagsFromHints(agent)
|
||||||
|
|
||||||
|
if !equalStringSlices(hints, expectedHints) {
|
||||||
|
t.Errorf("Expected hints %v, but got %v", expectedHints, hints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendAgent(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
config := gstructs.GagentConfig{
|
||||||
|
UUID: "test-uuid",
|
||||||
|
ClientPort: 1234,
|
||||||
|
Routers: map[string]gstructs.Router{
|
||||||
|
"test-router": {
|
||||||
|
RouterAddr: "127.0.0.1",
|
||||||
|
ClientPort: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := gstructs.AgentDetails{
|
||||||
|
Client: "test-client",
|
||||||
|
Script: []byte(`*set GHINT[split "tag1,tag2,tag3",]`),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace zmq.NewSocket with a function that returns a mock socket
|
||||||
|
origNewSocket := newSocket
|
||||||
|
defer func() { newSocket = origNewSocket }()
|
||||||
|
newSocket = func(t zmq.Type) (zmq.Socket, error) {
|
||||||
|
return &mockSocket{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go sendAgent(wg, config.UUID, "tcp://127.0.0.1:1234", agent)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
// Test with an error in sending a message
|
||||||
|
newSocket = func(t zmq.Type) (zmq.Socket, error) {
|
||||||
|
return &mockSocket{sendMessageError: errors.New("send message error")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go sendAgent(wg, config.UUID, "tcp://127.0.0.1:1234", agent)
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalStringSlices(a, b []string) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range a {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(t *testing.T) {
|
||||||
|
// Prepare a temporary agent file for testing
|
||||||
|
tmpAgentFile, err := ioutil.TempFile("", "agent")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tmpAgentFile.Name())
|
||||||
|
|
||||||
|
content := []byte(`*set GHINT[split "tag1,tag2,tag3",]`)
|
||||||
|
if _, err := tmpAgentFile.Write(content); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := tmpAgentFile.Close(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := gstructs.GagentConfig{
|
||||||
|
CMode: true,
|
||||||
|
UUID: "test-uuid",
|
||||||
|
ClientPort: 1234,
|
||||||
|
Agent: tmpAgentFile.Name(),
|
||||||
|
Routers: map[string]gstructs.Router{
|
||||||
|
"test-router": {
|
||||||
|
RouterAddr: "127.0.0.1",
|
||||||
|
ClientPort: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace log output with a buffer to suppress output during testing
|
||||||
|
origLogOutput := log.Writer()
|
||||||
|
defer log.SetOutput(origLogOutput)
|
||||||
|
log.SetOutput(&bytes.Buffer{})
|
||||||
|
|
||||||
|
// Replace zmq.NewSocket with a function that returns a mock socket
|
||||||
|
origNewSocket := newSocket
|
||||||
|
defer func() { newSocket = origNewSocket }()
|
||||||
|
newSocket = func(t zmq.Type) (zmq.Socket, error) {
|
||||||
|
return &mockSocket{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
go Main(wg, config)
|
||||||
|
wg.Wait()
|
||||||
|
}
|
35
internal/gstructs/agent_status.go
Normal file
35
internal/gstructs/agent_status.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package gstructs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AgentStatus []string
|
||||||
|
|
||||||
|
var AgentStatuses = AgentStatus{
|
||||||
|
"ERROR",
|
||||||
|
"INIT",
|
||||||
|
"SENDING",
|
||||||
|
"RECEIVING",
|
||||||
|
"ROUTING",
|
||||||
|
"PROCESSING",
|
||||||
|
"COMPLETED",
|
||||||
|
"RETURNING",
|
||||||
|
"ERROR",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AgentStatus) GetByIndex(index int) (string, error) {
|
||||||
|
if index < 0 || index >= len(a) {
|
||||||
|
return "", fmt.Errorf("invalid index: %d", index)
|
||||||
|
}
|
||||||
|
return a[index], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AgentStatus) GetByName(name string) (byte, error) {
|
||||||
|
for i, status := range a {
|
||||||
|
if status == name {
|
||||||
|
return byte(i), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("value not found: %s", name)
|
||||||
|
}
|
59
internal/gstructs/agent_status_test.go
Normal file
59
internal/gstructs/agent_status_test.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package gstructs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetByIndex(t *testing.T) {
|
||||||
|
agentStatuses := gstructs.AgentStatuses
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
index int
|
||||||
|
expected string
|
||||||
|
shouldReturn bool
|
||||||
|
}{
|
||||||
|
{0, "ERROR", true},
|
||||||
|
{1, "INIT", true},
|
||||||
|
{8, "ERROR", true},
|
||||||
|
{9, "", false},
|
||||||
|
{-1, "", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
res, err := agentStatuses.GetByIndex(test.index)
|
||||||
|
if test.shouldReturn {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.expected, res)
|
||||||
|
} else {
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetByName(t *testing.T) {
|
||||||
|
agentStatuses := gstructs.AgentStatuses
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expected byte
|
||||||
|
shouldReturn bool
|
||||||
|
}{
|
||||||
|
{"ERROR", 0, true},
|
||||||
|
{"INIT", 1, true},
|
||||||
|
{"COMPLETED", 6, true},
|
||||||
|
{"INVALID", 0, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
res, err := agentStatuses.GetByName(test.name)
|
||||||
|
if test.shouldReturn {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.expected, res)
|
||||||
|
} else {
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -111,10 +111,10 @@ type WorkerDetails struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentDetails struct {
|
type AgentDetails struct {
|
||||||
Status byte `hcl:"status"`
|
Status byte `hcl:"status"`
|
||||||
Client string `hcl:"client"`
|
Client string `hcl:"client"`
|
||||||
Shasum string `hcl:"shasum"`
|
Shasum string `hcl:"shasum"`
|
||||||
Hints []string
|
Hints []string `hcl:"hints"`
|
||||||
Script []byte
|
Script []byte `hcl:"script"`
|
||||||
Answer []byte
|
Answer []byte `hcl:"answer"`
|
||||||
}
|
}
|
||||||
|
|
76
internal/gstructs/gstructs_test.go
Normal file
76
internal/gstructs/gstructs_test.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package gstructs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGagentConfig(t *testing.T) {
|
||||||
|
config := gstructs.GagentConfig{
|
||||||
|
Name: "test-config",
|
||||||
|
Mode: "client",
|
||||||
|
UUID: "test-uuid",
|
||||||
|
ListenAddr: "127.0.0.1",
|
||||||
|
ChainDBPath: "/tmp/chaindb",
|
||||||
|
MonitorPort: 8888,
|
||||||
|
ClientPort: 1234,
|
||||||
|
RouterPort: 5678,
|
||||||
|
WorkerPort: 9012,
|
||||||
|
Clients: []*gstructs.ClientDetails{
|
||||||
|
{
|
||||||
|
ClientName: "test-client",
|
||||||
|
ClientID: "client-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Routers: []*gstructs.RouterDetails{
|
||||||
|
{
|
||||||
|
RouterName: "test-router",
|
||||||
|
RouterID: "router-id",
|
||||||
|
RouterAddr: "192.168.1.1",
|
||||||
|
RouterTags: []string{"tag1", "tag2"},
|
||||||
|
ClientPort: 1234,
|
||||||
|
RouterPort: 5678,
|
||||||
|
WorkerPort: 9012,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Workers: []*gstructs.WorkerDetails{
|
||||||
|
{
|
||||||
|
WorkerName: "test-worker",
|
||||||
|
WorkerID: "worker-id",
|
||||||
|
WorkerTags: []string{"tag3", "tag4"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Version: "1.0.0",
|
||||||
|
File: "config.hcl",
|
||||||
|
Agent: "agent.gagent",
|
||||||
|
CMode: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Name != "test-config" {
|
||||||
|
t.Errorf("Expected config name to be 'test-config', got %s", config.Name)
|
||||||
|
}
|
||||||
|
if config.Mode != "client" {
|
||||||
|
t.Errorf("Expected config mode to be 'client', got %s", config.Mode)
|
||||||
|
}
|
||||||
|
// TODO: add more assertions for other config fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgentDetails(t *testing.T) {
|
||||||
|
agent := gstructs.AgentDetails{
|
||||||
|
Status: 1,
|
||||||
|
Client: "test-client",
|
||||||
|
Shasum: "123456789abcdef",
|
||||||
|
Hints: []string{"tag1", "tag2", "tag3"},
|
||||||
|
Script: []byte("sample script content"),
|
||||||
|
Answer: []byte("sample answer content"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if agent.Status != 1 {
|
||||||
|
t.Errorf("Expected agent status to be 1, got %d", agent.Status)
|
||||||
|
}
|
||||||
|
if agent.Client != "test-client" {
|
||||||
|
t.Errorf("Expected agent client to be 'test-client', got %s", agent.Client)
|
||||||
|
}
|
||||||
|
// TODO: add more assertions for other agent fields
|
||||||
|
}
|
72
internal/router/router_test.go
Normal file
72
internal/router/router_test.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package router_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gs "github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
"github.com/dragonheim/gagent/internal/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRouterMain(t *testing.T) {
|
||||||
|
config := gs.GagentConfig{
|
||||||
|
Name: "test-config",
|
||||||
|
Mode: "router",
|
||||||
|
UUID: "test-uuid",
|
||||||
|
ListenAddr: "127.0.0.1",
|
||||||
|
ClientPort: 1234,
|
||||||
|
RouterPort: 5678,
|
||||||
|
WorkerPort: 9012,
|
||||||
|
ChainDBPath: "test-chaindb-path",
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go router.Main(wg, config)
|
||||||
|
|
||||||
|
// Allow router to start before sending HTTP requests
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
|
||||||
|
// Test GET request
|
||||||
|
resp := makeRequest(t, "GET", "http://localhost:1234/hello")
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
t.Errorf("Expected status code %d, got %d", http.StatusOK, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test POST request
|
||||||
|
resp = makeRequest(t, "POST", "http://localhost:1234/hello")
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
t.Errorf("Expected status code %d, got %d", http.StatusOK, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test OPTIONS request
|
||||||
|
resp = makeRequest(t, "OPTIONS", "http://localhost:1234/hello")
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
t.Errorf("Expected status code %d, got %d", http.StatusNoContent, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test unsupported method
|
||||||
|
resp = makeRequest(t, "PUT", "http://localhost:1234/hello")
|
||||||
|
if resp.StatusCode != http.StatusMethodNotAllowed {
|
||||||
|
t.Errorf("Expected status code %d, got %d", http.StatusMethodNotAllowed, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRequest(t *testing.T, method, url string) *http.Response {
|
||||||
|
req, err := http.NewRequest(method, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error creating request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
handler := http.HandlerFunc(router.AnswerClient)
|
||||||
|
handler.ServeHTTP(rr, req)
|
||||||
|
|
||||||
|
return rr.Result()
|
||||||
|
}
|
57
internal/setup/setup_test.go
Normal file
57
internal/setup/setup_test.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package setup_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
gs "github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
"github.com/dragonheim/gagent/internal/setup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetupMain(t *testing.T) {
|
||||||
|
config := gs.GagentConfig{
|
||||||
|
Name: "test-config",
|
||||||
|
Mode: "client",
|
||||||
|
UUID: "test-uuid",
|
||||||
|
ListenAddr: "127.0.0.1",
|
||||||
|
ClientPort: 1234,
|
||||||
|
RouterPort: 5678,
|
||||||
|
WorkerPort: 9012,
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
capturedOutput := captureOutput(func() {
|
||||||
|
setup.Main(wg, config)
|
||||||
|
})
|
||||||
|
|
||||||
|
expectedOutput := `Configuration file created`
|
||||||
|
if !strings.Contains(capturedOutput, expectedOutput) {
|
||||||
|
t.Errorf("Expected output to contain '%s', got '%s'", expectedOutput, capturedOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func captureOutput(f func()) string {
|
||||||
|
original := *log.Writer()
|
||||||
|
r, w, _ := os.Pipe()
|
||||||
|
log.SetOutput(w)
|
||||||
|
|
||||||
|
f()
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
log.SetOutput(original)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
io.Copy(&buf, r)
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
65
internal/worker/worker_test.go
Normal file
65
internal/worker/worker_test.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package worker_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
gs "github.com/dragonheim/gagent/internal/gstructs"
|
||||||
|
"github.com/dragonheim/gagent/internal/worker"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWorkerMain(t *testing.T) {
|
||||||
|
config := gs.GagentConfig{
|
||||||
|
Name: "test-config",
|
||||||
|
Mode: "worker",
|
||||||
|
UUID: "test-uuid",
|
||||||
|
ListenAddr: "127.0.0.1",
|
||||||
|
ClientPort: 1234,
|
||||||
|
RouterPort: 5678,
|
||||||
|
WorkerPort: 9012,
|
||||||
|
Routers: []*gs.RouterDetails{
|
||||||
|
{
|
||||||
|
RouterName: "test-router",
|
||||||
|
RouterID: "test-router-id",
|
||||||
|
RouterAddr: "127.0.0.1",
|
||||||
|
WorkerPort: 9012,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
capturedOutput := captureOutput(func() {
|
||||||
|
worker.Main(wg, config)
|
||||||
|
})
|
||||||
|
|
||||||
|
expectedOutput := `Starting worker`
|
||||||
|
if !strings.Contains(capturedOutput, expectedOutput) {
|
||||||
|
t.Errorf("Expected output to contain '%s', got '%s'", expectedOutput, capturedOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func captureOutput(f func()) string {
|
||||||
|
original := *log.Writer()
|
||||||
|
r, w, _ := os.Pipe()
|
||||||
|
log.SetOutput(w)
|
||||||
|
|
||||||
|
f()
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
log.SetOutput(original)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
io.Copy(&buf, r)
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue