Commit e8d006da authored by Kevin Di Lallo's avatar Kevin Di Lallo
Browse files

postgis package implementation updates

parent d9a59afb
Loading
Loading
Loading
Loading
+440 −30
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import (
	"strings"

	log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger"

	"github.com/lib/pq"
	_ "github.com/lib/pq"
)

@@ -34,6 +36,48 @@ const (
)
const dbMaxRetryCount int = 2

const (
	PathModeLoop    = "LOOP"
	PathModeReverse = "REVERSE"
	PathModeOnce    = "ONCE"
)

const (
	UeTable      = "ue"
	PoaTable     = "poa"
	ComputeTable = "compute"
)

type Ue struct {
	Id            string
	Name          string
	Position      string
	Path          string
	PathMode      string
	PathVelocity  float32
	PathLength    float32
	PathIncrement float32
	PathFraction  float32
	Poa           string
	PoaDistance   float32
	PoaInRange    []string
}

type Poa struct {
	Id       string
	Name     string
	SubType  string
	Position string
	Radius   float32
}

type Compute struct {
	Id       string
	Name     string
	SubType  string
	Position string
}

// Connector - Implements a Postgis SQL DB connector
type Connector struct {
	name      string
@@ -78,7 +122,7 @@ func NewConnector(name, namespace, user, pwd, host, port string) (pc *Connector,

	// Ignore DB creation error in case it already exists.
	// Failure will occur at DB connection if DB was not successfully created.
	_ = pc.DbCreate(pc.dbName)
	_ = pc.CreateDb(pc.dbName)

	// Close connection to postgis DB
	pc.db.Close()
@@ -128,8 +172,8 @@ func (pc *Connector) connectDB(dbName, user, pwd, host, port string) (db *sql.DB
	return db, nil
}

// DbCreate -- Create new DB with provided name
func (pc *Connector) DbCreate(name string) (err error) {
// CreateDb -- Create new DB with provided name
func (pc *Connector) CreateDb(name string) (err error) {
	_, err = pc.db.Exec("CREATE DATABASE " + name)
	if err != nil {
		log.Error(err.Error())
@@ -140,37 +184,403 @@ func (pc *Connector) DbCreate(name string) (err error) {
	return nil
}

// func DbDeleteTable(tableName string) (err error) {
// 	_, err = db.Exec("DROP TABLE IF EXISTS " + tableName)
// 	if err != nil {
// 		log.Error(err.Error())
// 		return err
// 	}
// 	log.Info("Deleted table: " + tableName)
// 	return nil
// }
func (pc *Connector) CreateTables() (err error) {
	_, err = pc.db.Exec("CREATE EXTENSION IF NOT EXISTS postgis")
	if err != nil {
		log.Error(err.Error())
		return err
	}

// func DbCreatePoaTable(tableName string) (err error) {
// 	_, err = db.Exec("CREATE EXTENSION IF NOT EXISTS postgis")
// 	if err != nil {
// 		log.Error(err.Error())
// 		return err
// 	}
	// UE Table
	_, err = pc.db.Exec(`CREATE TABLE ` + UeTable + ` (
		id 				varchar(36) 			NOT NULL PRIMARY KEY,
		name 			varchar(100) 			NOT NULL UNIQUE,
		position		geometry(POINT,4326)	NOT NULL,
		path 			geometry(LINESTRING,4326),
		path_mode       varchar(20)           	NOT NULL DEFAULT 'LOOP',
		path_velocity   decimal(10,3)         	NOT NULL DEFAULT '0.000',
		path_length     decimal(10,3)         	NOT NULL DEFAULT '0.000',
		path_increment  decimal(10,3)         	NOT NULL DEFAULT '0.000',
		path_fraction   decimal(10,3)         	NOT NULL DEFAULT '0.000',
		poa				varchar(100)			NOT NULL DEFAULT '',
		poa_distance    decimal(10,6)         	NOT NULL DEFAULT '0.000000',
		poa_in_range	varchar(100)[]			NOT NULL DEFAULT array[]::varchar[],
		start_time		timestamptz 			NOT NULL DEFAULT now()
	)`)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	log.Info("Created UE table: ", UeTable)

	// POA Table
	_, err = pc.db.Exec(`CREATE TABLE ` + PoaTable + ` (
		id 				varchar(36) 			NOT NULL PRIMARY KEY,
		name 			varchar(100) 			NOT NULL UNIQUE,
		type 			varchar(20)				NOT NULL DEFAULT '',
		radius			decimal(10,1) 			NOT NULL DEFAULT '0.0',
		position		geometry(POINT,4326)	NOT NULL
	)`)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	log.Info("Created POA table: ", PoaTable)

	// Compute Table
	_, err = pc.db.Exec(`CREATE TABLE ` + ComputeTable + ` (
		id 				varchar(36) 			NOT NULL PRIMARY KEY,
		name 			varchar(100) 			NOT NULL UNIQUE,
		type 			varchar(20)				NOT NULL DEFAULT '',
		position		geometry(POINT,4326)	NOT NULL
	)`)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	log.Info("Created Edge table: ", ComputeTable)

// 	_, err = db.Exec(`CREATE TABLE ` + tableName + ` (
// 		id 			varchar(36) 	NOT NULL PRIMARY KEY,
// 		name 		varchar(100) 	NOT NULL UNIQUE,
// 		lat			decimal(10,6) 	NOT NULL DEFAULT '0.000000',
// 		long		decimal(10,6) 	NOT NULL DEFAULT '0.000000',
// 		alt 		decimal(10,1) 	NOT NULL DEFAULT '0.0',
// 		radius		decimal(10,1) 	NOT NULL DEFAULT '0.0',
// 		position	geometry(POINTZ,4326)
// 		)`)
	return nil
}

func (pc *Connector) DeleteTable(tableName string) (err error) {
	_, err = pc.db.Exec("DROP TABLE IF EXISTS " + tableName)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	log.Info("Deleted table: " + tableName)
	return nil
}

// func (pc *Connector) AssetExists(name string, assetType AssetType) (exists bool) {
// 	count := 0

// 	rows, err := pc.db.Query(`select count(*) from `+getTableName(assetType)+` where name = ($1)`, name)
// 	if err != nil {
// 		log.Error(err.Error())
// 		return err
// 		return false
// 	}
// 	defer rows.Close()

// 	log.Info("Created table: ", tableName)
// 	return nil
// 	// Scan results
// 	for rows.Next() {
// 		err = rows.Scan(&count)
// 	}
// 	exists = (count != 0)
// 	return exists
// }

// CreateUe - Create new UE
func (pc *Connector) CreateUe(id string, name string, position string, path string, mode string, velocity float32) (err error) {
	// Validate input
	if id == "" {
		return errors.New("Missing ID")
	}
	if name == "" {
		return errors.New("Missing Name")
	}
	if position == "" {
		return errors.New("Missing Position")
	}

	if path != "" {
		// Validate Path parameters
		if mode == "" {
			return errors.New("Missing Path Mode")
		}

		// Create UE entry with path
		query := `INSERT INTO ` + UeTable + ` (id, name, position, path, path_mode, path_velocity)
			VALUES ($1, $2, ST_GeomFromGeoJSON('` + position + `'), ST_GeomFromGeoJSON('` + path + `'), $3, $4)`
		_, err = pc.db.Exec(query, id, name, mode, velocity)
		if err != nil {
			log.Error(err.Error())
			return err
		}

		// Calculate UE path length & increment
		err = pc.refreshUePath(name)
		if err != nil {
			log.Error(err.Error())
			return err
		}
	} else {
		// Create UE entry without path
		query := `INSERT INTO ` + UeTable + ` (id, name, position)
			VALUES ($1, $2, ST_GeomFromGeoJSON('` + position + `'))`
		_, err = pc.db.Exec(query, id, name)
		if err != nil {
			log.Error(err.Error())
			return err
		}
	}

	// Refresh UE POA information
	err = pc.refreshUePoa(name)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	return nil
}

// CreatePoa - Create new POA
func (pc *Connector) CreatePoa(id string, name string, subType string, position string, radius float32) (err error) {
	// Validate input
	if id == "" {
		return errors.New("Missing ID")
	}
	if name == "" {
		return errors.New("Missing Name")
	}
	if subType == "" {
		return errors.New("Missing Type")
	}
	if position == "" {
		return errors.New("Missing Position")
	}

	// Create POA entry
	query := `INSERT INTO ` + PoaTable + ` (id, name, type, position, radius)
		VALUES ($1, $2, $3, ST_GeomFromGeoJSON('` + position + `'), $4)`
	_, err = pc.db.Exec(query, id, name, subType, radius)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

// CreateCompute - Create new Compute
func (pc *Connector) CreateCompute(id string, name string, subType string, position string) (err error) {
	// Validate input
	if id == "" {
		return errors.New("Missing ID")
	}
	if name == "" {
		return errors.New("Missing Name")
	}
	if subType == "" {
		return errors.New("Missing Type")
	}
	if position == "" {
		return errors.New("Missing Position")
	}

	// Create Compute entry
	query := `INSERT INTO ` + ComputeTable + ` (id, name, type, position)
		VALUES ($1, $2, $3, ST_GeomFromGeoJSON('` + position + `'))`
	_, err = pc.db.Exec(query, id, name, subType)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

// GetUe - Get UE information
func (pc *Connector) GetUe(name string) (ue *Ue, err error) {
	// Validate input
	if name == "" {
		err = errors.New("Missing Name")
		return nil, err
	}

	// Get UE entry
	var rows *sql.Rows
	rows, err = pc.db.Query(`
		SELECT id, name, ST_AsGeoJSON(position), ST_AsGeoJSON(path),
			path_mode, path_velocity, path_length, path_increment, path_fraction,
			poa, poa_distance, poa_in_range
		FROM `+UeTable+`
		WHERE name = ($1)`, name)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	defer rows.Close()

	ue = new(Ue)
	path := new(string)

	// Scan result
	rows.Next()
	err = rows.Scan(&ue.Id, &ue.Name, &ue.Position, &path,
		&ue.PathMode, &ue.PathVelocity, &ue.PathLength, &ue.PathIncrement, &ue.PathFraction,
		&ue.Poa, &ue.PoaDistance, pq.Array(&ue.PoaInRange))
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	err = rows.Err()
	if err != nil {
		log.Error(err)
	}

	// Store path
	if path != nil {
		ue.Path = *path
	}

	return ue, nil
}

// GetPoa - Get POA information
func (pc *Connector) GetPoa(name string) (poa *Poa, err error) {
	// Validate input
	if name == "" {
		err = errors.New("Missing Name")
		return nil, err
	}

	// Get Poa entry
	var rows *sql.Rows
	rows, err = pc.db.Query(`
		SELECT id, name, type, ST_AsGeoJSON(position), radius
		FROM `+PoaTable+`
		WHERE name = ($1)`, name)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	defer rows.Close()

	poa = new(Poa)

	// Scan result
	rows.Next()
	err = rows.Scan(&poa.Id, &poa.Name, &poa.SubType, &poa.Position, &poa.Radius)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	err = rows.Err()
	if err != nil {
		log.Error(err)
	}

	return poa, nil
}

// GetCompute - Get Compute information
func (pc *Connector) GetCompute(name string) (compute *Compute, err error) {
	// Validate input
	if name == "" {
		err = errors.New("Missing Name")
		return nil, err
	}

	// Get Compute entry
	var rows *sql.Rows
	rows, err = pc.db.Query(`
		SELECT id, name, type, ST_AsGeoJSON(position)
		FROM `+ComputeTable+`
		WHERE name = ($1)`, name)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	defer rows.Close()

	compute = new(Compute)

	// Scan result
	rows.Next()
	err = rows.Scan(&compute.Id, &compute.Name, &compute.SubType, &compute.Position)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	err = rows.Err()
	if err != nil {
		log.Error(err)
	}

	return compute, nil
}

// Recalculate UE path length & increment
func (pc *Connector) refreshUePath(name string) (err error) {
	query := `UPDATE ` + UeTable + `
		SET path_length = selected_ue.path_len,
			path_increment = selected_ue.path_velocity / selected_ue.path_len,
			path_fraction = 0
		FROM (
			SELECT ST_Length(path::geography) AS path_len, path_velocity
			FROM ` + UeTable + `
			WHERE name = ($1)
		) AS selected_ue
		WHERE name = ($1)`
	_, err = pc.db.Exec(query, name)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

// Recalculate nearest POA & POAs in range for provided UE
func (pc *Connector) refreshUePoa(name string) (err error) {

	// Calculate distance from provided UE to each POA and check if within range
	var rows *sql.Rows
	rows, err = pc.db.Query(`
		SELECT ue.name AS ue, poa.name as poa,
			ST_Distance(ue.position::geography, poa.position::geography) AS dist,
			ST_DWithin(ue.position::geography, poa.position::geography, poa.radius) AS in_range
		FROM `+UeTable+`, `+PoaTable+`
		WHERE ue.name = ($1)`, name)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	defer rows.Close()

	nearestPoa := ""
	distance := float32(0)
	poaInRange := []string{}

	// Scan results
	for rows.Next() {
		ue := ""
		poa := ""
		dist := float32(0)
		inRange := false

		err := rows.Scan(&ue, &poa, &dist, &inRange)
		if err != nil {
			log.Error(err.Error())
			return err
		}

		// Add POA if in range
		if inRange {
			poaInRange = append(poaInRange, poa)
		}

		// Set nearest POA
		if nearestPoa == "" || dist < distance {
			nearestPoa = poa
			distance = dist
		}
	}
	err = rows.Err()
	if err != nil {
		log.Error(err)
	}

	// Update POA entries fro UE
	query := `UPDATE ` + UeTable + `
		SET poa = $2,
			poa_distance = $3,
			poa_in_range = $4
		WHERE name = ($1)`
	_, err = pc.db.Exec(query, name, nearestPoa, distance, pq.Array(&poaInRange))
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}
+393 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package postgisdb

import (
	"fmt"
	"sort"
	"testing"

	log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger"
@@ -30,12 +31,58 @@ const (
	pcDBPwd     = "pwd"
	pcDBHost    = "localhost"
	pcDBPort    = "30432"

	ue1Id       = "ue1-id"
	ue1Name     = "ue1"
	ue1Velocity = 5.0

	ue2Id       = "ue2-id"
	ue2Name     = "ue2"
	ue2Velocity = 0.0

	ue3Id       = "ue3-id"
	ue3Name     = "ue3"
	ue3Velocity = 25.0

	poa1Id     = "poa1-id"
	poa1Name   = "poa1"
	poa1Type   = "POA-CELLULAR"
	poa1Loc    = "[7.418494,43.733449]"
	poa1Radius = 160.0

	poa2Id     = "poa2-id"
	poa2Name   = "poa2"
	poa2Type   = "POA"
	poa2Loc    = "[7.421626,43.736983]"
	poa2Radius = 350.0

	poa3Id     = "poa3-id"
	poa3Name   = "poa3"
	poa3Type   = "POA-CELLULAR"
	poa3Loc    = "[7.422239,43.732972]"
	poa3Radius = 220.0

	compute1Id   = "compute1-id"
	compute1Name = "compute1"
	compute1Type = "EDGE"
	compute2Id   = "compute2-id"
	compute2Name = "compute2"
	compute2Type = "FOG"
	compute3Id   = "compute3-id"
	compute3Name = "compute3"
	compute3Type = "EDGE"

	point1 = "[7.418522,43.734198]"
	point2 = "[7.421501,43.736978]"
	point3 = "[7.422441,43.732285]"
	point4 = "[7.418944,43.732591]"
)

func TestPostgisConnectorNew(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

	// Invalid Connector
	fmt.Println("Invalid Postgis Connector")
	pc, err := NewConnector("", pcNamespace, pcDBUser, pcDBPwd, pcDBHost, pcDBPort)
	if err == nil || pc != nil {
@@ -54,11 +101,357 @@ func TestPostgisConnectorNew(t *testing.T) {
		t.Fatalf("DB connection should have failed")
	}

	// Valid Connector
	fmt.Println("Create valid Postgis Connector")
	pc, err = NewConnector(pcName, pcNamespace, pcDBUser, pcDBPwd, pcDBHost, pcDBPort)
	if err != nil || pc == nil {
		t.Fatalf("Unable to create postgis Connector")
	}

	// Cleanup
	_ = pc.DeleteTable(UeTable)
	_ = pc.DeleteTable(PoaTable)
	_ = pc.DeleteTable(ComputeTable)

	// Create tables
	fmt.Println("Create Tables")
	err = pc.CreateTables()
	if err != nil {
		t.Fatalf("Unable to create tables")
	}

	// Add Invalid UE
	fmt.Println("Create Invalid UEs")
	ueLoc := "{\"type\":\"Point\",\"coordinates\":[0,0]}"
	uePath := "{\"type\":\"LineString\",\"coordinates\":[[0,0],[1,1]]}"
	ueVelocity := float32(0)
	err = pc.CreateUe("", ue1Name, ueLoc, uePath, PathModeLoop, ueVelocity)
	if err == nil {
		t.Fatalf("UE creation should have failed")
	}
	err = pc.CreateUe(ue1Id, "", ueLoc, uePath, PathModeLoop, ueVelocity)
	if err == nil {
		t.Fatalf("UE creation should have failed")
	}
	err = pc.CreateUe(ue1Id, ue1Name, "", uePath, PathModeLoop, ueVelocity)
	if err == nil {
		t.Fatalf("UE creation should have failed")
	}
	ueLocInvalid := "{\"type\":\"Invalid\",\"coordinates\":[0,0]}"
	err = pc.CreateUe(ue1Id, ue1Name, ueLocInvalid, uePath, PathModeLoop, ueVelocity)
	if err == nil {
		t.Fatalf("UE creation should have failed")
	}
	ueLocInvalid = "{\"type\":\"Point\",\"coordinates\":[]}"
	err = pc.CreateUe(ue1Id, ue1Name, ueLocInvalid, uePath, PathModeLoop, ueVelocity)
	if err == nil {
		t.Fatalf("UE creation should have failed")
	}
	uePathInvalid := "{\"type\":\"Invalid\",\"coordinates\":[[0,0],[1,1]]}"
	err = pc.CreateUe(ue1Id, ue1Name, ueLoc, uePathInvalid, PathModeLoop, ueVelocity)
	if err == nil {
		t.Fatalf("UE creation should have failed")
	}
	uePathInvalid = "{\"type\":\"LineString\",\"coordinates\":[[0,0],[]]}"
	err = pc.CreateUe(ue1Id, ue1Name, ueLoc, uePathInvalid, PathModeLoop, ueVelocity)
	if err == nil {
		t.Fatalf("UE creation should have failed")
	}

	// Make sure POAs don't exist
	fmt.Println("Verify no POAs present")
	poa, err := pc.GetPoa(poa1Name)
	if err == nil || poa != nil {
		t.Fatalf("POA Get should have failed")
	}
	poa, err = pc.GetPoa(poa2Name)
	if err == nil || poa != nil {
		t.Fatalf("POA Get should have failed")
	}
	poa, err = pc.GetPoa(poa3Name)
	if err == nil || poa != nil {
		t.Fatalf("POA Get should have failed")
	}

	// Make sure UEs don't exist
	fmt.Println("Verify no UEs present")
	ue, err := pc.GetUe(ue1Name)
	if err == nil || ue != nil {
		t.Fatalf("UE Get should have failed")
	}
	ue, err = pc.GetUe(ue2Name)
	if err == nil || ue != nil {
		t.Fatalf("UE Get should have failed")
	}
	ue, err = pc.GetUe(ue3Name)
	if err == nil || ue != nil {
		t.Fatalf("UE Get should have failed")
	}

	// Make sure Computes don't exist
	fmt.Println("Verify no Computes present")
	compute, err := pc.GetCompute(compute1Name)
	if err == nil || compute != nil {
		t.Fatalf("Computes Get should have failed")
	}
	compute, err = pc.GetCompute(compute2Name)
	if err == nil || compute != nil {
		t.Fatalf("Computes Get should have failed")
	}
	compute, err = pc.GetCompute(compute3Name)
	if err == nil || compute != nil {
		t.Fatalf("Computes Get should have failed")
	}

	// Add POA & Validate successfully added
	fmt.Println("Add POAs & Validate successfully added")
	poaLoc := "{\"type\":\"Point\",\"coordinates\":" + poa1Loc + "}"
	err = pc.CreatePoa(poa1Id, poa1Name, poa1Type, poaLoc, poa1Radius)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	poa, err = pc.GetPoa(poa1Name)
	if err != nil || poa == nil {
		t.Fatalf("Failed to get POA")
	}
	if !validatePoa(poa, poa1Id, poa1Name, poa1Type, poaLoc, poa1Radius) {
		t.Fatalf("POA validation failed")
	}

	poaLoc = "{\"type\":\"Point\",\"coordinates\":" + poa2Loc + "}"
	err = pc.CreatePoa(poa2Id, poa2Name, poa2Type, poaLoc, poa2Radius)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	poa, err = pc.GetPoa(poa2Name)
	if err != nil || poa == nil {
		t.Fatalf("Failed to get POA")
	}
	if !validatePoa(poa, poa2Id, poa2Name, poa2Type, poaLoc, poa2Radius) {
		t.Fatalf("POA validation failed")
	}

	poaLoc = "{\"type\":\"Point\",\"coordinates\":" + poa3Loc + "}"
	err = pc.CreatePoa(poa3Id, poa3Name, poa3Type, poaLoc, poa3Radius)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	poa, err = pc.GetPoa(poa3Name)
	if err != nil || poa == nil {
		t.Fatalf("Failed to get POA")
	}
	if !validatePoa(poa, poa3Id, poa3Name, poa3Type, poaLoc, poa3Radius) {
		t.Fatalf("POA validation failed")
	}

	// Add UE & Validate successfully added
	fmt.Println("Add UEs & Validate successfully added")
	ueLoc = "{\"type\":\"Point\",\"coordinates\":" + point1 + "}"
	uePath = "{\"type\":\"LineString\",\"coordinates\":[" + point1 + "," + point2 + "," + point3 + "," + point4 + "," + point1 + "]}"
	err = pc.CreateUe(ue1Id, ue1Name, ueLoc, uePath, PathModeLoop, ue1Velocity)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	ue, err = pc.GetUe(ue1Name)
	if err != nil || ue == nil {
		t.Fatalf("Failed to get UE")
	}
	if !validateUe(ue, ue1Id, ue1Name, ueLoc, uePath, PathModeLoop, ue1Velocity, 1383.59, 0.004, 0.000, poa1Name, 83.24975, []string{poa1Name}) {
		t.Fatalf("UE validation failed")
	}

	ueLoc = "{\"type\":\"Point\",\"coordinates\":" + point2 + "}"
	err = pc.CreateUe(ue2Id, ue2Name, ueLoc, "", "", ue2Velocity)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	ue, err = pc.GetUe(ue2Name)
	if err != nil || ue == nil {
		t.Fatalf("Failed to get UE")
	}
	if !validateUe(ue, ue2Id, ue2Name, ueLoc, "", PathModeLoop, ue2Velocity, 0.000, 0.000, 0.000, poa2Name, 10.08527, []string{poa2Name}) {
		t.Fatalf("UE validation failed")
	}

	ueLoc = "{\"type\":\"Point\",\"coordinates\":" + point4 + "}"
	uePath = "{\"type\":\"LineString\",\"coordinates\":[" + point4 + "," + point3 + "," + point2 + "]}"
	err = pc.CreateUe(ue3Id, ue3Name, ueLoc, uePath, PathModeLoop, ue3Velocity)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	ue, err = pc.GetUe(ue3Name)
	if err != nil || ue == nil {
		t.Fatalf("Failed to get UE")
	}
	fmt.Printf("%+v\n", ue)
	if !validateUe(ue, ue3Id, ue3Name, ueLoc, uePath, PathModeLoop, ue3Velocity, 810.678, 0.031, 0.000, poa1Name, 101.99091, []string{poa1Name}) {
		t.Fatalf("UE validation failed")
	}

	// Add Compute & Validate successfully added
	fmt.Println("Add Computes & Validate successfully added")
	computeLoc := "{\"type\":\"Point\",\"coordinates\":[0,0]}"
	err = pc.CreateCompute(compute1Id, compute1Name, compute1Type, computeLoc)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	compute, err = pc.GetCompute(compute1Name)
	if err != nil || compute == nil {
		t.Fatalf("Failed to get Compute")
	}
	if !validateCompute(compute, compute1Id, compute1Name, compute1Type, computeLoc) {
		t.Fatalf("Compute validation failed")
	}

	computeLoc = "{\"type\":\"Point\",\"coordinates\":[0,2]}"
	err = pc.CreateCompute(compute2Id, compute2Name, compute2Type, computeLoc)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	compute, err = pc.GetCompute(compute2Name)
	if err != nil || compute == nil {
		t.Fatalf("Failed to get Compute")
	}
	if !validateCompute(compute, compute2Id, compute2Name, compute2Type, computeLoc) {
		t.Fatalf("Compute validation failed")
	}

	computeLoc = "{\"type\":\"Point\",\"coordinates\":[2,2]}"
	err = pc.CreateCompute(compute3Id, compute3Name, compute3Type, computeLoc)
	if err != nil {
		t.Fatalf("Unable to create asset")
	}
	compute, err = pc.GetCompute(compute3Name)
	if err != nil || compute == nil {
		t.Fatalf("Failed to get Compute")
	}
	if !validateCompute(compute, compute3Id, compute3Name, compute3Type, computeLoc) {
		t.Fatalf("Compute validation failed")
	}

	// t.Fatalf("DONE")
}

func validateUe(ue *Ue, id string, name string, position string, path string,
	mode string, velocity float32, length float32, increment float32, fraction float32,
	poa string, distance float32, poaInRange []string) bool {
	if ue == nil {
		fmt.Println("ue == nil")
		return false
	}
	if ue.Id != id {
		fmt.Println("ue.Id != id")
		return false
	}
	if ue.Name != name {
		fmt.Println("ue.Name != name")
		return false
	}
	if ue.Position != position {
		fmt.Println("ue.Position != position")
		return false
	}
	if ue.Path != path {
		fmt.Println("ue.Path != path")
		return false
	}
	if ue.PathMode != mode {
		fmt.Println("ue.PathMode != mode")
		return false
	}
	if ue.PathVelocity != velocity {
		fmt.Println("ue.PathVelocity != velocity")
		return false
	}
	if ue.PathLength != length {
		fmt.Println("ue.PathLength != length")
		return false
	}
	if ue.PathIncrement != increment {
		fmt.Println("ue.PathIncrement != increment")
		return false
	}
	if ue.PathFraction != fraction {
		fmt.Println("ue.PathFraction != fraction")
		return false
	}
	if ue.Poa != poa {
		fmt.Println("ue.Poa != poa")
		return false
	}
	if ue.PoaDistance != distance {
		fmt.Println("ue.PoaDistance != distance")
		return false
	}

	if len(ue.PoaInRange) != len(poaInRange) {
		fmt.Println("len(ue.PoaInRange) != len(poaInRange)")
		return false
	} else {
		sort.Strings(ue.PoaInRange)
		sort.Strings(poaInRange)

		for i, poa := range ue.PoaInRange {
			if poa != poaInRange[i] {
				fmt.Println("poa != poaInRange[i]")
				return false
			}
		}
	}

	return true
}

func validatePoa(poa *Poa, id string, name string, subType string, position string, radius float32) bool {
	if poa == nil {
		fmt.Println("poa == nil")
		return false
	}
	if poa.Id != id {
		fmt.Println("poa.Id != id")
		return false
	}
	if poa.Name != name {
		fmt.Println("poa.Name != name")
		return false
	}
	if poa.SubType != subType {
		fmt.Println("poa.SubType != subType")
		return false
	}
	if poa.Position != position {
		fmt.Println("poa.Position != position")
		return false
	}
	if poa.Radius != radius {
		fmt.Println("poa.Radius != radius")
		return false
	}

	return true
}

func validateCompute(compute *Compute, id string, name string, subType string, position string) bool {
	if compute == nil {
		fmt.Println("compute == nil")
		return false
	}
	if compute.Id != id {
		fmt.Println("compute.Id != id")
		return false
	}
	if compute.Name != name {
		fmt.Println("compute.Name != name")
		return false
	}
	if compute.SubType != subType {
		fmt.Println("compute.SubType != subType")
		return false
	}
	if compute.Position != position {
		fmt.Println("compute.Position != position")
		return false
	}

	return true
}