forked from usdot-jpo-ode/jpo-ode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7e35539
commit e6f5d6e
Showing
5 changed files
with
116 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM python:latest | ||
|
||
RUN pip3 install requests | ||
RUN pip3 install kafka-python | ||
|
||
WORKDIR /home/test-harness | ||
COPY . /home/test-harness | ||
|
||
CMD python main.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import threading | ||
import requests | ||
import time | ||
import queue | ||
import json | ||
from kafka import KafkaConsumer | ||
|
||
class TestCase: | ||
def __init__(self, input, expectedOutput): | ||
self.input = input | ||
self.expectedOutput = expectedOutput | ||
|
||
mcin = str(input['tim']['msgCnt']) | ||
mcout = str(expectedOutput['payload']['data']['MessageFrame']['value']['TravelerInformation']['msgCnt']) | ||
assert mcin == mcout, "Message count input and output do not match: input=%s, output=%s" % (mcin, mcout) | ||
self.msgCnt = mcin | ||
|
||
def compare(actualOutput): | ||
assert str(self.expectedOutput) == str(actualOutput), "Input file does not match expected output: expected <%s> but got <%s>" % (str(self.expectedOutput), str(actualOutput)) | ||
|
||
def sendRESTRequest(body): | ||
response=requests.post('https://10.6.180.147:8080/tim', data = body) | ||
print("Response code: " + str(response.status_code)) | ||
|
||
def listenToKafkaTopic(topic, msgQueue, expectedMsgCount): | ||
print("Listening on topic: " + topic) | ||
consumer=KafkaConsumer(topic, bootstrap_servers="10.6.180.147:9092") | ||
msgsReceived=0 | ||
for msg in consumer: | ||
msgsReceived += 1 | ||
print(str(msgsReceived)) | ||
msgQueue.put(msg) | ||
if msgsReceived >= expectedMsgCount: | ||
return | ||
|
||
def createOutputList(fileDict): | ||
outputList=[] | ||
for infile, outfile in fileDict.items(): | ||
outfileData=json.load(open(outfile, 'r').read()) | ||
outputList.append(outfileData) | ||
return outputList | ||
|
||
def findOutputFile(msgCnt, fileDict): | ||
for outfile in fileDict.queue: | ||
if json.loads(outfile.value)['payload']['data']['MessageFrame']['value']['TravelerInformation']['msgCnt'] == msgCnt: | ||
return outfile | ||
return None | ||
|
||
def validate(testCaseList, actualMsgQueue): | ||
assert len(testCaseList) == actualMsgQueue.qsize(), "Input list length does not match output list length, input: %d, output: %d" % (len(testCaseList), actualMsgQueue.qsize()) | ||
for msg in actualMsgQueue.queue: | ||
# Find corresponding output file | ||
msgCnt=json.loads(msg.value)['payload']['data']['MessageFrame']['value']['TravelerInformation']['msgCnt'] | ||
expectedOutputFile=findOutputFile(msgCnt, actualMsgQueue) | ||
assert expectedOutputFile != None, "Unable to find matching output file for input file msgCnt=%s" % str(msgCnt) | ||
assert str(msg) == str(expectedOutputFile), "Input file does not match expected output: expected <%s> but got <%s>" % (str(msg), str(expectedOutputFile)) | ||
|
||
def main(): | ||
print("Test routine started...") | ||
testFileDict={ | ||
"tim1_input.json": "tim1_output.json" | ||
} | ||
timBroadcastTopic='topic.J2735TimBroadcastJson' | ||
msgQueue=queue.Queue() | ||
|
||
# Create a kafka consumer and wait for it to connect | ||
kafkaListenerThread=threading.Thread(target=listenToKafkaTopic,args=(timBroadcastTopic,msgQueue, len(testFileDict)),) | ||
kafkaListenerThread.start() | ||
time.sleep(5) | ||
|
||
# Create test cases | ||
print("Creating test cases...") | ||
tcList = [] | ||
for inputFilename, expectedOutputFilename in testFileDict.items(): | ||
inputData = json.loads(open(inputFilename, 'r').read()) | ||
expectedOutputData = json.loads(open(expectedOutputFilename, 'r').read()) | ||
tc = TestCase(inputData, expectedOutputData) | ||
tcList.append(tc) | ||
|
||
print("Test cases created.") | ||
|
||
# Send test data | ||
for index, testCase in enumerate(tcList, start=1): | ||
print("Sending REST request for test case %d/%d" % (index, len(tcList))) | ||
sendRESTRequest(json.dumps(testCase.input)) | ||
|
||
# Perform validation | ||
print("Request sending complete.") | ||
|
||
print("Waiting for all messages to be received...") | ||
kafkaListenerThread.join() | ||
print("All messages received.") | ||
|
||
print("Validating output...") | ||
validate(tcList, msgQueue) | ||
print("Output validated.") | ||
|
||
print("All tests have passed") | ||
print("End.") | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/bin/sh | ||
docker build -t ode-test-harness . | ||
docker run ode-test-harness |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"request": {"rsus": [{"rsuIndex": "9","rsuTarget": "127.0.0.1","rsuUsername": "uuuuuuuu","rsuPassword": "pppppppp","rsuRetries": "1","rsuTimeout": "2500"}],"snmp": {"rsuid": "00000083","msgid": "31","mode": "1","channel": "178","interval": "2","deliverystart": "2018-06-01T17:47:11-05:00","deliverystop": "2019-01-01T17:47:11-05:15","enable": "1","status": "4"}},"tim": {"msgCnt": "1","timeStamp": "2017-03-13T01:07:11-05:00","packetID": "EC9C236B0000000000","urlB": "null","dataframes": [{"sspTimRights": "0","frameType": "advisory","msgId": {"roadSignID": {"position": {"latitude": "42.678473","longitude": "-102.782775","elevation": "912.1432"},"viewAngle": "1010101010101010","mutcdCode": "warning","crc": "F1A7"}},"startDateTime": "2017-12-01T17:47:11-05:00","durationTime": "22","priority": "0","sspLocationRights": "3","regions": [{"name": "bob","regulatorID": "23","segmentID": "33","anchorPosition": {"latitude": "42.278473","longitude": "-102.782775","elevation": "912.1432"},"laneWidth": "7","directionality": "3","closedPath": "false","direction": "1010101010101010","description": "geometry","geometry": {"direction": "1010101010101010","extent": "1","laneWidth": "33","circle": {"position": {"latitude": "42.678473","longitude": "-102.782775","elevation": "912.1432"},"radius": "15","units": "7"}}}],"sspMsgTypes": "2","sspMsgContent": "3","content": "Advisory","items": ["125","some text","250","'98765"],"url": "null"}]}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"metadata":{"request":{"ode":{"verb":"POST","version":3},"rsus":{"rsus":{"rsuTarget":"127.0.0.1","rsuUsername":"uuuuuuuu","rsuRetries":1,"rsuTimeout":2500,"rsuPassword":"*","rsuIndex":9}},"snmp":{"mode":1,"deliverystop":"2019-01-01T17:47:11-05:15","rsuid":"00000083","deliverystart":"2018-06-01T17:47:11-05:00","enable":1,"channel":178,"msgid":31,"interval":2,"status":4}},"recordGeneratedBy":"TMC","schemaVersion":6,"payloadType":"us.dot.its.jpo.ode.model.OdeTimPayload","serialId":{"recordId":0,"serialNumber":42,"streamId":"03965238-88a3-4f2b-a6d9-27501936514f","bundleSize":1,"bundleId":42},"sanitized":false,"recordGeneratedAt":"2017-03-13T06:07:11Z","odeReceivedAt":"2019-01-18T17:12:30.511Z"},"payload":{"data":{"MessageFrame":{"messageId":31,"value":{"TravelerInformation":{"timeStamp":102607,"packetID":"EC9C236B0000000000","urlB":null,"dataFrames":{"TravelerDataFrame":{"regions":{"GeographicalPath":{"closedPath":{"false":""},"anchor":{"elevation":9121,"lat":422784730,"long":-1027827750},"name":"bob","laneWidth":700,"directionality":{"both":""},"description":{"geometry":{"extent":1,"laneWidth":3300,"circle":{"center":{"elevation":9121,"lat":426784730,"long":-1027827750},"units":{"mile":""},"radius":15},"direction":1010101010101010}},"id":{"id":33,"region":23},"direction":1010101010101010}},"duratonTime":22,"sspMsgRights1":2,"sspMsgRights2":3,"startYear":2017,"msgId":{"roadSignID":{"crc":"F1A7","viewAngle":1010101010101010,"mutcdCode":{"warning":""},"position":{"elevation":9121,"lat":426784730,"long":-1027827750}}},"priority":0,"content":{"advisory":{"SEQUENCE":[{"item":{"itis":125}},{"item":{"text":"some text"}},{"item":{"itis":250}},{"item":{"text":98765}}]}},"url":null,"sspTimRights":0,"sspLocationRights":3,"frameType":{"advisory":""},"startTime":482327}},"msgCnt":1}}}},"dataType":"TravelerInformation"}} |