package com.spirent.service.execution.protocol;

// Protocol buffer compiler will generate code for serializing, parsing, and performing other common operations on message types.
// This code is extremely highly optimized.
option optimize_for = SPEED;

enum ReportResult {
        // successful
        PASS = 0;
        // unknown pass/fail
        INDETERMINATE = 1;
        // unsuccessful
        FAIL = 2;
        // test self-aborted (e.g., due to analysis rule)
        ABORT = 3;
        // bad things happened (e.g., could not obtain a reservation)
        ERROR = 4;
        // test was told to cancel
        CANCEL = 5;
}

// A union type where the required "type" field identifies the field that's set.
message ExecutionMessage {

    enum Type {
    
        ////////
        //
        // EXECUTION MESSAGES
        //
        ////////

        CANCEL_MESSAGE = 1;
        HEARTBEAT_MESSAGE = 2;
        INIT_MESSAGE = 3;
        INVOKE_ACK = 4; 
        INVOKE_MESSAGE = 5;
        INVOKE_RESPONSE = 6;
        REPORT_MESSAGE = 7;
        STEP_MESSAGE = 8;
        TERMINATE_MESSAGE = 9;
        TOKEN_MESSAGE = 10;
        EXECUTION_ISSUE_MESSAGE = 11;

        ////////
        //
        // SESSION CONTROL MESSAGES
        //
        ////////

        NEW_SESSION_MESSAGE = 12;
        NEW_SESSION_RESPONSE = 13;
        SEND_TERMINAL_DATA_MESSAGE = 14;
        SEND_TERMINAL_DATA_RESPONSE = 15;
        SESSION_ACTION_MESSAGE = 16;
        SESSION_ACTION_RESPONSE = 17; 
        LIST_PROJECTS = 18;
        LIST_PROJECTS_RESPONSE = 19;
        QUERY_PROJECT = 20;
        QUERY_PROJECT_RESPONSE = 21;
        QUERY_SESSION = 22;
        QUERY_SESSION_RESPONSE = 23;
    }

    // Identifies which field is filled in.
    required Type type = 1;
    
    ////////
    //
    // EXECUTION MESSAGES
    //
    ////////

    optional CancelMessage cancelMessage = 2;
    optional HeartbeatMessage heartbeatMessage = 3;
    optional InitMessage initMessage = 4;
    optional InvokeAck invokeAck = 5; 
    optional InvokeMessage invokeMessage = 6;
    optional InvokeResponse invokeResponse = 7;
    optional ReportMessage reportMessage = 8;
    optional StepMessage stepMessage = 9;
    optional TerminateMessage terminateMessage = 10;
    optional TokenMessage tokenMessage = 11;
    optional ExecutionIssueMessage executionIssueMessage = 12;

    ////////
    //
    // SESSION CONTROL MESSAGES
    //
    ////////

    optional NewSession newSessionMessage = 13;
    optional NewSessionResponse newSessionResponse = 14; 
    optional SendTerminalData sendTerminalDataMessage = 15;
    optional SendTerminalDataResponse sendTerminalDataResponse = 16;
    optional SessionAction sessionActionMessage = 17;
    optional SessionActionResponse sessionActionResponse = 18;
    optional ListProjects listProjects = 19;
    optional ListProjectsResponse listProjectsResponse = 20;
    optional QueryProject queryProject = 21;
    optional QueryProjectResponse queryProjectResponse = 22;
    optional QuerySession querySession = 23;
    optional QuerySessionResponse querySessionResponse = 24;
}


// Sent by the service to request cancellation. Agent is expected to reply with an InvokeResponse. 
message CancelMessage {
    // ID of the session to cancel. The session ID must be equal to the reportId provided in the InvokeMessage.
    required string sessionId = 1;
}


// Message that is streamed from Agent as execution issues occur.
message ExecutionIssueMessage {

    enum Severity {
        ERROR = 0;
        INFORMATION = 1;
        PASS = 2;
        WARNING = 3;
    }

    // What test case file is associated with the issue. e.g., "project://test_project/test_cases/myTest.fftc"
    required string fileUri = 1;
    // Issues are ordered within their parent. This index is unique only within the context of its reportId/stepId pair.
    required uint32 issueIndex = 2;
    // Where in a test case the issue occurred as defined at authoring time, rather than at runtime. e.g., "/procedures/0/steps/1"
    required string location = 3;
    // An informational message.
    optional string message = 4;
    // e.g., "analysis"
    optional string originator = 5;
    // Useful for display purposes, as well as mining quick call libraries for troublesome procedures. e.g., "main"
    optional string procedureName = 6;
    // The ID of the report.
    required string reportId = 7;
    // The ID of the session. e.g., "s1"
    required string sessionId = 8;
    // info, warning, error
    optional Severity severity = 9 [default = INFORMATION];
    // Executed step ID. e.g., "1.2.1"
    required string stepId = 10;
    // Step id of executable step in test case. e.g., "1.2.1"
    required string testCaseStepId = 11;
    optional uint64 line = 12;
    optional uint64 startCol = 13;
    optional uint64 endCol = 14;
    optional uint64 lineCount = 15;
    // Sequentially sorts issues in the order of their occurrence within the overall test case.
    optional uint64 sequenceNum = 16;
    // The time when the issue occurred. Represents milliseconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
    optional uint64 issueTime = 17;
}


message HeartbeatMessage {
    // Memory usage as a percentage available to the agent process. A negative value indicates memory usage information is unavailable.
    optional double memoryUsage = 1 [default = -1];
    // Returns the "recent cpu usage" for the Agent process. See Java's OperatingSystemMXBean.getProcessCpuLoad() for further details. A negative value indicates process cpu load information is unavailable.
    optional double processCpuLoad = 2 [default = -1];
    // Returns the "recent cpu usage" for the whole system. See Java's OperatingSystemMXBean.getSystemCpuLoad() for further details. A negative value indicates system cpu load information is unavailable.
    optional double systemCpuLoad = 3 [default = -1];
}


// Sent by the Agent upon receipt of an InvokeMessage. The session ID can be used to cancel the execution.
message InvokeAck {
    // The session ID must be equal to the reportId provided in the InvokeMessage.
    required string sessionId = 1;
    // Represents milliseconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
    optional uint64 startTime = 2;
}


// A parameter.
message Param {
    required string name = 1;
    required string value = 2;
    // Params may be nested
    repeated Param parameters = 3;
}


// Sent by the service to request execution. Agent is expected to reply with an InvokeAck and finally with an InvokeResponse. URIs are UTF-8 encoded and not escaped.
message InvokeMessage {

    enum DetailLevel {
        // nothing but the report-level details, including status/result.
        REPORT_ONLY = 0;
        // report-level details and ERROR-level execution issues
        ERROR_ISSUES_ONLY = 1;
        // report-level details and ERROR-level execution issues and any steps associated with those issues
        ERROR_ISSUES_WITH_STEPS = 2;
        // report-level details and all execution issues and steps that have an error
        ALL_ISSUES_ERROR_STEPS = 3;
        // report-level details and all execution issues and steps
        ALL_ISSUES_ALL_STEPS = 4;
        // only failed steps and at the end of execution if test case passed send the last step response in full
        LAST_RESPONSE = 5;
    }

    message Header {
        required string name = 1;
        required string value = 2;
    }

    message Reservation {
        // ID used to lookup all information about the reservation
        required string reservationId = 1;
        // location of reservation API endpoint, e.g., https://somehost/velocity/api
        required string reservationVelocityUrl = 2;
    }

    required TokenMessage token = 1;
    repeated Header header = 2;
    required string reportId = 3;
    repeated string dependencyUri = 4;
    repeated string paramFileUri = 5;
    repeated Param parameters = 6;
    // Information about the reservation to use during execution. Not present if testbedUri is set.
    optional Reservation reservation = 7;
    // URI of the topology to reserve. Not present when reservation information is provided.
    optional string testbedUri = 8;
    required string testCaseUri = 9;
    optional DetailLevel detailLevel = 10 [default = ALL_ISSUES_ALL_STEPS];
}


// Sent by the Agent when initially establishing a connection with the service.
message InitMessage {

    message Capability {
        required string name = 1;
        required string value = 2;
    }

    message Restriction {
        required string name = 1;
        required string value = 2;
    }

    // A globally unique identifier of the agent
    required string agentId = 1;
    // The name of the agent
    required string agentName = 2;
    required string protocolVersion = 3;
    // Capabilities of the agent.
    repeated Capability capability = 4;
    // Defined when an agent already has an execution in-progress which may be the case when a loss of connection occurred. The session ID must be equal to the reportId provided in the InvokeMessage.
    optional string sessionId = 5;
    // Restrictions on executions that may run on the agent.
    repeated Restriction restriction = 6;
}


// Sent by the Agent as the last message in response to an InvokeMessage.
message InvokeResponse {

    message Error {
        required uint32 code = 1;
        optional string message = 2;
    }

    required ReportResult reportResult = 1;
    // Represents milliseconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
    required uint64 startTime = 2;
    // Represents milliseconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
    required uint64 endTime = 3;
    // The session ID must be equal to the reportId provided in the InvokeMessage.
    required string sessionId = 4;
    optional Error error = 5;
}


// Sent by the Agent to inform the service of an imminent shutdown of the Agent.
message TerminateMessage {
    optional string cause = 1;
}


// Included in InvokeMessage. Stand-alone Token messages may periodically be sent to the Agent to update the refresh token.
message TokenMessage {
    required string token = 1;
}

// Message sent by the Agent to create or update report metadata.
message ReportMessage {

    // Identifies the report to update or the child report to create. If the ReportMessage identifies a new child report then the agent assigns the ID using UUID.randomUUID().toString().
    required string reportId = 1;
    // Represents milliseconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
    optional uint64 startTime = 2;
    // Represents milliseconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
    optional uint64 endTime = 3;
    optional string parentStepIndex = 4;
    // The ID of the parent report. This must be included when initially creating a new child report.
    optional string parentReportId = 5;
    // The path of the child test that was invoked. The Execution Service will handle conversion of paths like: project://foo.itar/path/bar.fftc to: repository/foo/path/bar.fftc
    optional string testPath = 6;
    optional string testId = 7;
    // The result of the execution.
    optional ReportResult result = 8;
    optional double percentageComplete = 9;
    // The Agent sets this to indicate what parameters were used when invoking a child test.
    repeated Param parameters = 10;

}


// The reportId and stepId together uniquely identify a StepMessage.
message StepMessage {

    enum StepResult {
        ABORTED = 0;
        FAILED = 1;
        SKIPPED = 2;
        SUCCESS = 3;
        TIMEOUT = 4;
    }

    message Action {
        // name of the action, e.g., "event"
        required string action = 1;
        // string form of what the action is, as rendered on the agent, e.g., "OnExecutionStarted"
        optional string description = 2;
        // actions can be nested
        repeated Action actions = 3;
    }

    message StepResponseDetails {

        message Alias {
            
            message Argument {
                // argument name
                required string name = 1;
                // how the possible values of the argument can be found, e.g., "mapped/Tabular/table1/table/row/key"
                optional string valuesQuery = 2;
                optional string interpretAs = 3;
            }
            
            // alias name as defined by the mapper or user
            required string name = 1;
            // how the structured data would be queried by the agent via XPath
            optional string queryFormat = 2;
            // list of arguments
            repeated Argument arguments = 3;
        }
    
        message AnalysisRule {
            // string describing the extractor type. Could be "regex", "contains", "query", etc.
            optional string extractor = 1;
            // collapsed information derived on the agent side from the rule
            optional string description = 2;
            // collapsed information on the result of this branch. Since this information describes what actually fired, either whenTrue or whenFalse will be null
            optional string whenTrue = 3;
            // same as whenTrue
            optional string whenFalse = 4;
            // list of actions taken as a result of this rule firing
            repeated Action actions = 5;
        }
        
        message StructuredData {
        
            message Item {
                // defined by the mapper
                optional string name = 1;
                // positional information if provided for a enclosing block or terminal token; allows highlighting of area within the textual response
                optional int32 line = 2;
                // positional information if provided for a enclosing block or terminal token; allows highlighting of area within the textual response
                optional int32 lineCount = 3;
                // positional information if provided for a enclosing block or terminal token; allows highlighting of area within the textual response
                optional int32 startCol = 4; 
                // positional information if provided for a enclosing block or terminal token; allows highlighting of area within the textual response
                optional int32 endCol = 5;
                // if a terminal token, the actual value of the token
                optional string value = 6;
                // list of nested items as defined by the mapper
                repeated Item items = 7;
            }
        
            // name of the mapper type (currently regex, table, block)
            required string map = 8;
            // reference to the response map used if not auto-mapped
            optional string responseMapUri = 9;
            //
            repeated Item items = 10;
        }
        
        // True when the structured data was derived from auto mappers. If not, then each map will state what response map it used.
        optional bool isAutoMapped = 1 [default = false];
        // escaped body of the response
        optional string body = 2;
        repeated Action postProcessing = 3;
        // Analysis rules that fired. Most of the structure is collapsed in favor of displayable strings.
        repeated AnalysisRule analysisRules = 4;
        repeated StructuredData structuredData = 5; 
        repeated Alias aliases = 6;
    }
      
    required string reportId = 1;
    // executed step id, e.g., "1.2.1"
    required string stepId = 2;
    // e.g., "1.2"
    optional string parentStepId = 3;
    // step id of executable step in test case, e.g., "1.2.1"
    required string testCaseStepId = 4;
    optional int32 threadId = 5;
    // e.g., "s1"
    optional string sessionId = 6;
    // "resolved application id", e.g., "com.fnfr.svt.applications.tclsh" - used to render icon, etc.
    optional string sessionType = 7;
    // e.g., "main"
    optional string procedure = 8;
    // all are resolved - what was sent to the device, e.g., "command"
    optional string action = 9;
    optional string context = 10;
    optional string target = 11;
    // e.g., "puts Hello"
    optional string command = 12;
    optional double startOffset = 13;
    optional double duration = 14;
    optional bool emulated = 15 [default = false];
    optional StepResult stepResult = 16;
    optional StepResponseDetails details = 17;
    // The rendered property group. It contains the serialized XML of the property group object for this step. Meant to be kept as opaque data by Velocity.
    optional string properties = 18;
    // Sequentially sorts steps in the order of their execution.
    optional uint64 sequenceNum = 19;
}

////////
//
// SESSION CONTROL MESSAGES
//
////////

// A union type consisting of the messages that are exchanged between service and client. The required "type" field identifies the field that's set.
message ClientSessionControlMessage {
    
    enum Type {
        INIT_MESSAGE = 1;
        INIT_RESPONSE = 2;
        NEW_SESSION_MESSAGE = 3;
        NEW_SESSION_RESPONSE = 4;
        SEND_TERMINAL_DATA_MESSAGE = 5;
        SEND_TERMINAL_DATA_RESPONSE = 6;
        SESSION_ACTION_MESSAGE = 7;
        SESSION_ACTION_RESPONSE = 8;
        SESSION_TERMINATED = 9;
        LIST_PROJECTS = 10;
        LIST_PROJECTS_RESPONSE = 11;
        QUERY_PROJECT = 12;
        QUERY_PROJECT_RESPONSE = 13;
        QUERY_SESSION = 14;
        QUERY_SESSION_RESPONSE = 15;
    }
    
    // Identifies which field is filled in.
    required Type type = 1;
    
    optional Init initMessage = 2;
    optional InitResponse initResponse = 3;
    optional NewSession newSessionMessage = 4;
    optional NewSessionResponse newSessionResponse = 5; 
    optional SendTerminalData sendTerminalDataMessage = 6;
    optional SendTerminalDataResponse sendTerminalDataResponse = 7;
    optional SessionAction sessionActionMessage = 8;
    optional SessionActionResponse sessionActionResponse = 9;
    optional SessionTerminated sessionTerminatedMessage = 10;
    optional ListProjects listProjects = 11;
    optional ListProjectsResponse listProjectsResponse = 12;
    optional QueryProject queryProject = 13;
    optional QueryProjectResponse queryProjectResponse = 14;
    optional QuerySession querySession = 15;
    optional QuerySessionResponse querySessionResponse = 16;
}

// Sent by a client upon initiation of the connection. 
message Init {

    required string token = 1;
    required string version = 2;
}

// Service reply to Init message.
message InitResponse {

    required string status = 1 [default = "success"];
    required string version = 2;
}

message NewSession {

    message Header {
        required string name = 1;
        required string value = 2;
    }
    
    message PropertiesGroup {
    
        message Property {
        
            required string name = 1;
            required string value = 2;
        }

        required string name = 1;
        repeated Property properties = 2;
        repeated PropertiesGroup children = 3;
    }
    
    message Requirement {
        required string name = 1;
        required string value = 2;
    }
    
    // GUID used to track this new session; generated by the execution service
    required string sessionId = 1;
    // e.g., "project://my_project/sessions/ssh_session.ffsp"
    required string sessionUri = 2;
    // e.g., ["/main/my_project.itar"]
    repeated string dependencyUri = 3;
    // collection of HTTP headers to be used in agent-Velocity interactions
    repeated Header header = 4;
    // a parameter file URI
    repeated string paramFileUri = 5;
    repeated Requirement requirement = 6;
    // Session properties for a built-in session type; maps directly to session properties group
    optional PropertiesGroup properties = 7;
    // a Response map library URI (Project uri). e.g., "project://my_project/"
    optional string responseMapLib = 8;
}

enum SessionStepResult {
    ABORTED = 0;
    FAILED = 1;
    SKIPPED = 2;
    SUCCESS = 3;
    TIMEOUT = 4;
}

message NewSessionResponse {
    
    // GUID used to track the session
    required string sessionId = 1;
    optional double duration = 2;
    optional SessionStepResult stepResult = 3 [default = SUCCESS];
    // structure for response details
    optional StepMessage.StepResponseDetails details = 4;
    // rue if the session allows direct terminal interaction
    optional bool allowTerminal = 5 [default = true];
}

message SendTerminalData {

    // GUID used to track the session
    required string sessionId = 1;
    // JSON encoded and will be interpreted by the session as appropriate.
    optional string data = 2;
}

message SendTerminalDataResponse {
    
    message Capture {

        // string form of the full command sent to the target (i.e. "set value foo")
        optional string action = 1;
        // JSON encoding of the full capture properties from the agent.
        optional string response = 2;
    }
    
    // GUID used to track the session
    required string sessionId = 1;
    // JSON encoded terminal data from the session.
    optional string data = 2;
    // If the interaction with the session resulted in a complete action/response
    optional Capture capture = 3;
}

message SessionAction {

    enum ResponseModeMap {
        // use auto response mapping only
        AUTO = 0;
        // use configured response map, otherwise do auto-mapping if no response map found
        DEFAULT = 1;
        // use the specified response map given in the URI in responseMap
        FILE = 2;
        // use the response map library configured for the session; if value provided for responseMap, then that is the name of the map to use in that library.
        LIBRARY = 3;
        OFF = 4;
    }

    // GUID used to track the session
    required string sessionId = 1;
    // Name of the action to be invoked or the name of the QuickCall to be invoked on the session. "close" is a legal action and will result in closing the session, as if a "close" step were encountered in a test case.
    required string action = 2;
    // String command to be sent as part of the action. QuickCalls do not use command, instead they use only parameters.
    optional string command = 3;
    // Set of parameters to be passed to the action/QuickCall.
    repeated Param parameters = 4;
    optional ResponseModeMap responseMapMode = 5 [default = DEFAULT];
    // Name of a response map within a response map library.
    optional string responseMap = 6;
}

message SessionActionResponse {

    // GUID used to track the session
    required string sessionId = 1;
    optional double duration = 2;
    optional SessionStepResult stepResult = 3 [default = SUCCESS];
    // structure for response details
    optional StepMessage.StepResponseDetails details = 4;
}

// Sent if the agent terminates the connection abnormally. The session is considered closed. Not sent when the client issues a close command via the SessionAction message.
message SessionTerminated {
    
    enum Status {
        AGENT_TERMINATED = 1;
    }

    required Status status = 1 [default = AGENT_TERMINATED];
}

message ListProjects {
}

message ListProjectsResponse {

    // Is a list of project names that are accessible to the current user (if authenticated through Velocity) within the applicable context.
    // For a local agent it should list all projects that are available within the ITAR_PATH.
    // For a iTest GUI instance it should list all projects in the workspace.
    // For Velocity, it should list all projects available within all repos that the user has access to.
    // When working through Velocity the names include the repo path ('/main/') within them. When working outside of Velocity only the project name will be returned. I.e. 'my_project'.
    repeated string projects = 1;
}

message QueryProject {

    // Name of the project to query.
    required string project = 1;

    // true if session profiles should be listed (default is true)
    optional bool sessionProfiles = 2 [default = true];

    // true if topologies should be listed (default is true)
    optional bool topologies = 3 [default = true];

    // true if parameter files should be listed (default is false)
    optional bool parameterFiles = 4 [default = false];

    // true if response maps should be listed (default is false)
    optional bool responseMaps = 5 [default = false];
}

message QueryProjectResponse {

    message Topology {

        message Device {
            required string name = 1;
            repeated string sessions = 2;
        }

        required string name = 1;
        repeated Device devices = 2;
    }

    // Name of the project to query.
    required string project = 1;

    repeated string sessionProfiles = 2;
    repeated Topology topologies = 3;
    repeated string parameterFiles = 4;
    repeated string responseMaps = 5;
}

message QuerySession {

    // e.g., "project://my_project/sessions/ssh_session.ffsp"
    required string sessionUri = 1;

    // Name of a specific QuickCall to show information about.
    // If specified, then only that QuickCall will be shown.
    optional string specificQC = 2;
}

message QuerySessionResponse {

    message QuickCall {

        message Argument {
            required string name = 1;
            optional string description = 2;
        }

        required string name = 1;
        repeated Argument args = 2;
    }

    repeated QuickCall quickCall = 2;
}