def test_b3270_json_seconds(self): b3270 = Popen(cti.vgwrap(['b3270', '-json']), stdin=PIPE, stdout=PIPE) self.children.append(b3270) # Feed b3270 an action. j = {"run": {"actions": {"action": "Wait", "args": [0.1, "Seconds"]}}} b3270.stdin.write(json.dumps(j).encode('utf8') + b'\n') b3270.stdin.flush() # Get the result. pq = pipeq.pipeq(self, b3270.stdout) while True: line = pq.get(2, 'b3270 did not produce expected output') self.assertNotEqual(b'', line) if b'run-result' in line: break out = json.loads(line.decode('utf8')) # Wait for the processes to exit. b3270.stdin.close() b3270.stdout.close() self.vgwait(b3270) pq.close() # Check. run_result = out['run-result'] self.assertTrue(run_result['success']) self.assertTrue(run_result['time'] >= 0.1)
def test_b3270_passthru_json(self): b3270 = Popen(cti.vgwrap(['b3270', '-json']), stdin=PIPE, stdout=PIPE) self.children.append(b3270) # Get the initial dump. b3270.stdout.readline().decode('utf8') # Register the Foo action and run it. b3270.stdin.write(b'{"register":{"name":"Foo"}}\n') b3270.stdin.flush() b3270.stdin.write( b'{"run":{"r-tag":"abc","actions":{"action":"Foo","args":["a","b"]}}}\n' ) b3270.stdin.flush() # Get the result. pq = pipeq.pipeq(self, b3270.stdout) out = json.loads( pq.get(2, 'b3270 did not produce expected output').decode('utf8')) self.assertTrue('passthru' in out) passthru = out['passthru'] self.assertTrue('action' in passthru) action = passthru['action'] self.assertEqual('Foo', action) self.assertTrue('p-tag' in passthru) p_tag = passthru['p-tag'] self.assertTrue('parent-r-tag' in passthru) self.assertEqual('abc', passthru['parent-r-tag']) self.assertTrue('args' in passthru) self.assertEqual(['a', 'b'], passthru['args']) # Make the action succeed. succeed = {"succeed": {"p-tag": p_tag, "text": ["hello", "there"]}} b3270.stdin.write(json.dumps(succeed).encode('utf8') + b'\n') b3270.stdin.flush() # Get the result of that. out = json.loads( pq.get(2, 'b3270 did not produce expected output').decode('utf8')) self.assertTrue('run-result' in out) run_result = out['run-result'] self.assertTrue('r-tag' in run_result) self.assertEqual('abc', run_result['r-tag']) self.assertTrue('success' in run_result) self.assertTrue(run_result['success']) self.assertTrue('text' in run_result) self.assertEqual(['hello', 'there'], run_result['text']) # Wait for the process to exit. b3270.stdin.close() b3270.stdout.close() self.vgwait(b3270) pq.close()
def test_b3270_passthru_xml(self): b3270 = Popen(cti.vgwrap(['b3270']), stdin=PIPE, stdout=PIPE) self.children.append(b3270) # Get the initial dump. pq = pipeq.pipeq(self, b3270.stdout) while True: line = pq.get(2, 'b3270 did not initialize').decode('utf8') if '</initialize>' in line: break # Register the Foo action and run it. top = ET.Element('b3270-in') ET.SubElement(top, 'register', {'name': 'Foo'}) ET.SubElement(top, 'run', {'r-tag': 'abc', 'actions': "Foo(a,b)"}) *first, _, _ = cti.xml_prettify(top).split(b'\n') b3270.stdin.write(b'\n'.join(first) + b'\n') b3270.stdin.flush() # Get the result. s = pq.get(2, 'b3270 did not produce expected output').decode('utf8') out = ET.fromstring(s) self.assertEqual('passthru', out.tag) attr = out.attrib tag = attr['p-tag'] self.assertEqual('abc', attr['parent-r-tag']) self.assertEqual('a', attr['arg1']) self.assertEqual('b', attr['arg2']) self.assertFalse('arg3' in attr) # Make the action succeed. succeed = ET.Element('succeed', {'p-tag': tag, 'text': 'hello\nthere'}) b3270.stdin.write(ET.tostring(succeed) + b'\n') b3270.stdin.flush() # Get the result of that. s = pq.get(2, 'b3270 did not produce expected output').decode('utf8') out = ET.fromstring(s) self.assertEqual('run-result', out.tag) attr = out.attrib self.assertEqual('abc', attr['r-tag']) self.assertEqual('true', attr['success']) self.assertEqual('hello\nthere', attr['text']) # Wait for the process to exit. b3270.stdin.write(b'</b3270-in>\n') b3270.stdin.close() b3270.stdout.close() self.vgwait(b3270) pq.close()
def test_b3270_reconnect_interference(self): # Start 'playback' to talk to b3270. playback_port, ts = cti.unused_port() with playback.playback(self, 'c3270/Test/ibmlink2.trc', port=playback_port) as p: ts.close() # Start b3270. hport, ts = cti.unused_port() b3270 = Popen(cti.vgwrap(['b3270', '-set', 'reconnect', '-json', '-httpd', str(hport)]), stdin=PIPE, stdout=PIPE) ts.close() self.children.append(b3270) # Throw away b3270's initialization output. pq = pipeq.pipeq(self, b3270.stdout) pq.get(2, 'b3270 did not start') # Tell b3270 to connect. b3270.stdin.write(f'"open 127.0.0.1:{playback_port}"\n'.encode('utf8')) b3270.stdin.flush() # Wait for b3270 to connect. p.wait_accept() # Asynchronously block for an input field. wait_thread = threading.Thread(target=self.wif, args = [hport]) wait_thread.start() # Wait for the Wait() to block. def wait_block(): r = ''.join(requests.get(f'http://127.0.0.1:{hport}/3270/rest/json/Query(Tasks)').json()['result']) return 'Wait("InputField")' in r self.try_until(wait_block, 2, 'Wait() did not block') # Close the connection. p.close() # Wait for the input field thread to complete. wait_thread.join(timeout=2) self.assertFalse(wait_thread.is_alive(), 'Wait thread did not terminate') # Check. self.assertIn('Host disconnected', ''.join(self.wait_result['result'])) # Clean up. b3270.stdin.write(b'"quit"\n') b3270.stdin.flush() b3270.stdin.close() self.vgwait(b3270) pq.close() b3270.stdout.close()
def test_b3270_xml_multiple(self): b3270 = Popen(cti.vgwrap(['b3270']), stdin=PIPE, stdout=PIPE) self.children.append(b3270) # Feed b3270 two actions, which it will run concurrently and complete # in reverse order. top = ET.Element('b3270-in') ET.SubElement(top, 'run', { 'actions': 'Wait(0.1,seconds) Set(startTls) Quit()', 'r-tag': 'tls' }) ET.SubElement(top, 'run', { 'actions': 'Set(insertMode)', 'r-tag': 'ins' }) *first, _, _ = cti.xml_prettify(top).split(b'\n') b3270.stdin.write(b'\n'.join(first) + b'\n') b3270.stdin.flush() # Get the result. errmsg = 'b3270 did not produce the expected output' pq = pipeq.pipeq(self, b3270.stdout) pq.get(2, errmsg) pq.get(2, errmsg) pq.get(2, errmsg) out = pq.get(2, errmsg).decode('utf8') et_ins = ET.fromstring(out) out = pq.get(2, errmsg).decode('utf8') et_tls = ET.fromstring(out) self.vgwait(b3270) pq.close() b3270.stdin.close() b3270.stdout.close() # Check. self.assertEqual('run-result', et_ins.tag) att_ins = et_ins.attrib self.assertEqual('ins', att_ins['r-tag']) self.assertEqual('true', att_ins['success']) self.assertEqual('false', att_ins['text']) self.assertEqual('run-result', et_tls.tag) att_tls = et_tls.attrib self.assertEqual('tls', att_tls['r-tag']) self.assertEqual('true', att_tls['success']) self.assertEqual('true', att_tls['text'])
def test_b3270_retry_5s(self): # Find an unused port, but do not listen on it yet. playback_port, ts = cti.unused_port() # Start b3270. b3270 = Popen(cti.vgwrap(['b3270', '-set', 'retry', '-json']), stdin=PIPE, stdout=PIPE) self.children.append(b3270) # Throw away b3270's initialization output. pq = pipeq.pipeq(self, b3270.stdout) pq.get(2, 'b3270 did not start') # Tell b3270 to connect. b3270.stdin.write(f'"open 127.0.0.1:{playback_port}"\n'.encode('utf8')) b3270.stdin.flush() # Wait for it to try to connect and fail. out_all = [] while True: out = pq.get(2, 'b3270 did not fail the connection') out_all += [out] if b'connection-error' in out: break outj = json.loads(out.decode('utf8'))['popup'] self.assertTrue(outj['retrying']) self.assertFalse(any(b'run-result' in o for o in out_all), 'Open action should not complete') # Start 'playback' to talk to b3270. with playback.playback(self, 'c3270/Test/ibmlink2.trc', port=playback_port) as p: ts.close() # Wait for b3270 to connect. p.wait_accept(timeout=6) # Clean up. b3270.stdin.write(b'"quit"\n') b3270.stdin.flush() b3270.stdin.close() self.vgwait(b3270) pq.close() b3270.stdout.close()
def test_b3270_json_multiple(self): b3270 = Popen(cti.vgwrap(['b3270', '-json']), stdin=PIPE, stdout=PIPE) self.children.append(b3270) # Feed b3270 two sets of actions, which it will run concurrently and complete # in reverse order. b3270.stdin.write( b'"Wait(0.1,seconds) Set(startTls) Quit()" "Set(insertMode)"\n') b3270.stdin.flush() # Get the output before waiting for b3270 to exit. Otherwise it # hangs trying to write to its stdout (on Windows). # Individual timed reads are used here because communicate() closes stdin and that will # cause b3270 to exit prematurely. errmsg = 'b3270 did not produce expected output' pq = pipeq.pipeq(self, b3270.stdout) pq.get(2, errmsg) insert_mode = json.loads(pq.get(2, errmsg).decode('utf8')) start_tls = json.loads(pq.get(2, errmsg).decode('utf8')) b3270.stdin.close() b3270.stdout.close() self.vgwait(b3270) pq.close() # Check. self.assertTrue('run-result' in insert_mode) result = insert_mode['run-result'] self.assertTrue('success' in result) self.assertTrue(result['success']) self.assertTrue('text' in result) self.assertEqual('false', result['text'][0]) self.assertTrue('run-result' in start_tls) result = start_tls['run-result'] self.assertTrue('success' in result) self.assertTrue(result['success']) self.assertTrue('text' in result) self.assertEqual('true', result['text'][0])
def test_b3270_xml_seconds(self): b3270 = Popen(cti.vgwrap(['b3270']), stdin=PIPE, stdout=PIPE) self.children.append(b3270) # Feed b3270 an action. top = ET.Element('b3270-in') ET.SubElement(top, 'run', {'actions': "Wait(0.2,Seconds)"}) *first, _, _ = cti.xml_prettify(top).split(b'\n') b3270.stdin.write(b'\n'.join(first) + b'\n') b3270.stdin.flush() # Get the result. pq = pipeq.pipeq(self, b3270.stdout) output = b'' while True: line = pq.get(2, 'b3270 did not produce expected output') self.assertNotEqual(b'', line) output += line if b'run-result' in line: break output += b'</b3270-out>' # a white lie out = ET.fromstring(output.decode('utf8')) # Wait for the processes to exit. b3270.stdin.write(b'</b3270-in>\n') b3270.stdin.close() b3270.stdout.close() self.vgwait(b3270) pq.close() # Check. a = out.find('./run-result') self.assertTrue(a != None) att = a.attrib self.assertTrue(att['success']) self.assertTrue(float(att['time']) >= 0.1)