Add per-session variable server logs

This commit is contained in:
Deans 2023-04-18 16:27:32 -05:00 committed by Jacqueline Deans
parent 99ee88a686
commit a4d49850f3
57 changed files with 894 additions and 193 deletions

2
.gitignore vendored
View File

@ -42,4 +42,4 @@ trickops_logs/
*.gcno
coverage.info
*.dSYM
*.log

View File

@ -0,0 +1,60 @@
/*
PURPOSE:
(Custom log file writable by message_publish.)
ASSUMPTIONS AND LIMITATIONS:
(())
PROGRAMMERS:
(((Jackie Deans) (LinCom) (4/23) (--) (CACI))
*/
#ifndef MESSAGE_CUSTOM_FILE_HH
#define MESSAGE_CUSTOM_FILE_HH
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include "trick/MessageFile.hh"
namespace Trick {
/**
* MessageCustomFile writes all messages its level to the given file
*/
class MessageCustomFile : public MessageFile {
public:
/**
@brief The constructor.
*/
MessageCustomFile() ;
/**
@brief Output message to the file.
*/
virtual void update( unsigned int level , std::string header , std::string message );
/**
* @brief Get the level
*
*/
virtual int get_level();
virtual void set_name(std::string name);
virtual void set_file_name(std::string file_name);
int this_level;
protected:
static int level_counter;
// static std::vector<MessageCustomFile *>& all_instances();
} ;
}
#endif

View File

@ -0,0 +1,53 @@
/*
PURPOSE:
(Track custom log files.)
ASSUMPTIONS AND LIMITATIONS:
(())
PROGRAMMERS:
(((Jackie Deans) (CACI) (4/23) (--) ())
*/
#ifndef MESSAGE_CUSTOM_MANAGER_HH
#define MESSAGE_CUSTOM_MANAGER_HH
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include "trick/MessageCustomFile.hh"
#include "trick/MessageSubscriber.hh"
namespace Trick {
/**
* MessageCustomFile writes all messages its level to the given file
*/
class MessageCustomManager : public MessageSubscriber {
public:
/**
@brief The constructor.
*/
MessageCustomManager() ;
virtual ~MessageCustomManager() ;
virtual int open_custom_message_file(std::string file_name, std::string subscriber_name, int level = -1);
/**
@brief Output message to the file.
*/
virtual void update( unsigned int level , std::string header , std::string message );
int restart();
protected:
std::vector<MessageCustomFile *> custom_message_files;
} ;
}
#endif

View File

@ -32,7 +32,7 @@ namespace Trick {
public:
/** The file name of a file which the messages goes to. \n*/
std::string file_name ; /**< trick_units(--) trick_io(*i) */
std::string file_name ; /**< trick_units(--) trick_io(io) */
/**
@brief The constructor.
@ -47,7 +47,7 @@ namespace Trick {
/**
@brief Output message to the file.
*/
virtual void update( unsigned int level , std::string header , std::string message ) ;
virtual void update( unsigned int level , std::string header , std::string message );
/**
@brief Set a file name for a file which the messages received by this subscriber goes to.
@ -61,6 +61,9 @@ namespace Trick {
*/
virtual int init() ;
virtual int restart() ;
protected:
/** The output file stream. \n */
std::fstream out_stream ; /**< trick_io(**) */

View File

@ -0,0 +1,47 @@
/*
PURPOSE:
(Trick runtime simulation executive parameter definition.)
REFERENCE:
(((Bailey, R.W, and Paddock, E.J.) (Trick Simulation Environment)
(NASA:JSC #37943)
(JSC / Engineering Directorate / Automation and Robotics Division)
(June 1994) (--)))
ASSUMPTIONS AND LIMITATIONS:
((Only 64 levels of nested input data file inclusion.))
PROGRAMMERS:
(((Robert W. Bailey) (LinCom) (4/92) (--) (Realtime))
((Robert W. Bailey) (LinCom) (6/1/91) (Trick-CR-00000) (Initial Release)))
*/
#ifndef MESSAGE_HS_FILE_HH
#define MESSAGE_HS_FILE_HH
#include <string>
#include <iostream>
#include <fstream>
#include "trick/MessageFile.hh"
namespace Trick {
/**
* MessageHSFile writes all messages of levels 0-99 to the send_hs file
*/
class MessageHSFile : public MessageFile {
public:
/**
@brief The constructor.
*/
MessageHSFile() ;
/**
@brief Output message to the file.
*/
virtual void update( unsigned int level , std::string header , std::string message );
} ;
}
#endif

View File

@ -41,6 +41,7 @@ namespace Trick {
@brief The constructor.
*/
MessagePublisher() ;
virtual ~MessagePublisher();
/**
@brief Initialization job. Sets tics_per_sec and print format.
@ -66,7 +67,7 @@ namespace Trick {
@param message - the text of the message
@return always 0
*/
int publish(int level, std::string message) ;
virtual int publish(int level, std::string message) ;
/**
@brief gets the subscriber from the list

View File

@ -22,5 +22,7 @@
int message_subscribe( Trick::MessageSubscriber * in_ms ) ;
int message_unsubscribe( Trick::MessageSubscriber * in_ms ) ;
int open_custom_message_file(std::string file_name, std::string subscriber_name, int level = -1);
#endif

View File

@ -0,0 +1,13 @@
#ifndef MOCK_EXECUTIVE_HH
#define MOCK_EXECUTIVE_HH
#include "trick/Executive.hh"
#include <gmock/gmock.h>
class MockExecutive : public Trick::Executive {
public:
MOCK_METHOD0(get_time_tics, long long());
MOCK_METHOD0(get_sim_time, double());
};
#endif

View File

@ -0,0 +1,13 @@
#ifndef MOCK_INPUT_PROCESSOR_HH
#define MOCK_INPUT_PROCESSOR_HH
#include "trick/InputProcessor.hh"
#include <gmock/gmock.h>
class MockInputProcessor : public Trick::InputProcessor {
public:
MOCK_METHOD1(parse, int(std::string in_string));
};
#endif

View File

@ -0,0 +1,13 @@
#ifndef MOCK_MESSAGE_CUSTOM_MANAGER_HH
#define MOCK_MESSAGE_CUSTOM_MANAGER_HH
#include "trick/MessageCustomManager.hh"
#include <gmock/gmock.h>
class MockMessageCustomManager : public Trick::MessageCustomManager {
public:
MOCK_METHOD3(update, void(int level, std::string header, std::string message));
MOCK_METHOD3(open_custom_message_file, int(std::string file_name, std::string subscriber_name, int level));
};
#endif

View File

@ -0,0 +1,12 @@
#ifndef MOCK_MESSAGE_PUBLISHER_HH
#define MOCK_MESSAGE_PUBLISHER_HH
#include "trick/MessagePublisher.hh"
#include <gmock/gmock.h>
class MockMessagePublisher : public Trick::MessagePublisher {
public:
MOCK_METHOD2(publish, int(int level, std::string message));
};
#endif

View File

@ -0,0 +1,21 @@
#ifndef MOCK_REALTIME_SYNC_HH
#define MOCK_REALTIME_SYNC_HH
#include "trick/GetTimeOfDayClock.hh"
#include "trick/RealtimeSync.hh"
#include <gmock/gmock.h>
// This sucks but refactoring this is out of the scope for now
Trick::GetTimeOfDayClock& my_static_clock() {
static Trick::GetTimeOfDayClock clock;
return clock;
}
class MockRealtimeSync : public Trick::RealtimeSync {
public:
MockRealtimeSync() : RealtimeSync(&(my_static_clock())) {}
MOCK_METHOD0(is_active, bool());
};
#endif

View File

@ -27,6 +27,7 @@ class MockVariableServerSession : public Trick::VariableServerSession {
MOCK_METHOD0(copy_and_write_async, int());
// Accessor for the concrete version
int copy_and_write_async_concrete() { return Trick::VariableServerSession::copy_and_write_async(); }
};

View File

@ -256,6 +256,12 @@ namespace Trick {
*/
virtual int start_sleep_timer();
/**
@brief Return whether realtime is currently active
@return True if active, false otherwise
*/
virtual bool is_active();
} ;
} ;

View File

@ -1,3 +1,7 @@
/*
PURPOSE: (A wrapper for system calls to facilitate testing.)
*/
#ifndef __SYSTEM_INTERFACE__
#define __SYSTEM_INTERFACE__

View File

@ -50,6 +50,7 @@ namespace Trick {
int writeValueAscii( std::ostream& out ) const;
int writeValueBinary( std::ostream& out , bool byteswap = false) const;
int writeNameBinary( std::ostream& out, bool byteswap = false) const;
int writeNameLengthBinary( std::ostream& out, bool byteswap = false) const;
int writeSizeBinary( std::ostream& out, bool byteswap = false) const;
int writeTypeBinary( std::ostream& out, bool byteswap = false) const;

View File

@ -340,8 +340,6 @@ int var_set_freeze_frame_multiple(unsigned int mult) ;
int var_set_freeze_frame_offset(unsigned int offset) ;
int var_byteswap(bool on_off) ;
// int var_signal() ;
// int var_multicast(bool on_off) ;
int var_send_list_size() ;

View File

@ -359,6 +359,13 @@ namespace Trick {
*/
virtual int set_log_off() ;
/**
@brief @userdesc Command to set info messages.
@return always 0
*/
virtual int set_info_message(bool on) ;
/**
@brief Command to send the number of items in the var_add list.
The variable server sends a message indicator of "3", followed by the total number of variables being sent.
@ -412,6 +419,7 @@ namespace Trick {
virtual int var_exit();
private:
static int instance_counter;
pthread_mutex_t _copy_mutex; /**< trick_io(**) */
@ -440,6 +448,16 @@ namespace Trick {
virtual int get_freeze_frame_offset () const;
virtual bool get_enabled () const;
// Check settings and log to appropriate places
void log_received_message(const std::string& msg);
void log_connection_opened ();
bool is_log_open();
void open_session_log();
void write_to_session_log(const std::string& msg);
/** Value set in var_cycle command.\n */
double _update_rate ; /**< trick_io(**) */
@ -491,6 +509,12 @@ namespace Trick {
/** Toggle to turn on/off variable server logged messages to a playback file.\n */
bool _log ; /**< trick_io(**) */
/** Toggle to turn on/off debug info messages.\n */
bool _info_msg ;
/** Message stream number for the log file */
int _log_msg_stream;
/** Toggle to indicate var_pause commanded.\n */
bool _pause_cmd ; /**< trick_io(**) */
@ -504,6 +528,8 @@ namespace Trick {
/** Toggle to indicate var_exit commanded.\n */
bool _exit_cmd ; /**< trick_io(**) */
int _instance_num;
};
}

View File

@ -36,6 +36,9 @@
#include "trick/MessageCout.hh"
#include "trick/MessageThreadedCout.hh"
#include "trick/MessageFile.hh"
#include "trick/MessageHSFile.hh"
#include "trick/MessageCustomFile.hh"
#include "trick/MessageCustomManager.hh"
#include "trick/MessageLCout.hh"
#include "trick/MessagePublisher.hh"
#include "trick/MessageTCDevice.hh"

View File

@ -48,6 +48,9 @@ a replacement SimObject will create an uncompilable sim.
##include "trick/MessageThreadedCout.hh"
##include "trick/MessageLCout.hh"
##include "trick/MessageFile.hh"
##include "trick/MessageHSFile.hh"
##include "trick/MessageCustomFile.hh"
##include "trick/MessageCustomManager.hh"
##include "trick/MessageTCDevice.hh"
##include "trick/PlaybackFile.hh"
##include "trick/MemoryManager.hh"
@ -258,9 +261,10 @@ class MessageSimObject : public Trick::SimObject {
Trick::MessagePublisher mpublisher ;
Trick::MessageCout mcout ;
Trick::MessageThreadedCout mtcout ;
Trick::MessageFile mfile ;
Trick::MessageHSFile mfile ;
Trick::MessageTCDevice mdevice ;
Trick::PlaybackFile pfile ;
Trick::MessageCustomManager message_file_manager ;
MessageSimObject() {
@ -269,6 +273,7 @@ class MessageSimObject : public Trick::SimObject {
{TRK} ("default_data") mpublisher.subscribe(&mfile) ;
{TRK} ("default_data") mpublisher.subscribe(&mdevice) ;
{TRK} ("default_data") mpublisher.subscribe(&pfile) ;
{TRK} ("default_data") mpublisher.subscribe(&message_file_manager) ;
{TRK} ("default_data") mdevice.default_data() ;
{TRK} P1 ("initialization") mpublisher.init() ;
//{TRK} P1 ("initialization") mtcout.init() ;
@ -278,9 +283,9 @@ class MessageSimObject : public Trick::SimObject {
{TRK} ("exec_time_tic_changed") mpublisher.init() ;
{TRK} P1 ("restart") mdevice.restart() ;
{TRK} P1 ("restart") message_file_manager.restart() ;
{TRK} ("shutdown") mtcout.shutdown() ;
{TRK} ("shutdown") mdevice.shutdown() ;
}
private:

View File

@ -9,6 +9,7 @@ def main():
trick.real_time_enable()
trick.exec_set_software_frame(0.01)
# trick.set_var_server_info_msg_on()
trick.set_var_server_log_on()
hostname = trick.var_server_get_hostname()

View File

@ -904,6 +904,7 @@ TEST_F (VariableServerTest, Cycle) {
socket << command;
// Give it a cycle to update
socket.receive();
socket.receive();
double sim_time = parse_message_for_sim_time(socket.receive());
compare_cycle(num_cycles, sim_time);
};

View File

@ -35,7 +35,6 @@ class Socket {
_hostname = hostname;
_port = port;
int tries = 0;
_socket_fd = socket(AF_INET, mode, 0);
if (_socket_fd < 0) {
@ -58,7 +57,6 @@ class Socket {
return -1;
}
tries = 0;
int connection_status;
connection_status = connect(_socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
@ -76,7 +74,6 @@ class Socket {
_multicast_socket = true;
_hostname = hostname;
_port = port;
int tries = 0;
_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (_socket_fd < 0) {

View File

@ -54,6 +54,7 @@ int VSTest::default_vars() {
blocked_from_input = 500;
blocked_from_output = 1000;
return 0;
}
int VSTest::init() {

View File

@ -6,4 +6,4 @@ include ${TRICK_HOME}/share/trick/makefiles/Makefile.common
unexport TRICK_PYTHON_PATH
sim_test:
python3 trickops.py --quiet
python3 trickops.py

View File

@ -130,6 +130,8 @@ set( SS_SRC
MasterSlave/Slave
Message/MessageCout
Message/MessageFile
Message/MessageHSFile
Message/MessageCustomFile
Message/MessageLCout
Message/MessagePublisher
Message/MessageSubscriber

View File

@ -1,3 +1,5 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../../../share/trick/makefiles/Makefile.common
include ${TRICK_HOME}/share/trick/makefiles/Makefile.tricklib
-include Makefile_deps
TRICK_CXXFLAGS += -std=c++11

View File

@ -31,6 +31,8 @@ object_${TRICK_HOST_CPU}/Message_c_intf.o: Message_c_intf.cpp \
${TRICK_HOME}/include/trick/MessageSubscriber.hh \
${TRICK_HOME}/include/trick/MessageCout.hh \
${TRICK_HOME}/include/trick/MessageFile.hh \
${TRICK_HOME}/include/trick/MessageHSFile.hh \
${TRICK_HOME}/include/trick/MessageCustomFile.hh \
${TRICK_HOME}/include/trick/MessageTCDevice.hh \
${TRICK_HOME}/include/trick/ThreadBase.hh \
${TRICK_HOME}/include/trick/tc.h \

View File

@ -0,0 +1,46 @@
#include <iostream>
#include <unistd.h>
#include "trick/MessageCustomFile.hh"
#include "trick/Message_proto.hh"
int Trick::MessageCustomFile::level_counter = 200;
/**
@details
-# Initializes everything
*/
Trick::MessageCustomFile::MessageCustomFile() : this_level(level_counter++) {
}
/**
@details
-# If enabled and level is this file's level
-# Write the header and message to the file stream
-# Flush the stream
*/
void Trick::MessageCustomFile::update( unsigned int level , std::string header, std::string message ) {
if ( enabled && level == this_level ) {
out_stream << header << message ;
out_stream.flush() ;
}
}
int Trick::MessageCustomFile::get_level() {
return this_level;
}
void Trick::MessageCustomFile::set_name(std::string name) {
if (name == "") {
name = "CustomLog" + this_level;
}
this->name = name;
}
void Trick::MessageCustomFile::set_file_name(std::string file_name) {
this->file_name = file_name;
}

View File

@ -0,0 +1,58 @@
#include "trick/MessageCustomManager.hh"
#include "trick/Message_proto.hh"
#include "trick/memorymanager_c_intf.h"
Trick::MessageCustomManager * the_message_custom_manager ;
int open_custom_message_file(std::string file_name, std::string subscriber_name, int level) {
if (the_message_custom_manager == NULL) {
std::cout << "Problem: custom_message_manager not yet intantiated" << std::endl;
return -1;
}
return the_message_custom_manager->open_custom_message_file(file_name, subscriber_name, level);
}
/**
@brief The constructor.
*/
Trick::MessageCustomManager::MessageCustomManager() {
the_message_custom_manager = this;
}
Trick::MessageCustomManager::~MessageCustomManager() {
the_message_custom_manager = NULL;
for (Trick::MessageCustomFile * message_file : custom_message_files) {
TMM_delete_var_a(message_file);
}
}
int Trick::MessageCustomManager::open_custom_message_file(std::string file_name, std::string subscriber_name, int level) {
Trick::MessageCustomFile * new_message_file = (Trick::MessageCustomFile *) TMM_declare_var_s("Trick::MessageCustomFile");
new_message_file->set_file_name(file_name);
new_message_file->set_name(subscriber_name);
new_message_file->init();
custom_message_files.push_back(new_message_file);
return new_message_file->get_level();
}
/**
@brief Output message to the file.
*/
void Trick::MessageCustomManager::update( unsigned int level , std::string header , std::string message ) {
for (MessageCustomFile* message_file : custom_message_files) {
message_file->update(level, header, message);
}
}
int Trick::MessageCustomManager::restart( ) {
for (MessageCustomFile* message_file : custom_message_files) {
message_file->restart();
}
return 0;
}

View File

@ -10,12 +10,8 @@
-# Initializes everything
*/
Trick::MessageFile::MessageFile() {
enabled = 1 ;
color = 0 ;
file_name = "send_hs" ;
name = "file" ;
}
/**
@ -29,18 +25,6 @@ int Trick::MessageFile::set_file_name(std::string in_name) {
}
/**
@details
-# Deletes the current output file
-# Opens a new file with the name "file_name"
*/
int Trick::MessageFile::init() {
unlink((std::string(command_line_args_get_output_dir()) + "/" + file_name).c_str()) ;
out_stream.open((std::string(command_line_args_get_output_dir()) + "/" + file_name).c_str() , std::fstream::out | std::fstream::app ) ;
return(0) ;
}
/**
@details
-# If enabled and level < 100
@ -56,6 +40,23 @@ void Trick::MessageFile::update( unsigned int level , std::string header, std::s
}
/**
@details
-# Deletes the current output file
-# Opens a new file with the name "file_name"
*/
int Trick::MessageFile::init() {
unlink((std::string(command_line_args_get_output_dir()) + "/" + file_name).c_str()) ;
out_stream.open((std::string(command_line_args_get_output_dir()) + "/" + file_name).c_str() , std::fstream::out | std::fstream::app ) ;
return(0) ;
}
int Trick::MessageFile::restart() {
out_stream.open((std::string(command_line_args_get_output_dir()) + "/" + file_name).c_str() , std::fstream::out | std::fstream::app ) ;
return(0) ;
}
/**
@details
-# Close the file stream

View File

@ -0,0 +1,32 @@
#include <iostream>
#include <unistd.h>
#include "trick/MessageHSFile.hh"
#include "trick/command_line_protos.h"
/**
@details
-# Initializes everything
*/
Trick::MessageHSFile::MessageHSFile() {
name = "file";
file_name = "send_hs";
}
/**
@details
-# If enabled and level < 100
-# Write the header and message to the file stream
-# Flush the stream
*/
void Trick::MessageHSFile::update( unsigned int level , std::string header, std::string message ) {
if ( enabled && level < 100 ) {
out_stream << header << message ;
out_stream.flush() ;
}
}

View File

@ -25,6 +25,10 @@ Trick::MessagePublisher::MessagePublisher() {
}
Trick::MessagePublisher::~MessagePublisher() {
the_message_publisher = NULL;
}
void Trick::MessagePublisher::set_print_format() {
num_digits = (int)round(log10((double)tics_per_sec)) ;
snprintf(print_format, sizeof(print_format), "|L %%3d|%%s|%%s|%%s|T %%d|%%lld.%%0%dlld| ", num_digits) ;

View File

@ -6,6 +6,7 @@
#include "trick/MessagePublisher.hh"
#include "trick/MessageCout.hh"
#include "trick/MessageFile.hh"
#include "trick/MessageCustomFile.hh"
#include "trick/MessageTCDevice.hh"
#include "trick/message_proto.h"

View File

@ -502,3 +502,6 @@ int Trick::RealtimeSync::shutdown() {
return(0) ;
}
bool Trick::RealtimeSync::is_active() {
return active;
}

View File

@ -59,7 +59,7 @@ extern "C" int real_time_restart(long long ref_time ) {
*/
extern "C" int is_real_time() {
if ( the_rts != NULL ) {
return((int)(the_rts->active)) ;
return((int)(the_rts->is_active())) ;
}
return(0) ;
}

View File

@ -99,26 +99,26 @@ Trick::VariableReference::VariableReference(std::string var_name) : _staged(fals
if ( _var_info == NULL ) {
// TODO: ERROR LOGGER sendErrorMessage("Variable Server could not find variable %s.\n", var_name);
// PRINTF IS NOT AN ERROR LOGGER @me
printf("Variable Server could not find variable %s.\n", var_name.c_str());
message_publish(MSG_ERROR, "Variable Server could not find variable %s.\n", var_name.c_str());
_var_info = make_error_ref(var_name);
} else if ( _var_info->attr ) {
if ( _var_info->attr->type == TRICK_STRUCTURED ) {
// sendErrorMessage("Variable Server: var_add cant add \"%s\" because its a composite variable.\n", var_name);
printf("Variable Server: var_add cant add \"%s\" because its a composite variable.\n", var_name.c_str());
message_publish(MSG_ERROR, "Variable Server: var_add cant add \"%s\" because its a composite variable.\n", var_name.c_str());
free(_var_info);
_var_info = make_do_not_resolve_ref(var_name);
} else if ( _var_info->attr->type == TRICK_STL ) {
// sendErrorMessage("Variable Server: var_add cant add \"%s\" because its an STL variable.\n", var_name);
printf("Variable Server: var_add cant add \"%s\" because its an STL variable.\n", var_name.c_str());
message_publish(MSG_ERROR,"Variable Server: var_add cant add \"%s\" because its an STL variable.\n", var_name.c_str());
free(_var_info);
_var_info = make_do_not_resolve_ref(var_name);
}
} else {
// sendErrorMessage("Variable Server: BAD MOJO - Missing ATTRIBUTES.");
printf("Variable Server: BAD MOJO - Missing ATTRIBUTES.");
message_publish(MSG_ERROR, "Variable Server: BAD MOJO - Missing ATTRIBUTES.");
free(_var_info);
_var_info = make_error_ref(var_name);
@ -143,9 +143,8 @@ Trick::VariableReference::VariableReference(std::string var_name) : _staged(fals
} else {
// Unconstrained array
if ((_var_info->attr->num_index - _var_info->num_index) > 1 ) {
// TODO: ERROR LOGGER
printf("Variable Server Error: var_add(%s) requests more than one dimension of dynamic array.\n", _var_info->reference);
printf("Data is not contiguous so returned values are unpredictable.\n") ;
message_publish(MSG_ERROR, "Variable Server Error: var_add(%s) requests more than one dimension of dynamic array.\n", _var_info->reference);
message_publish(MSG_ERROR, "Data is not contiguous so returned values are unpredictable.\n") ;
}
if ( _var_info->attr->type == TRICK_CHARACTER ) {
_trick_type = TRICK_STRING ;
@ -622,18 +621,23 @@ int Trick::VariableReference::writeSizeBinary( std::ostream& out, bool byteswap
int Trick::VariableReference::writeNameBinary( std::ostream& out, bool byteswap ) const {
std::string name = getName();
out.write(name.c_str(), name.size());
int name_size = name.size();
return 0;
}
int Trick::VariableReference::writeNameLengthBinary( std::ostream& out, bool byteswap ) const {
int name_size = getName().size();
if (byteswap) {
name_size = trick_byteswap_int(name_size);
}
out.write(const_cast<const char *>(reinterpret_cast<char *>(&name_size)), sizeof(int));
out.write(name.c_str(), name.size());
return 0;
}
void Trick::VariableReference::byteswap_var (char * out, char * in) const {
byteswap_var(out, in, *this);
}

View File

@ -53,10 +53,16 @@ bool Trick::VariableServer::get_info_msg() {
void Trick::VariableServer::set_var_server_info_msg_on() {
info_msg = true;
for ( auto& session_it : var_server_sessions ) {
session_it.second->set_info_message(info_msg);
}
}
void Trick::VariableServer::set_var_server_info_msg_off() {
info_msg = false;
for ( auto& session_it : var_server_sessions ) {
session_it.second->set_info_message(info_msg);
}
}
bool Trick::VariableServer::get_log() {

View File

@ -206,19 +206,19 @@ int Trick::VariableServerListenThread::restart() {
_requested_source_address.clear() ;
}
printf("variable server restart user_port requested set %s:%d\n",_requested_source_address.c_str(), _requested_port);
message_publish(MSG_INFO, "variable server restart user_port requested set %s:%d\n",_requested_source_address.c_str(), _requested_port);
_listener->disconnect();
ret = _listener->initialize(_requested_source_address, _requested_port);
if (ret != TC_SUCCESS) {
if (ret != 0) {
message_publish(MSG_ERROR, "ERROR: Could not establish listen port %d for Variable Server. Aborting.\n", _requested_port);
return (-1);
}
} else {
// Otherwise, just ask the listener what port it's using
_listener->checkSocket();
printf("restart variable server message port = %d\n", _listener->getPort());
message_publish(MSG_INFO, "restart variable server message port = %d\n", _listener->getPort());
}
initializeMulticast();
@ -233,14 +233,12 @@ void Trick::VariableServerListenThread::initializeMulticast() {
}
void Trick::VariableServerListenThread::pause_listening() {
// pthread_mutex_lock(&_restart_pause) ;
force_thread_to_pause();
}
void Trick::VariableServerListenThread::restart_listening() {
_listener->restart();
unpause_thread();
// pthread_mutex_unlock(&_restart_pause) ;
}
void Trick::VariableServerListenThread::dump( std::ostream & oss ) {

View File

@ -1,15 +1,19 @@
#include "trick/VariableServerSession.hh"
#include "trick/TrickConstant.hh"
#include "trick/exec_proto.h"
#include "trick/Message_proto.hh"
#include "trick/message_proto.h"
#include "trick/input_processor_proto.h"
#include "trick/realtimesync_proto.h"
int Trick::VariableServerSession::instance_counter = 0;
Trick::VariableServerSession::VariableServerSession() {
_debug = 0;
_enabled = true ;
_log = false ;
_log_msg_stream = -1;
_info_msg = false;
_copy_mode = VS_COPY_ASYNC ;
_write_mode = VS_WRITE_ASYNC ;
_frame_multiple = 1 ;
@ -35,6 +39,8 @@ Trick::VariableServerSession::VariableServerSession() {
_exit_cmd = false;
_pause_cmd = false;
_instance_num = instance_counter++;
pthread_mutex_init(&_copy_mutex, NULL);
}
@ -47,6 +53,16 @@ Trick::VariableServerSession::~VariableServerSession() {
void Trick::VariableServerSession::set_connection(ClientConnection * conn) {
_connection = conn;
log_connection_opened();
}
bool Trick::VariableServerSession::is_log_open() {
return _log_msg_stream != -1;
}
void Trick::VariableServerSession::open_session_log() {
std::string name = "VSSession" + std::to_string(_instance_num);
_log_msg_stream = open_custom_message_file(name + ".log", name);
}
@ -103,11 +119,41 @@ long long Trick::VariableServerSession::get_freeze_next_tics() const {
return _freeze_next_tics ;
}
void Trick::VariableServerSession::log_connection_opened() {
if (_log) {
if (!is_log_open()) {
open_session_log();
}
message_publish(_log_msg_stream, "Variable Server Session started with %s:%d\n", _connection->getClientHostname().c_str(), _connection->getClientPort());
}
}
void Trick::VariableServerSession::log_received_message(const std::string& msg) {
if (_log) {
message_publish(MSG_PLAYBACK, "tag=<%s> time=%f %s", _connection->getClientTag().c_str(), exec_get_sim_time(), msg.c_str());
if (!is_log_open()) open_session_log();
message_publish(_log_msg_stream, "tag=<%s> time=%f %s", _connection->getClientTag().c_str(), exec_get_sim_time(), msg.c_str());
}
if (_debug >= 3) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server received bytes = msg_len = %d\n", _connection, _connection->getClientTag().c_str(), msg.size());
}
if (_debug >= 1 || _info_msg) {
message_publish(MSG_DEBUG, "tag=<%s> time=%f %s", _connection->getClientTag().c_str(), exec_get_sim_time(), msg.c_str());
}
}
int Trick::VariableServerSession::handle_message() {
std::string received_message;
int nbytes = _connection->read(received_message);
if (nbytes > 0) {
log_received_message(received_message);
ip_parse(received_message.c_str()); /* returns 0 if no parsing error */
}
@ -125,6 +171,11 @@ Trick::VariableReference * Trick::VariableServerSession::find_session_variable(s
return NULL;
}
int Trick::VariableServerSession::set_info_message(bool on) {
_info_msg = on;
return 0;
}
double Trick::VariableServerSession::get_update_rate() const {
return _update_rate;
}

View File

@ -39,6 +39,15 @@ void * Trick::VariableServerSessionThread::thread_body() {
thread_shutdown();
}
// if log is set on for variable server (e.g., in input file), turn log on for each client
if (_vs->get_log()) {
_session->set_log_on();
}
if (_vs->get_info_msg()) {
_session->set_info_message(true);
}
// Give the initialized connection to the session
// Don't touch the connection anymore until we shut them both down
_session->set_connection(_connection);
@ -50,11 +59,6 @@ void * Trick::VariableServerSessionThread::thread_body() {
pthread_cond_signal(&_connection_status_cv);
pthread_mutex_unlock(&_connection_status_mutex);
// if log is set on for variable server (e.g., in input file), turn log on for each client
if (_vs->get_log()) {
_session->set_log_on();
}
try {
while (1) {
// Shutdown here if it's time

View File

@ -117,7 +117,7 @@ int Trick::VariableServerSession::var_exists(std::string in_name) {
buf1[4] = (error==false);
if (_debug >= 2) {
// message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending 1 binary byte\n", &_connection, _connection.client_tag);
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending 1 binary byte\n", _connection, _connection->getClientTag().c_str());
}
_connection->write(buf1, 5);
@ -125,7 +125,7 @@ int Trick::VariableServerSession::var_exists(std::string in_name) {
/* send ascii "1" or "0" */
sprintf(buf1, "%d\t%d\n", VS_VAR_EXISTS, (error==false));
if (_debug >= 2) {
// message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending:\n%s\n", &_connection, _connection.client_tag, buf1) ;
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending:\n%s\n", _connection, _connection->getClientTag().c_str(), buf1) ;
}
std::string write_string(buf1);
if (write_string.length() != strlen(buf1)) {
@ -312,7 +312,7 @@ int Trick::VariableServerSession::send_list_size() {
return 0 ;
}
int Trick::VariableServerSession::transmit_file(std::string sie_file) {
int Trick::VariableServerSession::transmit_file(std::string filename) {
const unsigned int packet_size = 4095 ;
FILE * fp ;
unsigned int file_size ;
@ -322,11 +322,11 @@ int Trick::VariableServerSession::transmit_file(std::string sie_file) {
int ret ;
if (_debug >= 2) {
message_publish(MSG_DEBUG,"%p tag=<%s> var_server opening %s.\n", _connection, _connection->getClientTag().c_str(), sie_file.c_str()) ;
message_publish(MSG_DEBUG,"%p tag=<%s> var_server opening %s.\n", _connection, _connection->getClientTag().c_str(), filename.c_str()) ;
}
if ((fp = fopen(sie_file.c_str() , "r")) == NULL ) {
message_publish(MSG_ERROR,"Variable Server Error: Cannot open %s.\n", sie_file.c_str()) ;
if ((fp = fopen(filename.c_str() , "r")) == NULL ) {
message_publish(MSG_ERROR,"Variable Server Error: Cannot open %s.\n", filename.c_str()) ;
sprintf(buffer, "%d\t-1\n", VS_SIE_RESOURCE) ;
std::string message(buffer);
_connection->write(message);
@ -352,7 +352,7 @@ int Trick::VariableServerSession::transmit_file(std::string sie_file) {
message.resize(bytes_read);
ret = _connection->write(message);
if (ret != (int)bytes_read) {
message_publish(MSG_ERROR,"Variable Server Error: Failed to send SIE file. Bytes read: %d Bytes sent: %d\n", bytes_read, ret) ;
message_publish(MSG_ERROR,"Variable Server Error: Failed to send file. Bytes read: %d Bytes sent: %d\n", bytes_read, ret) ;
return(-1);
}
current_size += bytes_read ;

View File

@ -18,19 +18,24 @@ PROGRAMMERS: (((Alex Lin) (NASA) (8/06) (--)))
#define MAX_MSG_LEN 8192
int Trick::VariableServerSession::write_binary_data(const std::vector<VariableReference *>& given_vars, VS_MESSAGE_TYPE message_type) {
typedef std::vector<VariableReference *> VarList;
typedef std::pair<int,VarList> MessageData;
// Some constants to make size calculations more readable
static const int header_size = 12;
static const int sizeof_size = 4;
static const int type_size = 4;
std::vector<std::pair<int,int>> message_sizes_and_num_vars;
std::vector<MessageData> message_sizes_and_vars;
// Calculate how many messages and how many vars in each
// Calculate how many messages and what vars in each
int total_size = header_size;
int num_vars = 0;
VarList curr_message_vars;
for (int i = 0; i < given_vars.size(); i++) {
const VariableReference * var = given_vars[i];
VariableReference * var = given_vars[i];
int total_var_size = 0;
if (!_binary_data_nonames) {
total_var_size += sizeof_size;
@ -41,29 +46,43 @@ int Trick::VariableServerSession::write_binary_data(const std::vector<VariableRe
total_var_size += sizeof_size;
total_var_size += var->getSizeBinary();
// If this variable won't fit in the current message, truncate the message and plan to put this var in a new one
if (total_size + total_var_size > MAX_MSG_LEN) {
message_sizes_and_num_vars.push_back(std::pair<int,int>(total_size, num_vars));
total_size = header_size;
num_vars = 0;
}
total_size += total_var_size;
num_vars++;
// Check if this variable will fit in a message at all
if (header_size + total_var_size > MAX_MSG_LEN) {
message_publish(MSG_WARNING, "tag=<%s> Variable Server buffer[%d] too small (need %d) for symbol %s, SKIPPING IT.\n",
_connection->getClientTag().c_str(), MAX_MSG_LEN, header_size + total_var_size, var->getName().c_str());
continue;
}
message_sizes_and_num_vars.push_back(std::pair<int,int>(total_size, num_vars));
// If this variable won't fit in the current message, truncate the message and plan to put this var in a new one
if (total_size + total_var_size > MAX_MSG_LEN) {
message_sizes_and_vars.emplace_back(MessageData(total_size, curr_message_vars));
if (_debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server buffer[%d] too small (need %d), sending multiple binary packets.\n",
_connection, _connection->getClientTag().c_str(), MAX_MSG_LEN, total_size + total_var_size);
}
total_size = header_size;
curr_message_vars.clear();
}
total_size += total_var_size;
curr_message_vars.push_back(var);
}
message_sizes_and_vars.emplace_back(MessageData(total_size, curr_message_vars));
// Now write out all of these messages
int var_index = 0;
for (std::pair<int,int> message_info : message_sizes_and_num_vars) {
for (const auto& message_info : message_sizes_and_vars) {
int curr_message_size = message_info.first;
int curr_message_num_vars = message_info.second;
VarList curr_message_vars = message_info.second;
std::stringstream stream;
int written_message_type = message_type;
int written_header_size = curr_message_size - 4;
int written_num_vars = curr_message_num_vars;
int written_num_vars = curr_message_vars.size();
if (_byteswap) {
written_message_type = trick_byteswap_int(written_message_type);
@ -71,22 +90,33 @@ int Trick::VariableServerSession::write_binary_data(const std::vector<VariableRe
written_num_vars = trick_byteswap_int(written_num_vars);
}
// Header format:
// <message_indicator><message_size><num_vars>
// Write the header first
stream.write((char *)(&written_message_type), sizeof(int));
stream.write((char *)(&written_header_size), sizeof(int));
stream.write ((char *)(&written_num_vars), sizeof(int));
stream.write((char *)(&written_num_vars), sizeof(int));
// Write variables next
for (int i = var_index; i < var_index + curr_message_num_vars; i++) {
VariableReference * var = given_vars[i];
for (VariableReference * var : curr_message_vars) {
// Each variable is formatted as:
// <namelength><name><type><size><value
// namelength and name are omitted if _binary_data_nonames is on
if (!_binary_data_nonames) {
var->writeNameLengthBinary(stream, _byteswap);
var->writeNameBinary(stream, _byteswap);
}
var->writeTypeBinary(stream, _byteswap);
var->writeSizeBinary(stream, _byteswap);
var->writeValueBinary(stream, _byteswap);
}
var_index += curr_message_num_vars;
if (_debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %u binary bytes containing %d variables.\n",
_connection, _connection->getClientTag().c_str(), curr_message_size, curr_message_vars.size());
}
// Send it out!
char write_buf[MAX_MSG_LEN];
@ -109,23 +139,39 @@ int Trick::VariableServerSession::write_ascii_data(const std::vector<VariableRef
message_stream << "\t";
std::stringstream var_stream;
if (given_vars[i]->writeValueAscii(var_stream) == -1) {
// If one of the values isn't ready, we need to abort the write
return 0;
}
given_vars[i]->writeValueAscii(var_stream);
// Unfortunately, there isn't a good way to get the size of the buffer without putting it into a string
std::string var_string = var_stream.str();
int var_size = var_string.size();
// Check if this single variable is too big, truncate if so
if (var_size + 2 > MAX_MSG_LEN) {
message_publish(MSG_WARNING, "tag=<%s> Variable Server buffer[%d] too small for symbol %s, TRUNCATED IT.\n",
_connection->getClientTag().c_str(), MAX_MSG_LEN, given_vars[i]->getName().c_str());
var_string = var_string.substr(0, MAX_MSG_LEN-2);
var_size = var_string.size();
}
// Check that there's enough room for the next variable, tab character, and possible newline
if (message_size + var_size + 2 > MAX_MSG_LEN) {
// Write out an incomplete message
std::string message = message_stream.str();
if (_debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server buffer[%d] too small (need %d), sending multiple ascii packets.\n",
_connection, _connection->getClientTag().c_str(), MAX_MSG_LEN, message_size + var_size + 2);
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sedning %d ascii bytes:\n%s\n",
_connection, _connection->getClientTag().c_str(), message_size, message.c_str());
}
int result = _connection->write(message);
if (result < 0)
if (result < 0) {
return result;
}
// Clear out the message stream
message_stream.str("");
@ -141,6 +187,12 @@ int Trick::VariableServerSession::write_ascii_data(const std::vector<VariableRef
// End with newline
message_stream << '\n';
std::string message = message_stream.str();
if (_debug >= 2) {
message_publish(MSG_DEBUG, "%p tag=<%s> var_server sedning %d ascii bytes:\n%s\n",
_connection, _connection->getClientTag().c_str(), message.size(), message.c_str());
}
int result = _connection->write(message);
return result;
}

View File

@ -15,6 +15,7 @@ int Trick::VariableServer::create_tcp_socket(const char * address, unsigned shor
int status = listener->initialize(address, in_port);
if (status != 0) {
message_publish(MSG_ERROR, "ERROR: Could not establish additional listen port at address %s and port %d for Variable Server.\n", address, in_port);
delete listener;
return 0;
}
@ -40,6 +41,7 @@ int Trick::VariableServer::create_udp_socket(const char * address, unsigned shor
UDPConnection * udp_conn = new UDPConnection();
int status = udp_conn->initialize(address, in_port);
if ( status != 0 ) {
message_publish(MSG_ERROR, "ERROR: Could not establish UDP port at address %s and port %d for Variable Server.\n", address, in_port);
delete udp_conn;
return 0;
}
@ -63,11 +65,17 @@ int Trick::VariableServer::create_multicast_socket(const char * mcast_address, c
// Multicast sockets are created without a listen thread, and represent only 1 session
// Create a VariableServerSessionThread to manage this session
if (mcast_address == NULL || mcast_address[0] == '\0') {
message_publish(MSG_ERROR, "Multicast address must be defined.\n");
return -1;
}
MulticastGroup * multicast = new MulticastGroup();
message_publish(MSG_INFO, "Created UDP variable server %s: %d\n", address, in_port);
int status = multicast->initialize_with_receiving(address, mcast_address, in_port);
if ( status != 0 ) {
message_publish(MSG_ERROR, "ERROR: Could not establish Multicast port at address %s and port %d for Variable Server.\n", address, in_port);
delete multicast;
return 0;
}

View File

@ -160,7 +160,7 @@ TEST_F(VariableReference_test, writeValueAscii_wide_char) {
EXPECT_EQ(ssb.str(), "jackiebutwider");
}
TEST_F(VariableReference_test, writeValueAscii_wide_char_unconstrained) {
TEST_F(VariableReference_test, DISABLED_writeValueAscii_wide_char_unconstrained) {
TestObject obj;
obj.wchar_str = (wchar_t *) malloc (sizeof(wchar_t) * 7);
for (int i = 0; i < 6; i++) {

View File

@ -140,12 +140,36 @@ TEST_F(VariableReference_test, writeNameBinary) {
ref.writeNameBinary(ss);
// ASSERT
char * actual_bytes = (char *) malloc (sizeof(int) + ref.getName().size());
ss.read(actual_bytes, sizeof(int) + 6);
unsigned char expected_bytes[sizeof(int) + 6] = {0x06, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61};
char * actual_bytes = (char *) malloc (ref.getName().size());
ss.read(actual_bytes, 6);
unsigned char expected_bytes[6] = {0x74, 0x65, 0x73, 0x74, 0x5f, 0x61};
// ASSERT
for (int i = 0; i < sizeof(int) + ref.getName().size(); i++) {
for (int i = 0; i < ref.getName().size(); i++) {
EXPECT_EQ(static_cast<unsigned char>(actual_bytes[i]), expected_bytes[i]);
}
}
TEST_F(VariableReference_test, writeNameLengthBinary) {
// ARRANGE
// Create a variable to make a reference for
std::string test_a = "abcdef";
(void) memmgr->declare_extern_var(&test_a, "std::string test_a");
Trick::VariableReference ref("test_a");
std::stringstream ss;
// ACT
ref.stageValue();
ref.prepareForWrite();
ref.writeNameLengthBinary(ss);
// ASSERT
char * actual_bytes = (char *) malloc (sizeof(int));
ss.read(actual_bytes, sizeof(int));
unsigned char expected_bytes[sizeof(int)] = {0x06, 0x00, 0x00, 0x00};
// ASSERT
for (int i = 0; i < sizeof(int); i++) {
EXPECT_EQ(static_cast<unsigned char>(actual_bytes[i]), expected_bytes[i]);
}
}

View File

@ -5,15 +5,20 @@ PURPOSE: ( Tests for the VariableServerListenThread class )
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "trick/Executive.hh"
#include "trick/CommandLineArguments.hh"
#include "trick/VariableServer.hh"
#include "trick/message_type.h"
#include "trick/Mock/MockExecutive.hh"
#include "trick/Mock/MockMessagePublisher.hh"
#include "trick/Mock/MockTCPClientListener.hh"
#include "trick/Mock/MockTCPConnection.hh"
#include "trick/Mock/MockMulticastGroup.hh"
#include "trick/VariableServerListenThread.hh"
#include "MockTCPClientListener.hh"
#include "MockTCPConnection.hh"
#include "MockMulticastGroup.hh"
using ::testing::Return;
using ::testing::_;
@ -26,20 +31,19 @@ using ::testing::AtLeast;
class VariableServerListenThread_test : public ::testing::Test {
protected:
// Static global dependencies that I would like to eventually mock out
Trick::Executive * executive;
Trick::CommandLineArguments * cmd_args;
Trick::VariableServer * varserver;
Trick::CommandLineArguments cmd_args;
Trick::VariableServer varserver;
// Static global dependencies that I have mocked out
MockExecutive executive;
MockMessagePublisher message_publisher;
// Listener
MockTCPClientListener * listener;
MockMulticastGroup * mcast;
VariableServerListenThread_test() {
// Set up dependencies that haven't been broken
executive = new Trick::Executive;
cmd_args = new Trick::CommandLineArguments;
varserver = new Trick::VariableServer;
Trick::VariableServerSessionThread::set_vs_ptr(varserver);
Trick::VariableServerSessionThread::set_vs_ptr(&varserver);
// Set up mocks
listener = new MockTCPClientListener;
@ -47,9 +51,6 @@ class VariableServerListenThread_test : public ::testing::Test {
}
~VariableServerListenThread_test() {
delete executive;
delete cmd_args;
delete varserver;
}
void SetUp() {}
@ -159,6 +160,8 @@ TEST_F(VariableServerListenThread_test, check_and_move_listen_device_init_fails)
EXPECT_CALL(*listener, initialize(_, _))
.WillOnce(Return(1));
EXPECT_CALL(message_publisher, publish(MSG_ERROR, _));
// ACT
int status = listen_thread.check_and_move_listen_device();
@ -316,7 +319,9 @@ TEST_F(VariableServerListenThread_test, accept_connection) {
// ACT
listen_thread.create_thread();
listen_thread.dump(std::cout);
std::stringstream stream;
listen_thread.dump(stream);
ASSERT_TRUE(stream.str().size() > 0);
sleep(3);
@ -385,6 +390,8 @@ TEST_F(VariableServerListenThread_test, restart_fails) {
EXPECT_CALL(*listener, disconnect());
EXPECT_CALL(message_publisher, publish(MSG_ERROR, _));
EXPECT_CALL(message_publisher, publish(MSG_INFO, _));
// ACT
// ASSERT

View File

@ -7,15 +7,14 @@ PURPOSE: ( Tests for the VariableServerSessionThread class )
#include <stdexcept>
#include "trick/VariableServer.hh"
#include "trick/RealtimeSync.hh"
#include "trick/GetTimeOfDayClock.hh"
#include "trick/ITimer.hh"
#include "trick/ExecutiveException.hh"
#include "trick/message_type.h"
#include "trick/VariableServerSessionThread.hh"
#include "MockVariableServerSession.hh"
#include "MockClientConnection.hh"
#include "trick/Mock/MockMessagePublisher.hh"
#include "trick/Mock/MockVariableServerSession.hh"
#include "trick/Mock/MockClientConnection.hh"
using ::testing::Return;
using ::testing::_;
@ -60,20 +59,17 @@ void setup_default_session_mocks (MockVariableServerSession * session, bool comm
*/
class VariableServerSessionThread_test : public ::testing::Test {
protected:
// Static global dependencies that I would like to eventually mock out
Trick::VariableServer * varserver;
Trick::RealtimeSync * realtime_sync;
Trick::GetTimeOfDayClock clock;
Trick::ITimer timer;
MockClientConnection connection;
NiceMock<MockVariableServerSession> * session;
MockMessagePublisher message_publisher;
VariableServerSessionThread_test() {
// Set up dependencies that haven't been broken
varserver = new Trick::VariableServer;
Trick::VariableServerSessionThread::set_vs_ptr(varserver);
realtime_sync = new Trick::RealtimeSync(&clock, &timer);
// Set up mocks
session = new NiceMock<MockVariableServerSession>;
@ -83,7 +79,6 @@ class VariableServerSessionThread_test : public ::testing::Test {
~VariableServerSessionThread_test() {
delete varserver;
delete realtime_sync;
}
void SetUp() {}
@ -216,10 +211,6 @@ TEST_F(VariableServerSessionThread_test, exit_commanded) {
Trick::ConnectionStatus status = vst->wait_for_accept();
ASSERT_EQ(status, Trick::ConnectionStatus::CONNECTION_SUCCESS);
// Confirm that the session has been created
Trick::VariableServerSession * vs_session = varserver->get_session(id);
ASSERT_TRUE(vs_session == session);
// Runs for a few loops, then exits
// Thread should shut down
@ -281,10 +272,6 @@ TEST_F(VariableServerSessionThread_test, turn_session_log_on) {
Trick::ConnectionStatus status = vst->wait_for_accept();
ASSERT_EQ(status, Trick::ConnectionStatus::CONNECTION_SUCCESS);
// Confirm that the session has been created
Trick::VariableServerSession * vs_session = varserver->get_session(id);
ASSERT_TRUE(vs_session == session);
// Thread should shut down
vst->join_thread();
@ -308,16 +295,14 @@ TEST_F(VariableServerSessionThread_test, throw_trick_executive_exception) {
EXPECT_CALL(*session, handle_message())
.WillOnce(Throw(Trick::ExecutiveException(-1, __FILE__, __LINE__, "Trick::ExecutiveException Error message for testing")));
EXPECT_CALL(message_publisher, publish(MSG_ERROR, _));
// ACT
vst->create_thread();
pthread_t id = vst->get_pthread_id();
Trick::ConnectionStatus status = vst->wait_for_accept();
ASSERT_EQ(status, Trick::ConnectionStatus::CONNECTION_SUCCESS);
// Confirm that the session has been created
Trick::VariableServerSession * vs_session = varserver->get_session(id);
ASSERT_TRUE(vs_session == session);
// Thread should shut down
vst->join_thread();
@ -340,6 +325,8 @@ TEST_F(VariableServerSessionThread_test, throw_exception) {
EXPECT_CALL(*session, handle_message())
.WillOnce(Throw(std::logic_error("Error message for testing")));
EXPECT_CALL(message_publisher, publish(MSG_ERROR, _));
// ACT
vst->create_thread();

View File

@ -13,15 +13,19 @@ PURPOSE: ( Tests for the VariableServerSession class )
#include "trick/MemoryManager.hh"
#include "trick/UdUnits.hh"
#include "trick/RealtimeSync.hh"
#include "trick/GetTimeOfDayClock.hh"
#include "trick/ITimer.hh"
#include "trick/message_type.h"
#include "trick/VariableServerSession.hh"
#include "trick/var_binary_parser.hh"
#include "MockClientConnection.hh"
#include "MockVariableServerSession.hh"
#include "trick/Mock/MockExecutive.hh"
#include "trick/Mock/MockRealtimeSync.hh"
#include "trick/Mock/MockMessagePublisher.hh"
#include "trick/Mock/MockMessageCustomManager.hh"
#include "trick/Mock/MockInputProcessor.hh"
#include "trick/Mock/MockClientConnection.hh"
#include "trick/Mock/MockVariableServerSession.hh"
@ -31,6 +35,9 @@ using ::testing::Truly;
using ::testing::Args;
using ::testing::Return;
using ::testing::Invoke;
using ::testing::DoAll;
using ::testing::SetArgReferee;
/*
@ -38,27 +45,24 @@ using ::testing::Invoke;
*/
class VariableServerSession_test : public ::testing::Test {
protected:
Trick::MemoryManager *memmgr;
Trick::UdUnits * udunits;
Trick::RealtimeSync * realtime_sync;
Trick::GetTimeOfDayClock clock;
Trick::ITimer timer;
// MemoryManager isn't actually a dependency, VariableReference is
// But using the memory manage is much easier than mocking VariableReference all the way
// Which is bad design @me
// shame
Trick::MemoryManager memmgr;
// Dependencies
MockRealtimeSync realtime_sync;
MockExecutive executive;
MockMessagePublisher message_publisher;
MockMessageCustomManager message_custom;
MockInputProcessor input_processor;
MockClientConnection connection;
VariableServerSession_test() {
memmgr = new Trick::MemoryManager;
udunits = new Trick::UdUnits;
realtime_sync = new Trick::RealtimeSync(&clock, &timer);
VariableServerSession_test() {}
udunits->read_default_xml();
}
~VariableServerSession_test() {
delete memmgr;
delete realtime_sync;
}
~VariableServerSession_test() {}
void SetUp() {}
void TearDown() {}
@ -69,9 +73,9 @@ TEST_F(VariableServerSession_test, toString) {
int a = 5;
double b = 6;
std::string c = "Hello";
(void) memmgr->declare_extern_var(&a, "int a");
(void) memmgr->declare_extern_var(&b, "double b");
(void) memmgr->declare_extern_var(&c, "std::string c");
(void) memmgr.declare_extern_var(&a, "int a");
(void) memmgr.declare_extern_var(&b, "double b");
(void) memmgr.declare_extern_var(&c, "std::string c");
Trick::VariableServerSession session;
@ -132,7 +136,7 @@ TEST_F(VariableServerSession_test, large_message_ascii) {
}
// Set it up with the memory manager
(void) memmgr->declare_extern_var(&big_arr, "int big_arr[4000]");
(void) memmgr.declare_extern_var(&big_arr, "int big_arr[4000]");
// Create references for all of them
std::vector <Trick::VariableReference *> vars;
@ -196,7 +200,7 @@ TEST_F(VariableServerSession_test, large_message_ascii) {
ASSERT_EQ(val_counter, big_arr_size);
}
TEST_F(VariableServerSession_test, DISABLED_large_message_binary) {
TEST_F(VariableServerSession_test, large_message_binary) {
// ARRANGE
Trick::VariableServerSession session;
session.set_connection(&connection);
@ -211,7 +215,7 @@ TEST_F(VariableServerSession_test, DISABLED_large_message_binary) {
}
// Set it up with the memory manager
(void) memmgr->declare_extern_var(&big_arr, "int big_arr[4000]");
(void) memmgr.declare_extern_var(&big_arr, "int big_arr[4000]");
// Create references for all of them
std::vector <Trick::VariableReference *> vars;
@ -273,6 +277,120 @@ TEST_F(VariableServerSession_test, DISABLED_large_message_binary) {
}
}
TEST_F(VariableServerSession_test, log_on) {
// ARRANGE
int fake_logstream = 200;
Trick::VariableServerSession session;
session.set_connection(&connection);
// Expect the per-session logfile to be opened
EXPECT_CALL(message_custom, open_custom_message_file(_, _, _))
.WillOnce(Return(fake_logstream));
// Expect a write to the log via message_publish
EXPECT_CALL(message_publisher, publish(MSG_PLAYBACK,_));
EXPECT_CALL(message_publisher, publish(fake_logstream,_));
// Just get whatever from the client
EXPECT_CALL(connection, read(_, _))
.WillOnce(DoAll(SetArgReferee<0>("some_python_command"), Return(10)));
EXPECT_CALL(connection, getClientTag())
.WillRepeatedly(Return("ClientTag"));
EXPECT_CALL(input_processor, parse(_));
// ACT
session.set_log_on();
session.handle_message();
// ASSERT
}
TEST_F(VariableServerSession_test, no_log_by_default) {
// ARRANGE
Trick::VariableServerSession session;
session.set_connection(&connection);
// Should not get any write to the log
EXPECT_CALL(message_publisher, publish(MSG_PLAYBACK,_))
.Times(0);
// Just get whatever from the client
EXPECT_CALL(connection, read(_, _))
.WillOnce(DoAll(SetArgReferee<0>("some_python_command"), Return(10)));
EXPECT_CALL(input_processor, parse(_));
// ACT
session.handle_message();
// ASSERT
}
TEST_F(VariableServerSession_test, info_msg_on) {
// ARRANGE
Trick::VariableServerSession session;
session.set_connection(&connection);
// Expect a write to info message_publish
EXPECT_CALL(message_publisher, publish(MSG_DEBUG,_));
// Just get whatever from the client
EXPECT_CALL(connection, read(_, _))
.WillOnce(DoAll(SetArgReferee<0>("some_python_command"), Return(10)));
EXPECT_CALL(connection, getClientTag())
.WillOnce(Return("ClientTag"));
EXPECT_CALL(input_processor, parse(_));
// ACT
session.set_info_message(true);
session.handle_message();
// ASSERT
}
TEST_F(VariableServerSession_test, info_msg_off_by_default) {
// ARRANGE
Trick::VariableServerSession session;
session.set_connection(&connection);
// Expect no write to info message_publish
EXPECT_CALL(message_publisher, publish(MSG_DEBUG,_))
.Times(0);
// Just get whatever from the client
EXPECT_CALL(connection, read(_, _))
.WillOnce(DoAll(SetArgReferee<0>("some_python_command"), Return(10)));
EXPECT_CALL(input_processor, parse(_));
// ACT
session.handle_message();
// ASSERT
}
TEST_F(VariableServerSession_test, debug_on) {
// ARRANGE
Trick::VariableServerSession session;
session.set_connection(&connection);
// Expect 2 writes to info message_publish
EXPECT_CALL(message_publisher, publish(MSG_DEBUG,_))
.Times(2);
// Just get whatever from the client
EXPECT_CALL(connection, read(_, _))
.WillOnce(DoAll(SetArgReferee<0>("some_python_command"), Return(10)));
EXPECT_CALL(input_processor, parse(_));
EXPECT_CALL(connection, getClientTag())
.WillRepeatedly(Return("ClientTag"));
// ACT
session.var_debug(3);
session.handle_message();
// ASSERT
}
/**************************************************************************/
/* Mode tests */
/**************************************************************************/
void setup_partial_session_mock(MockVariableServerSession& session) {
EXPECT_CALL(session, copy_and_write_async())
@ -372,10 +490,11 @@ TEST_F(VariableServerSession_test, copy_async_no_copy_or_write) {
// Copy async, write when copied, not paused
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
// Copy and write should be called
// Copy and write should not be called
EXPECT_CALL(session, copy_sim_data())
.Times(0);
@ -400,7 +519,8 @@ TEST_F(VariableServerSession_test, copy_async_non_realtime) {
// Copy async, write async, paused
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = false;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(false));
// Copy and write should be called
EXPECT_CALL(session, copy_sim_data())
@ -501,7 +621,8 @@ TEST_F(VariableServerSession_test, copy_and_write_top_copy_top_write_async) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_ASYNC, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_frame_multiple())
.WillRepeatedly(Return(10));
@ -531,7 +652,8 @@ TEST_F(VariableServerSession_test, copy_and_write_top_copy_top_write_when_copied
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_frame_multiple())
.WillRepeatedly(Return(10));
@ -561,8 +683,8 @@ TEST_F(VariableServerSession_test, copy_and_write_top_copy_top_dont_write_if_non
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = false;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(false));
EXPECT_CALL(session, get_frame_multiple())
.WillRepeatedly(Return(10));
EXPECT_CALL(session, get_frame_offset())
@ -591,7 +713,8 @@ TEST_F(VariableServerSession_test, copy_and_write_top_copy_top_write_paused) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_WHEN_COPIED, true);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_frame_multiple())
.WillRepeatedly(Return(10));
@ -626,7 +749,8 @@ TEST_F(VariableServerSession_test, copy_and_write_top_wrong_offset) {
EXPECT_CALL(session, get_write_mode())
.WillRepeatedly(Return(VS_WRITE_WHEN_COPIED));
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_frame_multiple())
.WillRepeatedly(Return(10));
@ -676,7 +800,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_copy_top_write_async) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_ASYNC, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_frame_multiple())
.WillRepeatedly(Return(10));
@ -706,7 +831,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_copy_top_write_when_cop
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_frame_multiple())
.WillRepeatedly(Return(10));
@ -736,7 +862,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_copy_top_dont_write_if_
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = false;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(false));
EXPECT_CALL(session, get_freeze_frame_multiple())
.WillRepeatedly(Return(10));
@ -766,7 +893,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_copy_top_write_paused)
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_TOP_OF_FRAME, VS_WRITE_WHEN_COPIED, true);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_frame_multiple())
.WillRepeatedly(Return(10));
@ -801,7 +929,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_wrong_offset) {
EXPECT_CALL(session, get_write_mode())
.WillRepeatedly(Return(VS_WRITE_WHEN_COPIED));
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_frame_multiple())
.WillRepeatedly(Return(10));
@ -904,7 +1033,8 @@ TEST_F(VariableServerSession_test, copy_and_write_scheduled_copy_and_write) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_next_tics())
.WillRepeatedly(Return(100));
@ -932,7 +1062,8 @@ TEST_F(VariableServerSession_test, copy_and_write_scheduled_copy_scheduled_write
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_ASYNC, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_next_tics())
.WillRepeatedly(Return(100));
@ -960,7 +1091,8 @@ TEST_F(VariableServerSession_test, copy_and_write_scheduled_paused) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_ASYNC, true);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_next_tics())
.WillRepeatedly(Return(100));
@ -988,7 +1120,8 @@ TEST_F(VariableServerSession_test, copy_and_write_scheduled_non_realtime) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_ASYNC, false);
realtime_sync->active = false;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(false));
EXPECT_CALL(session, get_next_tics())
.WillRepeatedly(Return(100));
@ -1017,7 +1150,8 @@ TEST_F(VariableServerSession_test, copy_and_write_scheduled_write_fails) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_next_tics())
.WillRepeatedly(Return(100));
@ -1121,7 +1255,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_scheduled_copy_and_writ
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_next_tics())
.WillRepeatedly(Return(100));
@ -1149,7 +1284,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_scheduled_copy_schedule
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_ASYNC, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_next_tics())
.WillRepeatedly(Return(100));
@ -1177,7 +1313,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_scheduled_paused) {
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_ASYNC, true);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_next_tics())
.WillRepeatedly(Return(100));
@ -1205,7 +1342,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_scheduled_non_realtime)
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_ASYNC, false);
realtime_sync->active = false;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(false));
EXPECT_CALL(session, get_freeze_next_tics())
.WillRepeatedly(Return(100));
@ -1234,7 +1372,8 @@ TEST_F(VariableServerSession_test, copy_and_write_freeze_scheduled_write_fails)
.WillOnce(Return(true));
set_session_modes(session, VS_COPY_SCHEDULED, VS_WRITE_WHEN_COPIED, false);
realtime_sync->active = true;
EXPECT_CALL(realtime_sync, is_active())
.WillRepeatedly(Return(true));
EXPECT_CALL(session, get_freeze_next_tics())
.WillRepeatedly(Return(100));

View File

@ -5,9 +5,9 @@ PURPOSE: ( Tests for the VariableServer class )
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "MockVariableServerSession.hh"
#include "trick/VariableServer.hh"
#include "trick/Mock/MockVariableServerSession.hh"
/*

View File

@ -271,22 +271,6 @@ Trick::VariableServerSession * session = get_session();
return(0) ;
}
// int var_signal() {
// Trick::VariableServerSession * session = get_session();
// if (session != NULL ) {
// session->var_signal() ;
// }
// return(0) ;
// }
// int var_multicast(bool on_off) {
// Trick::VariableServerSession * session = get_session();
// if (session != NULL ) {
// session->var_multicast(on_off) ;
// }
// return(0) ;
// }
int var_write_stdio(int stream , std::string text ) {
// std::cout << "Executing var_write_stdio" << std::endl;
Trick::VariableServerSession * session = get_session();

View File

@ -125,6 +125,9 @@
#include "trick/MessageCout.hh"
#include "trick/MessageThreadedCout.hh"
#include "trick/MessageFile.hh"
#include "trick/MessageHSFile.hh"
#include "trick/MessageCustomFile.hh"
#include "trick/MessageCustomManager.hh"
#include "trick/MessageLCout.hh"
#include "trick/MessagePublisher.hh"
#include "trick/MessageSubscriber.hh"

View File

@ -23,14 +23,14 @@ class SimTestWorkflow(TrickWorkflow):
build_jobs = self.get_jobs(kind='build')
# This is awful but I can't think of another way around it
# SIM_test_varserver has 2 tests that should return the code for SIG_USR1, the number is different on Mac vs Linux
# SIM_test_varserver has 2 tests that should return the code for SIGUSR1, the number is different on Mac vs Linux
# so it can't be hardcoded in the input yml file. Maybe this is a case having a label on a run would be cleaner?
import signal
run_names = ["Run test/SIM_test_varserv RUN_test/err1_test.py", "Run test/SIM_test_varserv RUN_test/err2_test.py"]
for job in [job for job in self.get_jobs(kind='run') if job.name in run_names]:
job._expected_exit_status = signal.SIGUSR1.value
# Several sims have runs that require ordering via phases:
# Several test sims have runs that require ordering via phases:
# - SIM_stls dumps a checkpoint that is then read in and checked by a subsequent run
# - SIM_checkpoint_data_recording dumps checkpoints that are read by subsequent runs
# - SIM_test_varserver has 3 runs that cannot be concurrent
@ -76,9 +76,10 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Build, run, and compare all test sims for Trick',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument( "--trick_top_level", type=str, help="Path to TRICK_HOME", default=thisdir)
parser.add_argument( "--quiet", action="store_true", help="Suppress progress bars.")
parser.add_argument( "--quiet", action="store_true", help="Suppress progress bars (automatically set to True if environment variable CI is present).")
parser.add_argument( "--cpus", type=int, default=(os.cpu_count() if os.cpu_count() is not None else 8),
help="Number of cpus to use for testing. For builds this number is used for MAKEFLAGS *and* number of "
"concurrent builds (cpus^2). For sim runs this controls the maximum number of simultaneous runs.")
myargs = parser.parse_args()
sys.exit(SimTestWorkflow(quiet=myargs.quiet, trick_top_level=myargs.trick_top_level, cpus=myargs.cpus).run())
should_be_quiet = myargs.quiet or os.getenv('CI') is not None
sys.exit(SimTestWorkflow(quiet=should_be_quiet, trick_top_level=myargs.trick_top_level, cpus=myargs.cpus).run())