diff --git a/src/core/api.go b/src/core/api.go index 20e1b38d..875d7bf2 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -1,11 +1,8 @@ package core import ( - "bytes" "crypto/ed25519" - "encoding/binary" "encoding/json" - "fmt" "net" "net/url" "sync/atomic" @@ -253,29 +250,3 @@ func (c *Core) SetAdmin(a AddHandler) error { } return nil } - -func (peerinfo PeerInfo) GetCoordinates() *[]byte { - var coordsBlob []byte - if peerinfo.Coords != nil { - coordsBlob = make([]byte, len(peerinfo.Coords)*8) - for i, coord := range peerinfo.Coords { - binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord) - } - } - return &coordsBlob -} - -func (peerinfo PeerInfo) SetCoordinates(coords *[]byte) error { - if len(*coords)%8 != 0 { - return fmt.Errorf("length of byte slice must be a multiple of 8") - } - numUint64 := len(*coords) / 8 - buf := bytes.NewReader(*coords) - for i := 0; i < numUint64; i++ { - err := binary.Read(buf, binary.LittleEndian, &peerinfo.Coords[i]) - if err != nil { - return err - } - } - return nil -} diff --git a/src/core/db.go b/src/core/db.go new file mode 100644 index 00000000..e97da5c5 --- /dev/null +++ b/src/core/db.go @@ -0,0 +1,178 @@ +package core + +import ( + "bytes" + "crypto/ed25519" + "crypto/x509" + "database/sql" + "encoding/binary" + "errors" + "fmt" +) + +type PeerInfoDB struct { + PeerInfo + Id int + CoordsBytes []byte + KeyBytes []byte + RootBytes []byte + PeerErr sql.NullString +} + +type SelfInfoDB struct { + SelfInfo + Id int + KeyBytes []byte +} + +type TreeEntryInfoDB struct { + TreeEntryInfo + Id int + KeyBytes []byte + ParentBytes []byte +} + +type PathEntryInfoDB struct { + PathEntryInfo + Id int + KeyBytes []byte + PathBytes []byte +} + +type SessionInfoDB struct { + SessionInfo + Id int + KeyBytes []byte +} + +func NewPeerInfoDB(peerInfo PeerInfo) (_ *PeerInfoDB, err error) { + peer := &PeerInfoDB{ + PeerInfo: peerInfo, + } + peer.PeerErr = MarshalError(peer.LastError) + peer.CoordsBytes = ConvertToByteSlise(peer.Coords) + peer.KeyBytes, err = MarshalPKIXPublicKey(&peer.Key) + if err != nil { + return nil, err + } + peer.RootBytes, err = MarshalPKIXPublicKey(&peer.Root) + if err != nil { + return nil, err + } + return peer, nil +} + +func NewSelfInfoDB(selfinfo SelfInfo) (_ *SelfInfoDB, err error) { + model := &SelfInfoDB{ + SelfInfo: selfinfo, + } + model.KeyBytes, err = MarshalPKIXPublicKey(&model.Key) + if err != nil { + return nil, err + } + return model, nil +} + +func NewTreeEntryInfoDB(treeEntyInfo TreeEntryInfo) (_ *TreeEntryInfoDB, err error) { + model := &TreeEntryInfoDB{ + TreeEntryInfo: treeEntyInfo, + } + model.KeyBytes, err = MarshalPKIXPublicKey(&model.Key) + if err != nil { + return nil, err + } + model.ParentBytes, err = MarshalPKIXPublicKey(&model.Parent) + if err != nil { + return nil, err + } + return model, nil +} + +func NewPathEntryInfoDB(PathEntryInfo PathEntryInfo) (_ *PathEntryInfoDB, err error) { + model := &PathEntryInfoDB{ + PathEntryInfo: PathEntryInfo, + } + model.KeyBytes, err = MarshalPKIXPublicKey(&model.Key) + if err != nil { + return nil, err + } + model.PathBytes = ConvertToByteSlise(model.Path) + + return model, nil +} + +func NewSessionInfoDB(SessionInfo SessionInfo) (_ *SessionInfoDB, err error) { + model := &SessionInfoDB{ + SessionInfo: SessionInfo, + } + model.KeyBytes, err = MarshalPKIXPublicKey(&model.Key) + if err != nil { + return nil, err + } + return model, nil +} + +func ConvertToByteSlise(uintSlise []uint64) []byte { + var ByteSlise []byte + if uintSlise != nil { + ByteSlise = make([]byte, len(uintSlise)*8) + for i, coord := range uintSlise { + binary.LittleEndian.PutUint64(ByteSlise[i*8:], coord) + } + } + return ByteSlise +} + +func ConvertToUintSlise(ByteSlise []byte) (_ []uint64, err error) { + if len(ByteSlise)%8 != 0 { + return nil, fmt.Errorf("length of byte slice must be a multiple of 8") + } + var uintSlise []uint64 + length := len(ByteSlise) / 8 + uintSlise = make([]uint64, length) + reader := bytes.NewReader(ByteSlise) + for i := 0; i < length; i++ { + err := binary.Read(reader, binary.LittleEndian, &uintSlise[i]) + if err != nil { + return nil, err + } + } + return uintSlise, nil +} + +func MarshalPKIXPublicKey(PublicKey *ed25519.PublicKey) ([]byte, error) { + pkey, err := x509.MarshalPKIXPublicKey(*PublicKey) + if err != nil { + return nil, err + } + return pkey, nil +} + +func ParsePKIXPublicKey(derBytes *[]byte) (PublicKey ed25519.PublicKey, err error) { + key, err := x509.ParsePKIXPublicKey(*derBytes) + if err != nil { + return nil, err + } + return key.(ed25519.PublicKey), nil +} + +func ParseError(PeerErr sql.NullString) error { + if PeerErr.Valid { + return errors.New(PeerErr.String) + } + return nil +} + +func MarshalError(err error) sql.NullString { + if err != nil { + return sql.NullString{ + String: err.Error(), + Valid: true, + } + } else { + return sql.NullString{ + String: "", + Valid: false, + } + } +} diff --git a/src/db/PathEntryInfoDB/PathEntryInfoDB.go b/src/db/PathEntryInfoDB/PathEntryInfoDB.go new file mode 100644 index 00000000..58b3d394 --- /dev/null +++ b/src/db/PathEntryInfoDB/PathEntryInfoDB.go @@ -0,0 +1,108 @@ +package pathentryinfodb + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + + "github.com/yggdrasil-network/yggdrasil-go/src/core" + "github.com/yggdrasil-network/yggdrasil-go/src/db" +) + +type PathEntryInfoDBConfig struct { + DbConfig *db.DbConfig + name string +} + +var Name = "PathEntryInfo" + +func New() (*PathEntryInfoDBConfig, error) { + dir, _ := os.Getwd() + fileName := fmt.Sprintf("%s.db", Name) + filePath := filepath.Join(dir, fileName) + schemas := []string{ + `CREATE TABLE IF NOT EXISTS path_entry_info ( + Id INTEGER NOT NULL PRIMARY KEY, + Key BLOB, + Path BLOB, + Sequence INTEGER + );`} + dbcfg, err := db.New("sqlite3", &schemas, filePath) + if err != nil { + return nil, err + } + cfg := &PathEntryInfoDBConfig{ + name: Name, + DbConfig: dbcfg, + } + return cfg, nil +} + +func (cfg *PathEntryInfoDBConfig) Add(model *core.PathEntryInfoDB) (_ sql.Result, err error) { + query := "INSERT INTO path_entry_info (Key, Path, Sequence) VALUES (?, ?, ?)" + result, err := cfg.DbConfig.DB.Exec( + query, + model.KeyBytes, + model.PathBytes, + model.Sequence) + if err != nil { + return nil, err + } + lastInsertId, err := result.LastInsertId() + if err != nil { + return nil, err + } + model.Id = int(lastInsertId) + return result, nil +} + +func (cfg *PathEntryInfoDBConfig) Remove(model *core.PathEntryInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec("DELETE FROM path_entry_info WHERE Id = ?", + model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *PathEntryInfoDBConfig) Update(model *core.PathEntryInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec(`UPDATE path_entry_info + SET + Sequence = ?, + Key = ?, + Path = ? + WHERE + Id = ?`, + model.Sequence, model.KeyBytes, model.PathBytes, model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *PathEntryInfoDBConfig) Get(model *core.PathEntryInfoDB) (_ *sql.Rows, err error) { + rows, err := cfg.DbConfig.DB.Query("SELECT Sequence, Key, Path FROM path_entry_info WHERE Id = ?", + model.Id, + ) + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + err = rows.Scan(&model.Sequence, &model.KeyBytes, &model.PathBytes) + if err != nil { + return nil, err + } + } + return rows, nil +} + +func (cfg *PathEntryInfoDBConfig) Count() (int, error) { + var count int + err := cfg.DbConfig.DB.QueryRow("SELECT COUNT(*) FROM path_entry_info").Scan(&count) + if err != nil { + return 0, err + } + return count, nil +} diff --git a/src/db/PeerInfoDB/PeerInfoDB.go b/src/db/PeerInfoDB/PeerInfoDB.go index c45d13a6..96897fc5 100644 --- a/src/db/PeerInfoDB/PeerInfoDB.go +++ b/src/db/PeerInfoDB/PeerInfoDB.go @@ -1,9 +1,7 @@ package peerinfodb import ( - "crypto/ed25519" - "crypto/x509" - "encoding/binary" + "database/sql" "fmt" "os" "path/filepath" @@ -26,19 +24,20 @@ func New() (*PeerInfoDBConfig, error) { filePath := filepath.Join(dir, fileName) schemas := []string{ `CREATE TABLE IF NOT EXISTS peer_infos ( + Id INTEGER NOT NULL PRIMARY KEY, uri TEXT, - up BOOLEAN, - inbound BOOLEAN, - last_error VARCHAR, - last_error_time TIMESTAMP, - key VARCHAR, - root VARCHAR, - coords VARCHAR, + up INTEGER, + inbound INTEGER, + last_error TEXT NULL, + last_error_time TIMESTAMP NULL, + key BLOB, + root BLOB, + coords BLOB, port INT, priority TINYINT, Rxbytes BIGINT, Txbytes BIGINT, - uptime BIGINT, + uptime INTEGER, latency SMALLINT );`} dbcfg, err := db.New("sqlite3", &schemas, filePath) @@ -52,132 +51,84 @@ func New() (*PeerInfoDBConfig, error) { return cfg, nil } -func (cfg *PeerInfoDBConfig) AddPeer(peer core.PeerInfo) (err error) { - var key, root []byte - if peer.Key != nil { - key, err = x509.MarshalPKIXPublicKey(peer.Key) +func (cfg *PeerInfoDBConfig) Add(model *core.PeerInfoDB) (_ sql.Result, err error) { + query := "INSERT OR REPLACE INTO peer_infos (uri, up, inbound, last_error, last_error_time, key, root, coords, port, priority, Rxbytes, Txbytes, uptime, latency) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + result, err := cfg.DbConfig.DB.Exec(query, + model.URI, + model.Up, + model.Inbound, + model.PeerErr, + model.LastErrorTime, + model.KeyBytes, + model.RootBytes, + model.CoordsBytes, + model.Port, + model.Priority, + model.RXBytes, + model.TXBytes, + model.Uptime, + model.Latency) + if err != nil { + return nil, err + } + LastInsertId, err := result.LastInsertId() + if err != nil { + return nil, err + } + model.Id = int(LastInsertId) + return result, nil +} + +func (cfg *PeerInfoDBConfig) Remove(model *core.PeerInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec("DELETE FROM peer_infos WHERE Id = ?", + model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *PeerInfoDBConfig) Get(model *core.PeerInfoDB) (_ *sql.Rows, err error) { + rows, err := cfg.DbConfig.DB.Query(` + SELECT + up, inbound, last_error, last_error_time, coords, port, + priority, Rxbytes, Txbytes, uptime, latency, uri, key, root + FROM + peer_infos + WHERE Id = ?`, + model.Id) + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + err = rows.Scan(&model.Up, &model.Inbound, &model.PeerErr, &model.LastErrorTime, &model.CoordsBytes, + &model.Port, &model.Priority, &model.RXBytes, &model.TXBytes, &model.Uptime, &model.Latency, + &model.URI, &model.KeyBytes, &model.RootBytes) if err != nil { - return err + return rows, err } } - if peer.Root != nil { - root, err = x509.MarshalPKIXPublicKey(peer.Root) - if err != nil { - return err - } - } - var peerErr interface{} - if peer.LastError != nil { - peerErr = peer.LastError.Error() - } else { - peerErr = nil - } - var coordsBlob []byte - if peer.Coords != nil { - coordsBlob = make([]byte, len(peer.Coords)*8) - for i, coord := range peer.Coords { - binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord) - } - } - if !cfg.DbConfig.DBIsOpened() { - return nil - } - _, err = cfg.DbConfig.DB.Exec(` - INSERT OR REPLACE INTO peer_infos - ( - uri, - up, - inbound, - last_error, - last_error_time, - key, - root, - coords, - port, - priority, - Rxbytes, - Txbytes, - uptime, - latency - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - peer.URI, peer.Up, peer.Inbound, peerErr, peer.LastErrorTime, key, root, coordsBlob, peer.Port, peer.Priority, peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency) + + model.Coords, err = core.ConvertToUintSlise(model.CoordsBytes) if err != nil { - return err + return nil, err } - return nil + publickey, err := core.ParsePKIXPublicKey(&model.KeyBytes) + if err != nil { + return nil, err + } + model.Key = publickey + publicRoot, err := core.ParsePKIXPublicKey(&model.RootBytes) + if err != nil { + return nil, err + } + model.Root = publicRoot + model.LastError = core.ParseError(model.PeerErr) + return rows, nil } -func (cfg *PeerInfoDBConfig) RemovePeer(peer core.PeerInfo) (err error) { - key, err := x509.MarshalPKIXPublicKey(peer.Key) - if err != nil { - return err - } - root, err := x509.MarshalPKIXPublicKey(peer.Root) - if err != nil { - return err - } - _, err = cfg.DbConfig.DB.Exec("DELETE FROM peer_infos WHERE uri = ? AND key = ? AND root = ?", - peer.URI, key, root) - if err != nil { - return err - } - return nil -} - -func (cfg *PeerInfoDBConfig) GetPeer(peer *core.PeerInfo) (err error) { - key, err := x509.MarshalPKIXPublicKey(peer.Key) - if err != nil { - return err - } - root, err := x509.MarshalPKIXPublicKey(peer.Root) - if err != nil { - return err - } - row := cfg.DbConfig.DB.QueryRow("SELECT * FROM peer_infos WHERE uri = ? AND key = ? AND root = ?", - peer.URI, key, root) - var coord []byte - var peerErr interface{} - err = row.Scan(&peer.URI, &peer.Up, &peer.Inbound, &peerErr, &peer.LastErrorTime, &key, &root, &coord, &peer.Port, &peer.Priority, &peer.RXBytes, &peer.TXBytes, &peer.Uptime, &peer.Latency) - if err != nil { - return err - } - - parsedKey, err := x509.ParsePKCS8PrivateKey(key) - if err != nil { - return err - } - ParsedRoot, err := x509.ParsePKCS8PrivateKey(root) - if err != nil { - return err - } - peer.Key = parsedKey.(ed25519.PublicKey) - peer.Root = ParsedRoot.(ed25519.PublicKey) - return nil -} - -func (cfg *PeerInfoDBConfig) UpdatePeer(peer core.PeerInfo) (err error) { - key, err := x509.MarshalPKIXPublicKey(peer.Key) - if err != nil { - return err - } - root, err := x509.MarshalPKIXPublicKey(peer.Root) - if err != nil { - return err - } - var peerErr interface{} - if peer.LastError != nil { - peerErr = peer.LastError.Error() - } else { - peerErr = nil - } - var coordsBlob []byte - if peer.Coords != nil { - coordsBlob = make([]byte, len(peer.Coords)*8) - for i, coord := range peer.Coords { - binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord) - } - } +func (cfg *PeerInfoDBConfig) Update(model *core.PeerInfoDB) (err error) { _, err = cfg.DbConfig.DB.Exec(`UPDATE peer_infos SET up = ?, @@ -189,12 +140,15 @@ func (cfg *PeerInfoDBConfig) UpdatePeer(peer core.PeerInfo) (err error) { priority = ?, RXBytes = RXBytes + ?, TXBytes = TXBytes + ?, - uptime = ?, - latency = ? + uptime = uptime + ?, + latency = ?, + uri = ?, + key = ?, + root = ? WHERE - uri = ? AND key = ? AND root = ?`, - peer.Up, peer.Inbound, peerErr, peer.LastErrorTime, coordsBlob, peer.Port, peer.Priority, - peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency, peer.URI, key, root) + Id = ?`, + model.Up, model.Inbound, model.PeerErr, model.LastErrorTime, model.CoordsBytes, model.Port, model.Priority, + model.RXBytes, model.TXBytes, model.Uptime, model.Latency, model.URI, model.KeyBytes, model.RootBytes, model.Id) if err != nil { return err } diff --git a/src/db/SelfInfoDB/SelfInfoDB.go b/src/db/SelfInfoDB/SelfInfoDB.go new file mode 100644 index 00000000..20499d36 --- /dev/null +++ b/src/db/SelfInfoDB/SelfInfoDB.go @@ -0,0 +1,103 @@ +package selfinfodb + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + + "github.com/yggdrasil-network/yggdrasil-go/src/core" + "github.com/yggdrasil-network/yggdrasil-go/src/db" +) + +type SelfInfoDBConfig struct { + DbConfig *db.DbConfig + name string +} + +var Name = "SelfInfo" + +func New() (*SelfInfoDBConfig, error) { + dir, _ := os.Getwd() + fileName := fmt.Sprintf("%s.db", Name) + filePath := filepath.Join(dir, fileName) + schemas := []string{ + `CREATE TABLE IF NOT EXISTS self_info ( + Id INTEGER NOT NULL PRIMARY KEY, + Key BLOB, + RoutingEntries INTEGER + );`} + dbcfg, err := db.New("sqlite3", &schemas, filePath) + if err != nil { + return nil, err + } + cfg := &SelfInfoDBConfig{ + name: Name, + DbConfig: dbcfg, + } + return cfg, nil +} + +func (cfg *SelfInfoDBConfig) Add(model *core.SelfInfoDB) (_ sql.Result, err error) { + query := "INSERT OR REPLACE INTO self_info (Key, RoutingEntries) VALUES (?, ?)" + result, err := cfg.DbConfig.DB.Exec(query, + model.KeyBytes, + model.RoutingEntries) + if err != nil { + return nil, err + } + lastInsertId, err := result.LastInsertId() + if err != nil { + return nil, err + } + model.Id = int(lastInsertId) + return result, nil +} + +func (cfg *SelfInfoDBConfig) Update(model *core.SelfInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec(`UPDATE self_info + SET + RoutingEntries = ?, + Key = ? + WHERE + Id = ?`, + model.RoutingEntries, model.KeyBytes, model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *SelfInfoDBConfig) Remove(model *core.SelfInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec("DELETE FROM self_info WHERE Id = ?", + model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *SelfInfoDBConfig) Get(model *core.SelfInfoDB) (_ *sql.Rows, err error) { + rows, err := cfg.DbConfig.DB.Query("SELECT RoutingEntries, Key FROM self_info WHERE Id = ?", + model.Id) + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + err = rows.Scan(&model.RoutingEntries, &model.KeyBytes) + if err != nil { + return rows, err + } + } + return rows, nil +} + +func (cfg *SelfInfoDBConfig) Count() (int, error) { + var count int + err := cfg.DbConfig.DB.QueryRow("SELECT COUNT(*) FROM self_info").Scan(&count) + if err != nil { + return 0, err + } + return count, nil +} diff --git a/src/db/SessionInfoDB/SessionInfoDB.go b/src/db/SessionInfoDB/SessionInfoDB.go new file mode 100644 index 00000000..bcb889e2 --- /dev/null +++ b/src/db/SessionInfoDB/SessionInfoDB.go @@ -0,0 +1,111 @@ +package sessioninfodb + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + + "github.com/yggdrasil-network/yggdrasil-go/src/core" + "github.com/yggdrasil-network/yggdrasil-go/src/db" +) + +type SessionInfoDBConfig struct { + DbConfig *db.DbConfig + name string +} + +var Name = "SessionInfo" + +func New() (*SessionInfoDBConfig, error) { + dir, _ := os.Getwd() + fileName := fmt.Sprintf("%s.db", Name) + filePath := filepath.Join(dir, fileName) + schemas := []string{ + `CREATE TABLE IF NOT EXISTS session_info ( + Id INTEGER NOT NULL PRIMARY KEY, + Key BLOB, + RXBytes INTEGER, + TXBytes INTEGER, + Duration INTEGER + );`} + dbcfg, err := db.New("sqlite3", &schemas, filePath) + if err != nil { + return nil, err + } + cfg := &SessionInfoDBConfig{ + name: Name, + DbConfig: dbcfg, + } + return cfg, nil +} + +func (cfg *SessionInfoDBConfig) Add(model *core.SessionInfoDB) (_ sql.Result, err error) { + query := "INSERT INTO session_info (Key, RXBytes, TXBytes, Duration) VALUES (?, ?, ?, ?)" + result, err := cfg.DbConfig.DB.Exec(query, + model.KeyBytes, + model.RXBytes, + model.TXBytes, + model.Uptime, + ) + if err != nil { + return nil, err + } + lastInsertId, err := result.LastInsertId() + if err != nil { + return nil, err + } + model.Id = int(lastInsertId) + return result, nil +} + +func (cfg *SessionInfoDBConfig) Remove(model *core.SessionInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec("DELETE FROM session_info WHERE Id = ?", + model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *SessionInfoDBConfig) Update(model *core.SessionInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec(`UPDATE session_info + SET + RXBytes = RXBytes + ?, + TXBytes = TXBytes + ?, + Duration = Duration + ?, + Key = ? + WHERE + Id = ?`, + model.RXBytes, model.TXBytes, model.Uptime, model.KeyBytes, model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *SessionInfoDBConfig) Get(model *core.SessionInfoDB) (_ *sql.Rows, err error) { + rows, err := cfg.DbConfig.DB.Query("SELECT RXBytes, TXBytes, Duration, Key FROM session_info WHERE Id = ?", + model.Id, + ) + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + err = rows.Scan(&model.RXBytes, &model.TXBytes, &model.Uptime, &model.KeyBytes) + if err != nil { + return nil, err + } + } + return rows, nil +} + +func (cfg *SessionInfoDBConfig) Count() (int, error) { + var count int + err := cfg.DbConfig.DB.QueryRow("SELECT COUNT(*) FROM session_info").Scan(&count) + if err != nil { + return 0, err + } + return count, nil +} diff --git a/src/db/TreeEntryInfoDB/TreeEntryInfoDB.go b/src/db/TreeEntryInfoDB/TreeEntryInfoDB.go new file mode 100644 index 00000000..07420300 --- /dev/null +++ b/src/db/TreeEntryInfoDB/TreeEntryInfoDB.go @@ -0,0 +1,108 @@ +package treeentryinfodb + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + + "github.com/yggdrasil-network/yggdrasil-go/src/core" + "github.com/yggdrasil-network/yggdrasil-go/src/db" +) + +type TreeEntryInfoDBConfig struct { + DbConfig *db.DbConfig + name string +} + +var Name = "TreeEntryInfo" + +func New() (*TreeEntryInfoDBConfig, error) { + dir, _ := os.Getwd() + fileName := fmt.Sprintf("%s.db", Name) + filePath := filepath.Join(dir, fileName) + schemas := []string{ + `CREATE TABLE IF NOT EXISTS tree_entry_info ( + Id INTEGER NOT NULL PRIMARY KEY, + Key BLOB, + Parent BLOB, + Sequence INTEGER + );`} + dbcfg, err := db.New("sqlite3", &schemas, filePath) + if err != nil { + return nil, err + } + cfg := &TreeEntryInfoDBConfig{ + name: Name, + DbConfig: dbcfg, + } + return cfg, nil +} + +func (cfg *TreeEntryInfoDBConfig) Add(model *core.TreeEntryInfoDB) (_ sql.Result, err error) { + query := "INSERT INTO tree_entry_info (Key, Parent, Sequence) VALUES (?, ?, ?)" + result, err := cfg.DbConfig.DB.Exec(query, + model.KeyBytes, + model.ParentBytes, + model.Sequence, + ) + if err != nil { + return nil, err + } + lastInsertId, err := result.LastInsertId() + if err != nil { + return nil, err + } + model.Id = int(lastInsertId) + return result, nil +} + +func (cfg *TreeEntryInfoDBConfig) Remove(model *core.TreeEntryInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec("DELETE FROM tree_entry_info WHERE Id = ?", + model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *TreeEntryInfoDBConfig) Update(model *core.TreeEntryInfoDB) (err error) { + _, err = cfg.DbConfig.DB.Exec(`UPDATE tree_entry_info + SET + Sequence = ?, + Key = ?, + Parent = ? + WHERE + Id = ?`, + model.Sequence, model.KeyBytes, model.ParentBytes, model.Id) + if err != nil { + return err + } + return nil +} + +func (cfg *TreeEntryInfoDBConfig) Get(model *core.TreeEntryInfoDB) (_ *sql.Rows, err error) { + rows, err := cfg.DbConfig.DB.Query("SELECT Sequence, Key, Parent FROM tree_entry_info WHERE Id = ?", + model.Id, + ) + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + err = rows.Scan(&model.Sequence, &model.KeyBytes, &model.ParentBytes) + if err != nil { + return nil, err + } + } + return rows, nil +} + +func (cfg *TreeEntryInfoDBConfig) Count() (int, error) { + var count int + err := cfg.DbConfig.DB.QueryRow("SELECT COUNT(*) FROM tree_entry_info").Scan(&count) + if err != nil { + return 0, err + } + return count, nil +} diff --git a/src/db/test/PeerInfo.db b/src/db/test/PeerInfo.db deleted file mode 100644 index a770f6ab..00000000 Binary files a/src/db/test/PeerInfo.db and /dev/null differ diff --git a/src/db/test/db_test.go b/src/db/test/db_test.go index 118c4e28..e83440a6 100644 --- a/src/db/test/db_test.go +++ b/src/db/test/db_test.go @@ -1,11 +1,9 @@ package db_test import ( - "bytes" "crypto/ed25519" "crypto/rand" - "crypto/x509" - "encoding/binary" + "errors" "fmt" "reflect" "strconv" @@ -20,33 +18,39 @@ import ( ) func TestPeerGetCoords(t *testing.T) { - peer := core.PeerInfo{ + peerinfo := core.PeerInfo{ Coords: []uint64{1, 2, 3, 4}, } + peer := core.PeerInfoDB{ + PeerInfo: peerinfo, + } + target := []byte{1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0} - var coordinates = peer.GetCoordinates() - if reflect.DeepEqual(target, coordinates) { + coordinates := core.ConvertToByteSlise(peer.Coords) + if !reflect.DeepEqual(target, coordinates) { t.Error(fmt.Errorf("Not equal")) } } func TestPeerSetCoords(t *testing.T) { - peer := core.PeerInfo{ - Coords: []uint64{1, 2, 3, 4}, + peerinfo := core.PeerInfo{} + peer := core.PeerInfoDB{ + PeerInfo: peerinfo, } - target := []byte{4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0} - var coordinates = peer.SetCoordinates(&target) - if reflect.DeepEqual(target, coordinates) { + var err error + peer.CoordsBytes = []byte{4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0} + peer.Coords, err = core.ConvertToUintSlise(peer.CoordsBytes) + require.NoError(t, err) + coords := []uint64{4, 3, 2, 1} + if !reflect.DeepEqual(coords, peer.Coords) { t.Error(fmt.Errorf("Not equal")) } - fmt.Print(peer.Coords) } func TestAddPeer(t *testing.T) { mockDB, mock, err := sqlmock.New() require.NoError(t, err) defer mockDB.Close() - cfg, err := peerinfodb.New() require.NoError(t, err) cfg.DbConfig.DB = mockDB @@ -55,12 +59,11 @@ func TestAddPeer(t *testing.T) { require.NoError(t, err) rootPubKey, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - - peer := core.PeerInfo{ + peerinfo := core.PeerInfo{ URI: "test.test", Up: true, Inbound: true, - LastError: nil, + LastError: errors.New("test"), LastErrorTime: time.Now(), Key: pubkey, Root: rootPubKey, @@ -72,28 +75,19 @@ func TestAddPeer(t *testing.T) { Uptime: 3600, Latency: 50.0, } + peer, err := core.NewPeerInfoDB(peerinfo) + require.NoError(t, err) - pKey, err := x509.MarshalPKIXPublicKey(peer.Key) - require.NoError(t, err) - pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root) - require.NoError(t, err) - var coordsBlob []byte - if peer.Coords != nil { - coordsBlob = make([]byte, len(peer.Coords)*8) - for i, coord := range peer.Coords { - binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord) - } - } mock.ExpectExec("INSERT OR REPLACE INTO peer_infos"). WithArgs( peer.URI, peer.Up, peer.Inbound, - nil, + peer.PeerErr, peer.LastErrorTime, - pKey, - pKeyRoot, - coordsBlob, + peer.KeyBytes, + peer.RootBytes, + peer.CoordsBytes, peer.Port, peer.Priority, peer.RXBytes, @@ -103,7 +97,7 @@ func TestAddPeer(t *testing.T) { ). WillReturnResult(sqlmock.NewResult(1, 1)) - err = cfg.AddPeer(peer) + _, err = cfg.Add(peer) require.NoError(t, err) err = mock.ExpectationsWereMet() @@ -114,7 +108,6 @@ func TestRemovePeer(t *testing.T) { mockDB, mock, err := sqlmock.New() require.NoError(t, err) defer mockDB.Close() - cfg, err := peerinfodb.New() require.NoError(t, err) cfg.DbConfig.DB = mockDB @@ -124,11 +117,11 @@ func TestRemovePeer(t *testing.T) { rootPubKey, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - peer := core.PeerInfo{ + peerinfo := core.PeerInfo{ URI: "test.test", Up: true, Inbound: true, - LastError: nil, + LastError: errors.New("test"), LastErrorTime: time.Now(), Key: pubkey, Root: rootPubKey, @@ -140,16 +133,14 @@ func TestRemovePeer(t *testing.T) { Uptime: 3600, Latency: 50.0, } + peer, err := core.NewPeerInfoDB(peerinfo) + require.NoError(t, err) - pKey, err := x509.MarshalPKIXPublicKey(peer.Key) - require.NoError(t, err) - pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root) - require.NoError(t, err) - mock.ExpectExec("DELETE FROM peer_infos WHERE uri = \\? AND key = \\? AND root = \\?"). - WithArgs(peer.URI, pKey, pKeyRoot). + mock.ExpectExec("DELETE FROM peer_infos WHERE Id = \\?"). + WithArgs(peer.Id). WillReturnResult(sqlmock.NewResult(1, 1)) - err = cfg.RemovePeer(peer) + err = cfg.Remove(peer) require.NoError(t, err) err = mock.ExpectationsWereMet() @@ -170,11 +161,11 @@ func TestGetPeer(t *testing.T) { rootPubKey, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - peer := core.PeerInfo{ + peerinfo := core.PeerInfo{ URI: "test.test", Up: true, Inbound: true, - LastError: nil, + LastError: errors.New("test"), LastErrorTime: time.Now(), Key: pubkey, Root: rootPubKey, @@ -186,20 +177,21 @@ func TestGetPeer(t *testing.T) { Uptime: 3600, Latency: 50.0, } - - pKey, err := x509.MarshalPKIXPublicKey(peer.Key) + peer, err := core.NewPeerInfoDB(peerinfo) require.NoError(t, err) - pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root) - require.NoError(t, err) - var coords []byte - rows := sqlmock.NewRows([]string{"uri", "up", "Inbound", "LastError", "LastErrorTime", "Key", "Root", "Coords", "Port", "Priority", "Rxbytes", "Txbytes", "Uptime", "Latency"}). - AddRow(peer.URI, peer.Up, peer.Inbound, peer.LastError, peer.LastErrorTime, peer.Key, peer.Root, coords, peer.Port, peer.Priority, peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency) - mock.ExpectQuery("SELECT * FROM peer_infos WHERE uri = ? AND key = ? AND root = ?"). - WithArgs(peer.URI, pKey, pKeyRoot). + rows := sqlmock.NewRows([]string{"up", "inbound", "last_error", "last_error_time", "coords", + "port", "priority", "Rxbytes", "Txbytes", "uptime", "latency", "uri", "key", "root"}). + AddRow(peer.Up, peer.Inbound, peer.PeerErr, peer.LastErrorTime, peer.CoordsBytes, + peer.Port, peer.Priority, peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency, + peer.URI, peer.KeyBytes, peer.RootBytes) + + mock.ExpectQuery("SELECT (.+) FROM peer_infos WHERE Id = \\?"). + WithArgs(peer.Id). WillReturnRows(rows) - err = cfg.GetPeer(&peer) + _, err = cfg.Get(peer) + t.Log(err) require.NoError(t, err) err = mock.ExpectationsWereMet() @@ -210,7 +202,6 @@ func TestUpdatePeer(t *testing.T) { mockDB, mock, err := sqlmock.New() require.NoError(t, err) defer mockDB.Close() - cfg, err := peerinfodb.New() require.NoError(t, err) cfg.DbConfig.DB = mockDB @@ -219,12 +210,11 @@ func TestUpdatePeer(t *testing.T) { require.NoError(t, err) rootPubKey, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - - peer := core.PeerInfo{ + peerinfo := core.PeerInfo{ URI: "test.test", Up: true, Inbound: true, - LastError: nil, + LastError: errors.New("test"), LastErrorTime: time.Now(), Key: pubkey, Root: rootPubKey, @@ -236,17 +226,7 @@ func TestUpdatePeer(t *testing.T) { Uptime: 3600, Latency: 50.0, } - - pKey, err := x509.MarshalPKIXPublicKey(peer.Key) - require.NoError(t, err) - pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root) - var coordsBlob []byte - if peer.Coords != nil { - coordsBlob = make([]byte, len(peer.Coords)*8) - for i, coord := range peer.Coords { - binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord) - } - } + peer, err := core.NewPeerInfoDB(peerinfo) require.NoError(t, err) mock.ExpectExec(`UPDATE peer_infos SET @@ -259,23 +239,25 @@ func TestUpdatePeer(t *testing.T) { priority = \?, RXBytes = RXBytes \+ \?, TXBytes = TXBytes \+ \?, - uptime = \?, - latency = \? + uptime = uptime \+ \?, + latency = \?, + uri = \?, + key = \?, + root = \? WHERE - uri = \? AND key = \? AND root = \?`). + Id = \?`). WithArgs( - peer.Up, peer.Inbound, peer.LastError, peer.LastErrorTime, coordsBlob, peer.Port, peer.Priority, - peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency, peer.URI, pKey, pKeyRoot). + peer.Up, peer.Inbound, peer.PeerErr, peer.LastErrorTime, peer.CoordsBytes, peer.Port, peer.Priority, + peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency, peer.URI, peer.KeyBytes, peer.RootBytes, peer.Id). WillReturnResult(sqlmock.NewResult(1, 1)) - err = cfg.UpdatePeer(peer) + err = cfg.Update(peer) require.NoError(t, err) err = mock.ExpectationsWereMet() require.NoError(t, err) } -// One more test here func TestMain(t *testing.T) { peerinfodb.Name = fmt.Sprintf( "%s.%s", @@ -297,7 +279,7 @@ func TestMain(t *testing.T) { require.NoError(t, err) rootPubKey, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - peer := core.PeerInfo{ + peerinfo := core.PeerInfo{ URI: "test.test", Up: true, Inbound: true, @@ -313,14 +295,16 @@ func TestMain(t *testing.T) { Uptime: 3600, Latency: 50.0, } + peer, err := core.NewPeerInfoDB(peerinfo) + require.NoError(t, err) root2PubKey, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - peer2 := core.PeerInfo{ + peerinfo2 := core.PeerInfo{ URI: "new.test", Up: true, Inbound: true, - LastError: nil, + LastError: errors.New("test2"), LastErrorTime: time.Now(), Key: pubkey, Root: root2PubKey, @@ -332,9 +316,13 @@ func TestMain(t *testing.T) { Uptime: 3600, Latency: 50.0, } + peer2, err := core.NewPeerInfoDB(peerinfo2) + require.NoError(t, err) - peerdb.AddPeer(peer) - peerdb.AddPeer(peer2) + _, err = peerdb.Add(peer) + require.NoError(t, err) + _, err = peerdb.Add(peer2) + require.NoError(t, err) count, err := peerdb.Count() require.NoError(t, err) condition = func() bool { @@ -342,29 +330,35 @@ func TestMain(t *testing.T) { } require.Condition(t, condition, "Expected count to be 2", count) - peerdb.RemovePeer(peer) + err = peerdb.Remove(peer) + require.NoError(t, err) count, err = peerdb.Count() require.NoError(t, err) condition = func() bool { return count == 1 } + require.Condition(t, condition, "Expected count to be 1", count) peer2.Latency = 10 peer2.RXBytes = 1024 peer2.TXBytes = 1024 peer2.Port = 80 - peerdb.UpdatePeer(peer2) - peerdb.GetPeer(&peer2) + err = peerdb.Update(peer2) + require.NoError(t, err) + _, err = peerdb.Get(peer2) + require.NoError(t, err) + condition = func() bool { return peer2.Latency == 10 && peer2.RXBytes == 2048 && peer2.TXBytes == 3072 && - peer2.Port == 80 && peer2.URI == "new.test" && bytes.Equal(peer.Key, pubkey) + peer2.Port == 80 && peer2.URI == "new.test" && peer2.Key.Equal(pubkey) } + require.Condition(t, condition, "Inner exception") - peerdb.RemovePeer(peer2) + peerdb.Remove(peer2) count, err = peerdb.Count() require.NoError(t, err) diff --git a/src/db/test/pathentryinfodb_test.go b/src/db/test/pathentryinfodb_test.go new file mode 100644 index 00000000..f3c24121 --- /dev/null +++ b/src/db/test/pathentryinfodb_test.go @@ -0,0 +1,258 @@ +package db_test + +import ( + "crypto/ed25519" + "crypto/rand" + "fmt" + "strconv" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/require" + "github.com/yggdrasil-network/yggdrasil-go/src/core" + + pathentryinfodb "github.com/yggdrasil-network/yggdrasil-go/src/db/PathEntryInfoDB" +) + +func TestSelectPathEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := pathentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.PathEntryInfo{ + Key: pubkey, + Path: []uint64{0, 0, 0}, + Sequence: 100, + } + model, err := core.NewPathEntryInfoDB(entry) + require.NoError(t, err) + + rows := sqlmock.NewRows([]string{"Sequence", "Key", "Path"}). + AddRow(100, model.KeyBytes, model.PathBytes) + + mock.ExpectQuery("SELECT (.+) FROM path_entry_info WHERE Id = \\?"). + WithArgs(model.Id). + WillReturnRows(rows) + + _, err = cfg.Get(model) + t.Log(err) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) + +} + +func TestInsertPathEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := pathentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.PathEntryInfo{ + Key: pubkey, + Path: []uint64{0, 0, 0}, + Sequence: 100, + } + model, err := core.NewPathEntryInfoDB(entry) + require.NoError(t, err) + mock.ExpectExec("INSERT INTO path_entry_info"). + WithArgs( + model.KeyBytes, + model.PathBytes, + model.Sequence, + ). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _, err = cfg.Add(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestDeletePathEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := pathentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.PathEntryInfo{ + Key: pubkey, + Path: []uint64{0, 0, 0}, + Sequence: 100, + } + model, err := core.NewPathEntryInfoDB(entry) + require.NoError(t, err) + mock.ExpectExec("DELETE FROM path_entry_info WHERE Id = \\?"). + WithArgs( + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Remove(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestUpdatePathEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := pathentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.PathEntryInfo{ + Key: pubkey, + Path: []uint64{0, 0, 0}, + Sequence: 100, + } + model, err := core.NewPathEntryInfoDB(entry) + require.NoError(t, err) + mock.ExpectExec(` + UPDATE path_entry_info + SET + Sequence = \?, + Key = \?, + Path = \? + WHERE + Id = \?`). + WithArgs( + model.Sequence, + model.KeyBytes, + model.PathBytes, + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Update(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestMainPathEntryInfo(t *testing.T) { + pathentryinfodb.Name = fmt.Sprintf( + "%s.%s", + pathentryinfodb.Name, + strconv.Itoa(int(time.Now().Unix())), + ) + pathentryinfodb, err := pathentryinfodb.New() + require.NoError(t, err) + + pathentryinfodb.DbConfig.OpenDb() + isOpened := pathentryinfodb.DbConfig.DBIsOpened() + condition := func() bool { + return isOpened + } + require.Condition(t, condition, "Expected db is opened", isOpened) + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + secondPubKey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.PathEntryInfo{ + Key: pubkey, + Path: []uint64{0, 0, 0}, + Sequence: 100, + } + model, err := core.NewPathEntryInfoDB(entry) + require.NoError(t, err) + + secondEntry := core.PathEntryInfo{ + Key: secondPubKey, + Path: []uint64{0, 0, 0}, + Sequence: 100, + } + secondModel, err := core.NewPathEntryInfoDB(secondEntry) + require.NoError(t, err) + + _, err = pathentryinfodb.Add(model) + require.NoError(t, err) + _, err = pathentryinfodb.Add(secondModel) + require.NoError(t, err) + count, err := pathentryinfodb.Count() + require.NoError(t, err) + condition = func() bool { + return count == 2 + } + require.Condition(t, condition, "Expected count to be 2", count) + + err = pathentryinfodb.Remove(secondModel) + require.NoError(t, err) + count, err = pathentryinfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 1 + } + require.Condition(t, condition, "Expected count to be 1", count) + + model.Sequence = 10 + err = pathentryinfodb.Update(model) + require.NoError(t, err) + _, err = pathentryinfodb.Get(model) + require.NoError(t, err) + + err = pathentryinfodb.Update(secondModel) + require.NoError(t, err) + + condition = func() bool { + return model.Sequence == 10 + } + require.Condition(t, condition, "Inner exception") + + pathentryinfodb.Remove(model) + count, err = pathentryinfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 0 + } + require.Condition(t, condition, "Expected count to be 0", count) + + err = pathentryinfodb.DbConfig.CloseDb() + isOpened = pathentryinfodb.DbConfig.DBIsOpened() + require.NoError(t, err) + + condition = func() bool { + return !isOpened + } + require.Condition(t, condition, "Expected db is not opened", isOpened) + + err = pathentryinfodb.DbConfig.DeleteDb() + require.NoError(t, err) + + isExist := pathentryinfodb.DbConfig.DBIsExist() + condition = func() bool { + return !isExist + } + require.Condition(t, condition, "Expected db is not exist", isExist) +} diff --git a/src/db/test/selfinfodb_test.go b/src/db/test/selfinfodb_test.go new file mode 100644 index 00000000..0b3e63bb --- /dev/null +++ b/src/db/test/selfinfodb_test.go @@ -0,0 +1,246 @@ +package db_test + +import ( + "crypto/ed25519" + "crypto/rand" + "fmt" + "strconv" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/require" + "github.com/yggdrasil-network/yggdrasil-go/src/core" + + selfinfodb "github.com/yggdrasil-network/yggdrasil-go/src/db/SelfInfoDB" +) + +func TestSelectSelfInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := selfinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + selfinfo := core.SelfInfo{ + Key: pubkey, + } + model, err := core.NewSelfInfoDB(selfinfo) + require.NoError(t, err) + + rows := sqlmock.NewRows([]string{"RoutingEntries", "Key"}). + AddRow(100, model.KeyBytes) + + mock.ExpectQuery("SELECT (.+) FROM self_info WHERE Id = \\?"). + WithArgs(model.Id). + WillReturnRows(rows) + + _, err = cfg.Get(model) + t.Log(err) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) + +} + +func TestInsertSelfInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := selfinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + selfinfo := core.SelfInfo{ + Key: pubkey, + } + model, err := core.NewSelfInfoDB(selfinfo) + require.NoError(t, err) + mock.ExpectExec("INSERT OR REPLACE INTO self_info"). + WithArgs( + model.KeyBytes, + model.RoutingEntries, + ). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _, err = cfg.Add(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestDeleteSelfInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := selfinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + selfinfo := core.SelfInfo{ + Key: pubkey, + } + model, err := core.NewSelfInfoDB(selfinfo) + require.NoError(t, err) + mock.ExpectExec("DELETE FROM self_info WHERE Id = \\?"). + WithArgs( + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Remove(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestUpdateSelfInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := selfinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + selfinfo := core.SelfInfo{ + Key: pubkey, + RoutingEntries: 100, + } + model, err := core.NewSelfInfoDB(selfinfo) + require.NoError(t, err) + mock.ExpectExec(` + UPDATE self_info + SET + RoutingEntries = \?, + Key = \? + WHERE + Id = \?`). + WithArgs( + model.RoutingEntries, + model.KeyBytes, + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Update(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestMainSelfInfo(t *testing.T) { + selfinfodb.Name = fmt.Sprintf( + "%s.%s", + selfinfodb.Name, + strconv.Itoa(int(time.Now().Unix())), + ) + selfinfodb, err := selfinfodb.New() + require.NoError(t, err) + + selfinfodb.DbConfig.OpenDb() + isOpened := selfinfodb.DbConfig.DBIsOpened() + condition := func() bool { + return isOpened + } + require.Condition(t, condition, "Expected db is opened", isOpened) + + firstKey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + secondKey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + firstSelfinfo := core.SelfInfo{ + Key: firstKey, + RoutingEntries: 100, + } + firstModel, err := core.NewSelfInfoDB(firstSelfinfo) + require.NoError(t, err) + + secondSelfinfo := core.SelfInfo{ + Key: secondKey, + RoutingEntries: 200, + } + secondModel, err := core.NewSelfInfoDB(secondSelfinfo) + require.NoError(t, err) + + _, err = selfinfodb.Add(firstModel) + require.NoError(t, err) + _, err = selfinfodb.Add(secondModel) + require.NoError(t, err) + count, err := selfinfodb.Count() + require.NoError(t, err) + condition = func() bool { + return count == 2 + } + require.Condition(t, condition, "Expected count to be 2", count) + + err = selfinfodb.Remove(secondModel) + require.NoError(t, err) + count, err = selfinfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 1 + } + require.Condition(t, condition, "Expected count to be 1", count) + + firstModel.RoutingEntries = 10 + err = selfinfodb.Update(firstModel) + require.NoError(t, err) + _, err = selfinfodb.Get(firstModel) + require.NoError(t, err) + + err = selfinfodb.Update(secondModel) + require.NoError(t, err) + + condition = func() bool { + return firstModel.RoutingEntries == 10 + } + require.Condition(t, condition, "Inner exception") + + selfinfodb.Remove(firstModel) + count, err = selfinfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 0 + } + require.Condition(t, condition, "Expected count to be 0", count) + + err = selfinfodb.DbConfig.CloseDb() + isOpened = selfinfodb.DbConfig.DBIsOpened() + require.NoError(t, err) + + condition = func() bool { + return !isOpened + } + require.Condition(t, condition, "Expected db is not opened", isOpened) + + err = selfinfodb.DbConfig.DeleteDb() + require.NoError(t, err) + + isExist := selfinfodb.DbConfig.DBIsExist() + condition = func() bool { + return !isExist + } + require.Condition(t, condition, "Expected db is not exist", isExist) +} diff --git a/src/db/test/sessioninfodb_test.go b/src/db/test/sessioninfodb_test.go new file mode 100644 index 00000000..4914512a --- /dev/null +++ b/src/db/test/sessioninfodb_test.go @@ -0,0 +1,271 @@ +package db_test + +import ( + "crypto/ed25519" + "crypto/rand" + "fmt" + "strconv" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/require" + "github.com/yggdrasil-network/yggdrasil-go/src/core" + + sessioninfodb "github.com/yggdrasil-network/yggdrasil-go/src/db/SessionInfoDB" +) + +func TestSelectSessionInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := sessioninfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.SessionInfo{ + Key: pubkey, + RXBytes: 10, + TXBytes: 10, + Uptime: time.Hour, + } + model, err := core.NewSessionInfoDB(entry) + require.NoError(t, err) + + rows := sqlmock.NewRows([]string{"RXBytes", "TXBytes", "Duration", "Key"}). + AddRow(100, 200, 100, model.KeyBytes) + + mock.ExpectQuery("SELECT (.+) FROM session_info WHERE Id = \\?"). + WithArgs(model.Id). + WillReturnRows(rows) + + _, err = cfg.Get(model) + t.Log(err) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) + +} + +func TestInsertSessionInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := sessioninfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.SessionInfo{ + Key: pubkey, + RXBytes: 10, + TXBytes: 10, + Uptime: time.Hour, + } + model, err := core.NewSessionInfoDB(entry) + require.NoError(t, err) + + mock.ExpectExec("INSERT INTO session_info"). + WithArgs( + model.KeyBytes, + model.RXBytes, + model.TXBytes, + model.Uptime, + ). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _, err = cfg.Add(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestDeleteSessionInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := sessioninfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.SessionInfo{ + Key: pubkey, + RXBytes: 10, + TXBytes: 10, + Uptime: time.Hour, + } + model, err := core.NewSessionInfoDB(entry) + require.NoError(t, err) + mock.ExpectExec("DELETE FROM session_info WHERE Id = \\?"). + WithArgs( + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Remove(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestUpdateSessionInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := sessioninfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.SessionInfo{ + Key: pubkey, + RXBytes: 10, + TXBytes: 10, + Uptime: time.Hour, + } + model, err := core.NewSessionInfoDB(entry) + require.NoError(t, err) + mock.ExpectExec(` + UPDATE session_info + SET + RXBytes = RXBytes \+ \?, + TXBytes = TXBytes \+ \?, + Duration = Duration \+ \?, + Key = \? + WHERE + Id = \?`). + WithArgs( + model.RXBytes, + model.TXBytes, + model.Uptime, + model.KeyBytes, + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Update(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestMainSessionInfo(t *testing.T) { + sessioninfodb.Name = fmt.Sprintf( + "%s.%s", + sessioninfodb.Name, + strconv.Itoa(int(time.Now().Unix())), + ) + sessioninfodb, err := sessioninfodb.New() + require.NoError(t, err) + + sessioninfodb.DbConfig.OpenDb() + isOpened := sessioninfodb.DbConfig.DBIsOpened() + condition := func() bool { + return isOpened + } + require.Condition(t, condition, "Expected db is opened", isOpened) + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + secondPubKey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.SessionInfo{ + Key: pubkey, + RXBytes: 10, + TXBytes: 10, + Uptime: time.Hour, + } + model, err := core.NewSessionInfoDB(entry) + require.NoError(t, err) + + secondEntry := core.SessionInfo{ + Key: secondPubKey, + RXBytes: 10, + TXBytes: 10, + Uptime: time.Hour, + } + secondModel, err := core.NewSessionInfoDB(secondEntry) + require.NoError(t, err) + + _, err = sessioninfodb.Add(model) + require.NoError(t, err) + _, err = sessioninfodb.Add(secondModel) + require.NoError(t, err) + count, err := sessioninfodb.Count() + require.NoError(t, err) + condition = func() bool { + return count == 2 + } + require.Condition(t, condition, "Expected count to be 2", count) + + err = sessioninfodb.Remove(secondModel) + require.NoError(t, err) + count, err = sessioninfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 1 + } + require.Condition(t, condition, "Expected count to be 1", count) + + model.TXBytes = 100 + model.RXBytes = 150 + model.Uptime = 100 + err = sessioninfodb.Update(model) + require.NoError(t, err) + _, err = sessioninfodb.Get(model) + require.NoError(t, err) + + err = sessioninfodb.Update(secondModel) + require.NoError(t, err) + + condition = func() bool { + return model.RXBytes == 160 && + model.TXBytes == 110 && model.Uptime == 3600000000100 + } + require.Condition(t, condition, "Inner exception") + + sessioninfodb.Remove(model) + count, err = sessioninfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 0 + } + require.Condition(t, condition, "Expected count to be 0", count) + + err = sessioninfodb.DbConfig.CloseDb() + isOpened = sessioninfodb.DbConfig.DBIsOpened() + require.NoError(t, err) + + condition = func() bool { + return !isOpened + } + require.Condition(t, condition, "Expected db is not opened", isOpened) + + err = sessioninfodb.DbConfig.DeleteDb() + require.NoError(t, err) + + isExist := sessioninfodb.DbConfig.DBIsExist() + condition = func() bool { + return !isExist + } + require.Condition(t, condition, "Expected db is not exist", isExist) +} diff --git a/src/db/test/treeentryinfodb_test.go b/src/db/test/treeentryinfodb_test.go new file mode 100644 index 00000000..d5ded78e --- /dev/null +++ b/src/db/test/treeentryinfodb_test.go @@ -0,0 +1,259 @@ +package db_test + +import ( + "crypto/ed25519" + "crypto/rand" + "fmt" + "strconv" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/require" + "github.com/yggdrasil-network/yggdrasil-go/src/core" + + treeentryinfodb "github.com/yggdrasil-network/yggdrasil-go/src/db/TreeEntryInfoDB" +) + +func TestSelectTreeEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := treeentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.TreeEntryInfo{ + Key: pubkey, + Parent: pubkey, + Sequence: 10, + } + model, err := core.NewTreeEntryInfoDB(entry) + require.NoError(t, err) + + rows := sqlmock.NewRows([]string{"Sequence", "Key", "Parent"}). + AddRow(100, model.KeyBytes, model.ParentBytes) + + mock.ExpectQuery("SELECT (.+) FROM tree_entry_info WHERE Id = \\?"). + WithArgs(model.Id). + WillReturnRows(rows) + + _, err = cfg.Get(model) + t.Log(err) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) + +} + +func TestInsertTreeEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := treeentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.TreeEntryInfo{ + Key: pubkey, + Parent: pubkey, + Sequence: 10, + } + model, err := core.NewTreeEntryInfoDB(entry) + require.NoError(t, err) + + mock.ExpectExec("INSERT INTO tree_entry_info"). + WithArgs( + model.KeyBytes, + model.ParentBytes, + model.Sequence, + ). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _, err = cfg.Add(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestDeleteTreeEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := treeentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.TreeEntryInfo{ + Key: pubkey, + Parent: pubkey, + Sequence: 10, + } + model, err := core.NewTreeEntryInfoDB(entry) + require.NoError(t, err) + mock.ExpectExec("DELETE FROM tree_entry_info WHERE Id = \\?"). + WithArgs( + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Remove(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestUpdateTreeEntryInfo(t *testing.T) { + mockDB, mock, err := sqlmock.New() + require.NoError(t, err) + defer mockDB.Close() + + cfg, err := treeentryinfodb.New() + require.NoError(t, err) + cfg.DbConfig.DB = mockDB + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.TreeEntryInfo{ + Key: pubkey, + Parent: pubkey, + Sequence: 10, + } + model, err := core.NewTreeEntryInfoDB(entry) + require.NoError(t, err) + mock.ExpectExec(` + UPDATE tree_entry_info + SET + Sequence = \?, + Key = \?, + Parent = \? + WHERE + Id = \?`). + WithArgs( + model.Sequence, + model.KeyBytes, + model.ParentBytes, + model.Id, + ).WillReturnResult(sqlmock.NewResult(1, 1)) + + err = cfg.Update(model) + require.NoError(t, err) + + err = mock.ExpectationsWereMet() + require.NoError(t, err) +} + +func TestMainTreeEntryInfo(t *testing.T) { + treeentryinfodb.Name = fmt.Sprintf( + "%s.%s", + treeentryinfodb.Name, + strconv.Itoa(int(time.Now().Unix())), + ) + treeentryinfodb, err := treeentryinfodb.New() + require.NoError(t, err) + + treeentryinfodb.DbConfig.OpenDb() + isOpened := treeentryinfodb.DbConfig.DBIsOpened() + condition := func() bool { + return isOpened + } + require.Condition(t, condition, "Expected db is opened", isOpened) + + pubkey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + secondPubKey, _, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + entry := core.TreeEntryInfo{ + Key: pubkey, + Parent: pubkey, + Sequence: 10, + } + model, err := core.NewTreeEntryInfoDB(entry) + require.NoError(t, err) + + secondEntry := core.TreeEntryInfo{ + Key: secondPubKey, + Parent: secondPubKey, + Sequence: 20, + } + secondModel, err := core.NewTreeEntryInfoDB(secondEntry) + require.NoError(t, err) + + _, err = treeentryinfodb.Add(model) + require.NoError(t, err) + _, err = treeentryinfodb.Add(secondModel) + require.NoError(t, err) + count, err := treeentryinfodb.Count() + require.NoError(t, err) + condition = func() bool { + return count == 2 + } + require.Condition(t, condition, "Expected count to be 2", count) + + err = treeentryinfodb.Remove(secondModel) + require.NoError(t, err) + count, err = treeentryinfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 1 + } + require.Condition(t, condition, "Expected count to be 1", count) + + model.Sequence = 100 + err = treeentryinfodb.Update(model) + require.NoError(t, err) + _, err = treeentryinfodb.Get(model) + require.NoError(t, err) + + err = treeentryinfodb.Update(secondModel) + require.NoError(t, err) + + condition = func() bool { + return model.Sequence == 100 + } + require.Condition(t, condition, "Inner exception") + + treeentryinfodb.Remove(model) + count, err = treeentryinfodb.Count() + require.NoError(t, err) + + condition = func() bool { + return count == 0 + } + require.Condition(t, condition, "Expected count to be 0", count) + + err = treeentryinfodb.DbConfig.CloseDb() + isOpened = treeentryinfodb.DbConfig.DBIsOpened() + require.NoError(t, err) + + condition = func() bool { + return !isOpened + } + require.Condition(t, condition, "Expected db is not opened", isOpened) + + err = treeentryinfodb.DbConfig.DeleteDb() + require.NoError(t, err) + + isExist := treeentryinfodb.DbConfig.DBIsExist() + condition = func() bool { + return !isExist + } + require.Condition(t, condition, "Expected db is not exist", isExist) +}