nip/tests/test_utcp_protocol.nim

359 lines
11 KiB
Nim

## Test suite for UTCP Protocol implementation
import unittest
import std/[tables, json, options]
import ../src/nimpak/utcp_protocol
suite "UTCP Address Assignment":
test "Assign UTCP address to Nippel":
let res = assignUTCPAddress(Nippel, "dev-env", "localhost")
check res.isOk
if res.isOk:
let address = res.okValue
check address.scheme == UtcpPlain
check address.host == "localhost"
check address.resourceType == Nippel
check address.resourceName == "dev-env"
test "Assign UTCP address with default host":
let res = assignUTCPAddress(Nexter, "web-server")
check res.isOk
let address = res.okValue
check address.host.len > 0 # Should use hostname
check address.resourceType == Nexter
check address.resourceName == "web-server"
test "Create agent endpoint":
let res = createAgentEndpoint("n8n-workflow", "localhost")
check res.isOk
let address = res.okValue
check address.resourceType == Agent
check address.resourceName == "n8n-workflow"
test "Create tool endpoint":
let res = createToolEndpoint("nexus", "localhost")
check res.isOk
let address = res.okValue
check address.resourceType == Tool
check address.resourceName == "nexus"
test "Create LLM endpoint":
let res = createLLMEndpoint("llama2", "localhost")
check res.isOk
let address = res.okValue
check address.resourceType == LLM
check address.resourceName == "llama2"
suite "UTCP Address Parsing":
test "Parse simple UTCP address":
let res = parseUTCPAddress("utcp://localhost/nippel/dev-env")
check res.isOk
let address = res.okValue
check address.scheme == UtcpPlain
check address.host == "localhost"
check address.resourceType == Nippel
check address.resourceName == "dev-env"
test "Parse UTCP address with port":
let res = parseUTCPAddress("utcp://localhost:8080/nexter/web-server")
check res.isOk
let address = res.okValue
check address.port.isSome
check address.port.get() == 8080
test "Parse UTCP address with path":
let res = parseUTCPAddress("utcp://localhost/nippel/dev-env/state")
check res.isOk
let address = res.okValue
check address.path == "/state"
test "Parse UTCP address with query":
let res = parseUTCPAddress("utcp://localhost/nippel/dev-env?cmd=vim")
check res.isOk
let address = res.okValue
check address.query.hasKey("cmd")
check address.query["cmd"] == "vim"
test "Parse secure UTCP address":
let res = parseUTCPAddress("utcps://localhost/agent/n8n")
check res.isOk
let address = res.okValue
check address.scheme == UtcpSecure
test "Parse invalid scheme":
let res = parseUTCPAddress("http://localhost/nippel/dev-env")
check not res.isOk
test "Parse invalid path":
let res = parseUTCPAddress("utcp://localhost/invalid")
check not res.isOk
suite "UTCP Address Formatting":
test "Format simple address":
let address = newUTCPAddress("localhost", Nippel, "dev-env")
let formatted = formatUTCPAddress(address)
check formatted == "utcp://localhost/nippel/dev-env"
test "Format address with port":
let address = newUTCPAddress("localhost", Nexter, "web-server", port = some(8080))
let formatted = formatUTCPAddress(address)
check formatted == "utcp://localhost:8080/nexter/web-server"
test "Format address with path":
let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/state")
let formatted = formatUTCPAddress(address)
check formatted == "utcp://localhost/nippel/dev-env/state"
test "Format address with query":
var query = initTable[string, string]()
query["cmd"] = "vim"
let address = newUTCPAddress("localhost", Nippel, "dev-env", query = query)
let formatted = formatUTCPAddress(address)
check formatted.contains("?cmd=vim")
test "Format secure address":
let address = newUTCPAddress("localhost", Agent, "n8n", scheme = UtcpSecure)
let formatted = formatUTCPAddress(address)
check formatted.startsWith("utcps://")
suite "UTCP Request Creation":
test "Create GET request":
let address = newUTCPAddress("localhost", Nippel, "dev-env")
let request = newUTCPRequest(address, GET)
check request.meth == GET
check request.address.resourceName == "dev-env"
check request.headers.hasKey("User-Agent")
check request.headers.hasKey("UTCP-Version")
test "Create POST request with payload":
let address = newUTCPAddress("localhost", Nippel, "dev-env")
let payload = %*{"command": "vim"}
let request = newUTCPRequest(address, POST, payload)
check request.meth == POST
check request.payload.hasKey("command")
check request.payload["command"].getStr() == "vim"
suite "UTCP Response Creation":
test "Create success response":
let response = newUTCPResponse(Ok, %*{"status": "active"}, "req-123")
check response.status == Ok
check response.requestId == "req-123"
check response.data.hasKey("status")
test "Create error response":
let response = newUTCPResponse(NotFound, %*{"error": "Not found"})
check response.status == NotFound
check response.data.hasKey("error")
suite "UTCP Method Handlers":
test "Handle GET state":
let res = handleGetState(Nippel, "dev-env")
check res.isOk
let state = res.okValue
check state.hasKey("resourceType")
check state.hasKey("resourceName")
check state.hasKey("status")
test "Handle activate":
let res = handleActivate(Nippel, "dev-env")
check res.isOk
let response = res.okValue
check response.hasKey("action")
check response["action"].getStr() == "activate"
test "Handle deactivate":
let res = handleDeactivate(Nippel, "dev-env")
check res.isOk
let response = res.okValue
check response.hasKey("action")
check response["action"].getStr() == "deactivate"
test "Handle get merkle":
let res = handleGetMerkle(Nippel, "dev-env")
check res.isOk
let merkle = res.okValue
check merkle.hasKey("merkleRoot")
test "Handle exec":
let res = handleExec(Nippel, "dev-env", "vim")
check res.isOk
let execResult = res.okValue
check execResult.hasKey("command")
check execResult["command"].getStr() == "vim"
suite "UTCP Request Routing":
test "Route GET state request":
let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/state")
let request = newUTCPRequest(address, GET)
let res = routeUTCPRequest(request)
check res.isOk
let response = res.okValue
check response.status == Ok
check response.data.hasKey("resourceType")
test "Route POST activate request":
let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/activate")
let request = newUTCPRequest(address, POST)
let res = routeUTCPRequest(request)
check res.isOk
let response = res.okValue
check response.status == Ok
check response.data["action"].getStr() == "activate"
test "Route POST deactivate request":
let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/deactivate")
let request = newUTCPRequest(address, POST)
let res = routeUTCPRequest(request)
check res.isOk
let response = res.okValue
check response.status == Ok
check response.data["action"].getStr() == "deactivate"
test "Route GET merkle request":
let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/merkle")
let request = newUTCPRequest(address, GET)
let res = routeUTCPRequest(request)
check res.isOk
let response = res.okValue
check response.status == Ok
check response.data.hasKey("merkleRoot")
test "Route POST exec request":
let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/exec")
let payload = %*{"command": "vim"}
let request = newUTCPRequest(address, POST, payload)
let res = routeUTCPRequest(request)
check res.isOk
let response = res.okValue
check response.status == Ok
check response.data["command"].getStr() == "vim"
test "Route invalid path":
let address = newUTCPAddress("localhost", Nippel, "dev-env", path = "/invalid")
let request = newUTCPRequest(address, GET)
let res = routeUTCPRequest(request)
check res.isOk
let response = res.okValue
check response.status == NotFound
test "Route unsupported method":
let address = newUTCPAddress("localhost", Nippel, "dev-env")
let request = newUTCPRequest(address, DELETE)
let res = routeUTCPRequest(request)
check res.isOk
let response = res.okValue
check response.status == MethodNotAllowed
suite "UTCP Utility Functions":
test "Check local address - localhost":
let address = newUTCPAddress("localhost", Nippel, "dev-env")
check isLocalAddress(address)
test "Check local address - 127.0.0.1":
let address = newUTCPAddress("127.0.0.1", Nippel, "dev-env")
check isLocalAddress(address)
test "Check remote address":
let address = newUTCPAddress("remote.example.com", Nippel, "dev-env")
check not isLocalAddress(address)
test "Get default port for plain UTCP":
let port = getDefaultPort(UtcpPlain)
check port == UTCP_DEFAULT_PORT
test "Get default port for secure UTCP":
let port = getDefaultPort(UtcpSecure)
check port == UTCP_DEFAULT_PORT + 1
test "Validate valid address":
let address = newUTCPAddress("localhost", Nippel, "dev-env")
let res = validateAddress(address)
check res.isOk
test "Validate address with empty host":
let address = UTCPAddress(
scheme: UtcpPlain,
host: "",
resourceType: Nippel,
resourceName: "dev-env"
)
let res = validateAddress(address)
check not res.isOk
test "Validate address with empty resource name":
let address = UTCPAddress(
scheme: UtcpPlain,
host: "localhost",
resourceType: Nippel,
resourceName: ""
)
let res = validateAddress(address)
check not res.isOk
suite "UTCP Resource Types":
test "Create Nippel address":
let address = newUTCPAddress("localhost", Nippel, "dev-env")
check address.resourceType == Nippel
test "Create Nexter address":
let address = newUTCPAddress("localhost", Nexter, "web-server")
check address.resourceType == Nexter
test "Create Package address":
let address = newUTCPAddress("localhost", Package, "nginx")
check address.resourceType == Package
test "Create System address":
let address = newUTCPAddress("localhost", System, "config")
check address.resourceType == System
test "Create Tool address":
let address = newUTCPAddress("localhost", Tool, "nexus")
check address.resourceType == Tool
test "Create Agent address":
let address = newUTCPAddress("localhost", Agent, "n8n-workflow")
check address.resourceType == Agent
test "Create LLM address":
let address = newUTCPAddress("localhost", LLM, "llama2")
check address.resourceType == LLM