# Brent Couvrette
# September 16, 2008
# THIS FILE IS CURRENTLY UNUSED...
#
# Repy script to run the Seattle test cases using the node manager...  
# Adapted from a python script by Justin Cappos
#
# The types of tests are:
#
#   s_*.py -- The correct result is the same as when run with python
#   e_*.py -- The restricted program produces output on stderr (most likely
#             because it throws an exception)
#   z_*.py -- The restricted program produces no output 
#   n_*.py -- The restricted program produces some output on stdout and no
#             output on stderr
#   b_*.py -- The restricted program produces output on both stderr and stdout
#   u_*.py -- The result of running these programs is undefined.   They are
#             not tested but may be useful as examples
#   l_*.py -- Use circular logging while testing.   These test cases indicate
#             an error by using exitall instead of letting the program 
#             terminate normally...
#

include rsa.repy
include time.repy
include nmclient.repy

# what we print at the end...
mycontext['endput'] = ''

def run_test(testname):
	if testname.startswith('rs_') or testname.startswith('re_') or \
			testname.startswith('rz_') or testname.startswith('rn_') or \
			testname.startswith('rb_') or testname.startswith('rl_'):

 		# must have three parts: r?_restrictionfn_testname.py
		if len(testname.split('_')) != 3:
			raise Exception, "Test name '"+testname+"' does not have 3 parts!"

		# take the 2nd character of the testname 'rs_' -> 's'
		testtype = testname[1]
		restrictfn = testname.split('_')[1]

	elif testname.startswith('s_') or testname.startswith('e_') or \
			testname.startswith('z_') or testname.startswith('n_') or \
			testname.startswith('b_') or testname.startswith('l_'):

 		# take the 1st character of the testname 's_' -> 's'
		testtype = testname[0]
		restrictfn = 'default'
    
	elif testname.startswith('ru_') or testname.startswith('u_'):
    	# Do not run undefined tests...
		return
	else:
		raise Exception, "Test name '"+testname+"' of an unknown type!"


	resultstring = "Ran test %-50s [" % testname
	
	# If there is no custom restrictions file, we can do a user test,
	# otherwise we need to have owner privilages to do the test.
	if restrictfn == 'default':
		result = do_user_test(testtype, testname)
	else:
		result = do_owner_test(testtype, restrictfn, testname)

	if result:
		mycontext['passcount'] = mycontext['passcount'] + 1
		resultstring = resultstring + " PASS ]"
	else:
		mycontext['failcount'] = mycontext['failcount'] + 1
		resultstring = resultstring + "FAILED]"
	print resultstring


def do_user_test(testtype, testname):
	repylog = run_in_vessel(testname, restrictfn)

	# match python
	if testtype == 's':
		pyoutfile = file(testname+'.out', 'r')
		pyout = pyoutfile.read()
		pyoutfile.close()

		same = True

		if pyout != repylog:
			# stdout differs
			mycontext['endput'] = mycontext['endput']+testname+"\n"+ "output mismatch '"+pyout+"' != '"+repylog+"'\n\n"
			same = False
    
		return same

	# any out, no err...
	elif testtype == 'n':
		if repylog != '' and repylog.find('Traceback') == -1:
			return True
		else:
			mycontext['endput'] = mycontext['endput']+testname+"\nout:"+repylog+"\n\n"
			return False

	# any err, no out... (doesn't check no out as is)
	elif testtype == 'e':
		if repylog.find('Traceback') != -1:
			return True
		else:
			mycontext['endput'] = mycontext['endput']+testname+"\nout:"+repylog+"\n\n"
			return False

	# no err, no out...
	elif testtype == 'z':
		if repylog == '':
			return True
		else:
			mycontext['endput'] = mycontext['endput']+testname+"\nout:"+repylog+"\n\n"
			return False

	# any err, any out...
	elif testtype == 'b':
		if repylog.find('Traceback') != -1:
			return True
		else:
			mycontext['endput'] = mycontext['endput']+testname+"\nout:"+repylog+"\n\n"
			return False

	# no err, no out (logging)...
	elif testtype == 'l':
		if 'Fail' in repylog:
			mycontext['endput'] = mycontext['endput']+testname+"\nString 'Fail' in logdata\n\n"
			return False
		elif "Success" not in repylog:
			mycontext['endput']= mycontext['endput']+testname+"\nString 'Success' not in logdata\n\n"
			return False 
		else:
			return True
	else: 
		raise Exception, "Unknown test type '"+str(testout)+"'"


def run_in_vessel(testname, restrictfn):
	# the maximum size the logging buffer can be
	# NOTE: make sure this is equal to the maxbuffersize in logging.py and logmaxbuffersize in nmAPI.mix
	maxlogsize = 16*1024
	
	# get the test vessel
	testvessel = nmclient_listaccessiblevessels(mycontext['nmhandle'], mycontext['testpubkey'])[1][0]
	
	# Run the log flusher to ensure that we don't get anything back from other test's logs
	nmclient_signedsay(mycontext['nmhandle'], 'StartVessel', testvessel, 'logflusher.py')
	
	# wait for the log flusher to complete
	while nmclient_getvesseldict(mycontext['nmhandle'])['vessels'][testvessel]['status'] == 'Started':
		sleep(0.1)
	
	# add the test program that we wish to run
	testfile = file(testname, 'r')
	teststring = testfile.read()
	testfile.close()
	nmclient_signedsay(mycontext['nmhandle'], 'AddFileToVessel', testvessel, testname, teststring)

	# run the test program
	nmclient_signedsay(mycontext['nmhandle'], 'StartVessel', testvessel, testname)

	# wait for the program to complete
	while nmclient_getvesseldict(mycontext['nmhandle'])['vessels'][testvessel]['status'] == 'Started':
		sleep(0.5)

	# read the log of the program's output
	repylog = nmclient_signedsay(mycontext['nmhandle'], "ReadVesselLog", testvessel)

	# Remove the extra whitespace on the ends of the log caused by the log flusher
	repylog = repylog.strip()
	
	# return the program's log
	return repylog


# Adds the log flusher and any separate files required by any of the
# tests to the test vessel
def init_testvessel():
	# get the test vessel
	testvessel = nmclient_listaccessiblevessels(mycontext['nmhandle'], mycontext['testpubkey'])[1][0]
	
	# Setup the log flusher program.  This program fills the readable log with
	# whitespace, effectively erasing any previous log entry.
	flusher = """
if callfunc == 'initialize':
	print ' ' * (16*1024)
"""

	# Add the flusher to the testvessel
	nmclient_signedsay(mycontext['nmhandle'], 'AddFileToVessel', testvessel, 'logflusher.py', flusher)
	
	# Add the separate files necesary for the tests to the test vessel
	# Is there definately enough structure to do this in some sort of loop?
	addFileToVessel(testvessel, 'hello')
	addFileToVessel(testvessel, 'hello1')
	addFileToVessel(testvessel, 'hello2')
	addFileToVessel(testvessel, 'hello3')
	addFileToVessel(testvessel, 'hello4')
	addFileToVessel(testvessel, 'hello5')
	addFileToVessel(testvessel, 'hello.file')
	addFileToVessel(testvessel, 'hello.multiline')
	
	
def addFileToVessel(vessel, filename):
	testfile = file(filename, 'r')
	filestring = testfile.read()
	nmclient_signedsay(mycontext['nmhandle'], 'AddFileToVessel', vessel, filename, filestring)

#carry out all of the tests
def testmain():

	# these are updated in run_test
	mycontext['passcount']=0
	mycontext['failcount']=0

	time_updatetime(34612)
	mycontext['nmhandle'] = nmclient_createhandle(getmyip(), 1224)
 
	mycontext['testpubkey'] = rsa_file_to_publickey('test.publickey')

	privkey = rsa_file_to_privatekey('test.privatekey')

	myhandleinfo = nmclient_get_handle_info(mycontext['nmhandle'])

	myhandleinfo['publickey'] = mycontext['testpubkey']

	myhandleinfo['privatekey'] = privkey

	nmclient_set_handle_info(mycontext['nmhandle'], myhandleinfo)

	# initialize the test vessel
	init_testvessel()

	# for each test... run it!
	for testfile in listdir():
		if((testfile[0:2] == "s_" or 
		testfile[0:2] == "e_" or testfile[0:2] == "z_" or 
		testfile[0:2] == "n_" or testfile[0:2] == "b_" or
		testfile[0:2] == "u_" or testfile[0:2] == "l_") and
		testfile[-3:] == ".py"): 
			run_test(testfile)


	print mycontext['passcount'],"tests passed,",mycontext['failcount'],"tests failed"

	# only print if there is something to print
	if mycontext['endput']:
		print mycontext['endput']

#start testmain if we are being initialized
if callfunc == 'initialize':
	testmain()
