def test_multiple_run_calls(callrpc_sg): """Make sure we can call run multiple times.""" sim = SensorGraphSimulator(callrpc_sg) sim.stop_condition('run_time 100 seconds') sim.run() # Make sure the sensor graph ran correctly last_input = callrpc_sg.sensor_log.inspect_last( DataStream.FromString('system input 2')) last_output = callrpc_sg.sensor_log.inspect_last( DataStream.FromString('unbuffered 2')) assert last_input.value == 100 assert last_output.value == 0 sim.run() # Make sure the sensor graph ran correctly last_input = callrpc_sg.sensor_log.inspect_last( DataStream.FromString('system input 2')) last_output = callrpc_sg.sensor_log.inspect_last( DataStream.FromString('unbuffered 2')) assert last_input.value == 200 assert last_output.value == 0
def test_stream_type_parsing(): """Make sure we can parse each type of stream.""" # Make sure parsing stream type works stream = DataStream.FromString('buffered 1') assert stream.stream_type == stream.BufferedType stream = DataStream.FromString(u'buffered 1') assert stream.stream_type == stream.BufferedType stream = DataStream.FromString('unbuffered 1') assert stream.stream_type == stream.UnbufferedType stream = DataStream.FromString(u'unbuffered 1') assert stream.stream_type == stream.UnbufferedType stream = DataStream.FromString('counter 1') assert stream.stream_type == stream.CounterType stream = DataStream.FromString(u'counter 1') assert stream.stream_type == stream.CounterType stream = DataStream.FromString('constant 1') assert stream.stream_type == stream.ConstantType stream = DataStream.FromString(u'constant 1') assert stream.stream_type == stream.ConstantType stream = DataStream.FromString('output 1') assert stream.stream_type == stream.OutputType stream = DataStream.FromString(u'output 1') assert stream.stream_type == stream.OutputType
def test_tick1(tick1_sg): """Make sure we receive tick_1 ticks in the simulation.""" assert tick1_sg.get_tick('user1') == 2 sim = SensorGraphSimulator(tick1_sg) sim.stop_condition('run_time 100 seconds') sim.run() # Make sure the sensor graph ran correctly last_input = tick1_sg.sensor_log.inspect_last( DataStream.FromString('system input 5')) last_output = tick1_sg.sensor_log.inspect_last( DataStream.FromString('counter 1')) assert last_input.value == 100 assert last_output.value == 100 sim.run() # Make sure the sensor graph ran correctly last_input = tick1_sg.sensor_log.inspect_last( DataStream.FromString('system input 5')) last_output = tick1_sg.sensor_log.inspect_last( DataStream.FromString('counter 1')) assert last_input.value == 200 assert last_output.value == 200
def test_on_block(parser): """Make sure on count(stream), on value(stream) and on stream work.""" parser.parse_file(get_path(u'basic_on.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() counter1 = log.create_walker(DataStreamSelector.FromString('counter 1')) counter2 = log.create_walker(DataStreamSelector.FromString('counter 2')) counter3 = log.create_walker(DataStreamSelector.FromString('counter 3')) sim = SensorGraphSimulator(sg) sim.step(DataStream.FromString('input 1'), 8) assert counter1.count() == 0 assert counter2.count() == 0 assert counter3.count() == 0 for i in range(0, 10): sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 10 assert counter2.count() == 5 assert counter3.count() == 5
def test_on_block_dual(parser): """Make sure on with two conditions works.""" parser.parse_file(get_path(u'basic_on_dual.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() counter1 = log.create_walker(DataStreamSelector.FromString('counter 1')) sim = SensorGraphSimulator(sg) sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 0 sim.step(DataStream.FromString('input 2'), 1) for _i in range(0, 10): sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 11 sim.step(DataStream.FromString('input 2'), 0) for _i in range(0, 10): sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 11
def test_when_block_clock(parser): """Make sure we can compile when blocks (without identifiers).""" parser.parse_file(get_path(u'basic_when.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() assert sg.get_tick('fast') == 1 # Now make sure it produces the right output counter15 = log.create_walker(DataStreamSelector.FromString('counter 15')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 60 seconds') sim.run() assert counter15.count() == 0 sim.step(DataStream.FromString('system input 1025'), 8) assert counter15.count() == 1 counter15.skip_all() sim.run() assert counter15.count() == 60 counter15.skip_all() sim.step(DataStream.FromString('system input 1026'), 8) sim.run() assert counter15.count() == 0
def test_seek_walker(): """Make sure we can seek a walker can count with an offset.""" model = DeviceModel() log = SensorLog(model=model) stream = DataStream.FromString('buffered 1') reading = IOTileReading(stream.encode(), 0, 1) log.push(stream, reading) log.push(stream, reading) log.push(DataStream.FromString('buffered 2'), reading) log.push(stream, reading) walk = log.create_walker(DataStreamSelector.FromString('buffered 1'), skip_all=False) assert walk.offset == 0 assert walk.count() == 3 walk.seek(1) assert walk.offset == 1 assert walk.count() == 2 # Make sure we can seek to a position corresponding to another stream walk.seek(2) assert walk.offset == 2 assert walk.count() == 1 # Make sure we can find a reading by reading ID walk = log.create_walker(DataStreamSelector.FromString('output 1'), skip_all=False) output1 = DataStream.FromString('output 1') output2 = DataStream.FromString('output 2') log.push(output1, IOTileReading(0, 0, 1, reading_id=1)) log.push(output1, IOTileReading(0, 0, 1, reading_id=2)) log.push(output2, IOTileReading(0, 0, 1, reading_id=3)) log.push(output1, IOTileReading(0, 0, 1, reading_id=4)) exact = walk.seek(2, target='id') assert exact is True assert walk.count() == 2 assert walk.offset == 1 exact = walk.seek(3, target='id') assert exact is False assert walk.count() == 1 assert walk.offset == 2 # Verify exceptions thrown by seek() with pytest.raises(UnresolvedIdentifierError): walk.seek(5, target='id') with pytest.raises(UnresolvedIdentifierError): walk.seek(5, target=u'id') with pytest.raises(UnresolvedIdentifierError): walk.seek(5, target='offset') with pytest.raises(ArgumentError): walk.seek(2, target="unsupported")
def test_stringification(): """Make sure we can stringify DataStream objects.""" stream1 = DataStream.FromString('system buffered 1') stream2 = DataStream.FromString('buffered 0xF') assert str(stream1) == str('system buffered 1') assert str(stream2) == str('buffered 15')
def test_complex_gate_optimization(complex_gate, complex_gate_opt): """Make sure the optimized version runs identically to the unoptimized.""" sg, sg_opt = complex_gate, complex_gate_opt sim1 = SensorGraphSimulator(sg) sim1.stop_condition("run_time 10 minutes") sg.load_constants() sim1.record_trace() sim1.run() sim2 = SensorGraphSimulator(sg_opt) sim2.stop_condition("run_time 10 minutes") sg_opt.load_constants() sim2.record_trace() sim2.run() assert len(sim1.trace) == 0 assert len(sim2.trace) == 0 sim1.step(DataStream.FromString("system input 1034"), 1) sim2.step(DataStream.FromString("system input 1034"), 1) sim1.run() sim2.run() print("Unoptimized Output") for x in sim1.trace: print("%08d %s: %d" % (x.raw_time, DataStream.FromEncoded(x.stream), x.value)) print("\nOptimized Output") for x in sim2.trace: print("%08d %s: %d" % (x.raw_time, DataStream.FromEncoded(x.stream), x.value)) assert len(sim1.trace) == 4 assert len(sim2.trace) == 4 assert sim1.trace == sim2.trace #Check that number of trigger streamer commands is same for optimized and unoptimized trigger_nodes = [ node for node in complex_gate.nodes if node.func_name == 'trigger_streamer' ] trigger_nodes_opt = [ node for node in complex_gate_opt.nodes if node.func_name == 'trigger_streamer' ] assert len(trigger_nodes) == len(trigger_nodes_opt)
def test_system_parsing(): """Make sure we can parse the system prefix.""" stream = DataStream.FromString('buffered 1') assert stream.system is False stream = DataStream.FromString(u'buffered 1') assert stream.system is False stream = DataStream.FromString('system buffered 1') assert stream.system is True stream = DataStream.FromString(u'system buffered 1') assert stream.system is True
def test_basic_sensorgraph(): """Make sure we can parse, load and run a basic sensor graph.""" model = DeviceModel() log = SensorLog(model=model) sg = SensorGraph(log, model=model) sg.add_node('(input 1 always && input 2 when count >= 1) => unbuffered 1 using copy_all_a') sg.process_input(DataStream.FromString('input 1'), IOTileReading(0, 1, 1), rpc_executor=None) sg.process_input(DataStream.FromString('input 2'), IOTileReading(0, 1, 1), rpc_executor=None) assert sg.sensor_log.inspect_last(DataStream.FromString('unbuffered 1')).value == 1
def test_stream_id_parsing(): """Make sure we can parse stream ids.""" stream = DataStream.FromString('buffered 1') assert stream.stream_id == 1 stream = DataStream.FromString('buffered 0x100') assert stream.stream_id == 0x100 stream = DataStream.FromString(u'buffered 1') assert stream.stream_id == 1 stream = DataStream.FromString(u'buffered 0x100') assert stream.stream_id == 0x100
def test_rpc_sim(callrpc_sg): """Make sure we can run a very simple sensor graph and have it work.""" sim = SensorGraphSimulator(callrpc_sg) sim.stop_condition('run_time 1000 seconds') sim.run() # Make sure the sensor graph ran correctly last_input = callrpc_sg.sensor_log.inspect_last( DataStream.FromString('system input 2')) last_output = callrpc_sg.sensor_log.inspect_last( DataStream.FromString('unbuffered 2')) assert last_input.value == 1000 assert last_output.value == 0
def test_copy_constant_statement(parser): """Make sure we can copy constant values.""" parser.parse_file(get_path(u'basic_copy_constant.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() output1 = log.create_walker(DataStreamSelector.FromString('output 1')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 10 seconds') sim.run() assert output1.count() == 1 assert output1.pop().value == 15 sim.step(DataStream.FromString('input 1'), 10) assert output1.count() == 1 assert output1.pop().value == 0x10
def FromBinary(cls, record_data, record_count=1): """Create an UpdateRecord subclass from binary record data. This should be called with a binary record blob (NOT including the record type header) and it will decode it into a SetConstantRecord. Args: record_data (bytearray): The raw record data that we wish to parse into an UpdateRecord subclass NOT including its 8 byte record header. record_count (int): The number of records included in record_data. Raises: ArgumentError: If the record_data is malformed and cannot be parsed. Returns: SetConstantRecord: The decoded reflash tile record. """ _cmd, address, _resp_length, payload = cls._parse_rpc_info(record_data) try: value, encoded_stream = struct.unpack("<LH", payload) stream = DataStream.FromEncoded(encoded_stream) except ValueError: raise ArgumentError("Could not parse set_constant payload", payload=payload) return SetConstantRecord(stream, value, address=address)
def count_matching(self, selector, offset=0): """Count the number of readings matching selector. Args: selector (DataStreamSelector): The selector that we want to count matching readings for. offset (int): The starting offset that we should begin counting at. Returns: int: The number of matching readings. """ if selector.output: data = self.streaming_data elif selector.buffered: data = self.storage_data else: raise ArgumentError( "You can only pass a buffered selector to count_matching", selector=selector) count = 0 for i in range(offset, len(data)): reading = data[i] stream = DataStream.FromEncoded(reading.stream) if selector.matches(stream): count += 1 return count
def test_counter_walker(): """Make sure counter walkers work correctly.""" model = DeviceModel() log = SensorLog(model=model) walk = log.create_walker(DataStreamSelector.FromString('counter 1')) stream = DataStream.FromString('counter 1') reading = IOTileReading(0, 1, 1) assert walk.count() == 0 log.push(stream, IOTileReading(0, 1, 1)) assert walk.count() == 1 assert walk.peek().value == 1 log.push(stream, IOTileReading(0, 1, 3)) assert walk.count() == 2 assert walk.peek().value == 3 val = walk.pop() assert walk.count() == 1 assert val.value == 3 val = walk.pop() assert walk.count() == 0 assert val.value == 3 with pytest.raises(StreamEmptyError): walk.pop()
def test_walker_at_beginning(): """Make sure we can start a walker at the beginning of a stream.""" model = DeviceModel() log = SensorLog(model=model) stream = DataStream.FromString('buffered 1') reading = IOTileReading(stream.encode(), 0, 1) log.push(stream, reading) log.push(stream, reading) log.push(DataStream.FromString('buffered 2'), reading) walk = log.create_walker(DataStreamSelector.FromString('buffered 1'), skip_all=False) assert walk.offset == 0 assert walk.count() == 2
def inspect_virtual(self, stream_id): """Inspect the last value written into a virtual stream. Args: stream_id (int): The virtual stream was want to inspect. Returns: (int, int): An error code and the stream value. """ stream = DataStream.FromEncoded(stream_id) if stream.buffered: return [ pack_error(ControllerSubsystem.SENSOR_LOG, SensorLogError.VIRTUAL_STREAM_NOT_FOUND), 0 ] try: reading = self.storage.inspect_last(stream, only_allocated=True) return [Error.NO_ERROR, reading.value] except StreamEmptyError: return [Error.NO_ERROR, 0] except UnresolvedIdentifierError: return [ pack_error(ControllerSubsystem.SENSOR_LOG, SensorLogError.VIRTUAL_STREAM_NOT_FOUND), 0 ]
def stream_name(stream_id): """Map a stream id to a human readable name. The mapping process is as follows: If the stream id is globally known, its global name is used as <name> otherwise a string representation of the stream is used as <name>. In both cases the hex representation of the stream id is appended as a number: <name> (0x<stream id in hex>) Args: stream_id (int): An integer stream id. Returns: str: The nice name of the stream. """ name = _STREAM_NAME_MAP.get(stream_id) if name is None: name = str(DataStream.FromEncoded(stream_id)) return "{} (0x{:04X})".format(name, stream_id)
def test_storage_streaming_walkers(): """Make sure the storage and streaming walkers work simultaneously.""" model = DeviceModel() log = SensorLog(model=model) storage_walk = log.create_walker(DataStreamSelector.FromString('buffered 1')) output_walk = log.create_walker(DataStreamSelector.FromString('output 1')) storage1 = DataStream.FromString('buffered 1') storage2 = DataStream.FromString('buffered 2') output1 = DataStream.FromString('output 1') output2 = DataStream.FromString('output 2') assert storage_walk.offset == 0 assert output_walk.offset == 0 for i in range(0, 5000): reading = IOTileReading(0, 0, i) log.push(storage1, reading) log.push(storage2, reading) log.push(output1, reading) log.push(output2, reading) assert storage_walk.count() == (i + 1) assert output_walk.count() == (i + 1) assert storage_walk.offset == 0 assert output_walk.offset == 0 for i in range(0, 5000): reading1 = storage_walk.pop() reading2 = output_walk.pop() assert reading1.value == i assert reading1.stream == storage1.encode() assert reading2.value == i assert reading2.stream == output1.encode() assert storage_walk.offset == (2 * i) + 1 assert output_walk.offset == (2* i) + 1 log.clear() assert storage_walk.count() == 0 assert storage_walk.offset == 0 assert output_walk.count() == 0 assert output_walk.offset == 0
def test_user_tick_optimization(usertick_gate, usertick_gate_opt): """Make sure the optimized version runs identically to the unoptimized.""" sg, sg_opt = usertick_gate, usertick_gate_opt for node in sg_opt.nodes: print(node) sim1 = SensorGraphSimulator(sg) sim1.stop_condition("run_time 10 minutes") sg.load_constants() sim1.record_trace() sim1.run() sim2 = SensorGraphSimulator(sg_opt) sim2.stop_condition("run_time 10 minutes") sg_opt.load_constants() sim2.record_trace() sim2.run() assert len(sim1.trace) == 0 assert len(sim2.trace) == 0 sim1.step(DataStream.FromString("system input 1034"), 1) sim2.step(DataStream.FromString("system input 1034"), 1) sim1.run() sim2.run() print("Unoptimized Output") for x in sim1.trace: print("%08d %s: %d" % (x.raw_time, DataStream.FromEncoded(x.stream), x.value)) print("\nOptimized Output") for x in sim2.trace: print("%08d %s: %d" % (x.raw_time, DataStream.FromEncoded(x.stream), x.value)) assert len(sim1.trace) == 4 assert len(sim2.trace) == 4 assert sim1.trace == sim2.trace
def test_important_inputs(): """Make sure we support matching important inputs and outputs.""" imp_stream = DataStream.FromString('system input 1024') imp_store_stream = DataStream.FromString('system input 1536') assert imp_stream.important is True assert imp_store_stream.important is True assert imp_stream.associated_stream() == DataStream.FromString( 'system output 1024') assert imp_store_stream.associated_stream() == DataStream.FromString( 'system buffered 1536') random_stream = DataStream.FromString('unbuffered 1024') assert random_stream.important is False with pytest.raises(InternalError): random_stream.associated_stream()
def test_fill_stop(): """Make sure we can configure SensorLog into fill-stop mode.""" model = DeviceModel() log = SensorLog(model=model) storage = DataStream.FromString('buffered 1') output = DataStream.FromString('output 1') reading = IOTileReading(0, 0, 1) # Neither fill-stop for _i in range(0, 50000): log.push(storage, reading) for _i in range(0, 50000): log.push(output, reading) log.clear() log.set_rollover('storage', False) with pytest.raises(StorageFullError): for _i in range(0, 50000): log.push(storage, reading) for _i in range(0, 50000): log.push(output, reading) assert log.count() == (16128, 48720) log.clear() log.set_rollover('streaming', False) with pytest.raises(StorageFullError): for _i in range(0, 50000): log.push(storage, reading) with pytest.raises(StorageFullError): for _i in range(0, 50000): log.push(output, reading) assert log.count() == (16128, 48896)
def test_encoding(): """Test data stream and selector encoding.""" sel = DataStreamSelector.FromString(u'all system output') assert sel.encode() == 0x5FFF sel = DataStreamSelector.FromString(u'all user output') assert sel.encode() == 0x57FF sel = DataStreamSelector.FromString(u'all output') assert sel.encode() == 0xD7FF sel = DataStreamSelector.FromString(u'all combined output') assert sel.encode() == 0xDFFF stream = DataStream.FromString('output 1') assert stream.encode() == 0x5001 stream = DataStream.FromString('unbuffered 10') assert stream.encode() == 0x100a
def callrpc_sg(): model = DeviceModel() log = SensorLog(model=model) sg = SensorGraph(log, model=model) sg.add_node( '(system input 2 always && constant 1 always) => unbuffered 2 using call_rpc' ) log.push(DataStream.FromString('constant 1'), IOTileReading(0, 0, 0x000a8000)) return sg
def test_when_block_on_event(parser): """Make sure on connect and on disconnect work.""" parser.parse_file(get_path(u'basic_when_on.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() sim = SensorGraphSimulator(sg) # We should only get a reading in unbuffered 1 on connect and unbuffered 2 on disconnect with pytest.raises(StreamEmptyError): log.inspect_last(DataStream.FromString('unbuffered 2')) sim.step(DataStream.FromString('system input 1025'), 8) assert log.inspect_last(DataStream.FromString('unbuffered 1')).value == 0 with pytest.raises(StreamEmptyError): log.inspect_last(DataStream.FromString('unbuffered 2')) sim.step(DataStream.FromString('system input 1026'), 8) assert log.inspect_last(DataStream.FromString('unbuffered 2')).value == 0
def declare_stream(string_name): """Create a StreamDeclaration from a string name. This will encode the string name into a 16-bit stream identifier. Args: string_name (str): The human-readable name of the stream. Returns: int: The stream declaration. """ return DataStream.FromString(string_name).encode()
def test_latch_block(parser): """Make sure that we can compile and run latch blocks.""" parser.parse_file(get_path(u'basic_latch.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() assert sg.get_tick('fast') == 1 # Now make sure it produces the right output counter15 = log.create_walker(DataStreamSelector.FromString('counter 15')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 60 seconds') sim.run() assert counter15.count() == 0 sim.step(DataStream.FromString('input 10'), 1) assert log.inspect_last(DataStream.FromString('constant 1')).value == 1 assert log.inspect_last(DataStream.FromString('constant 1024')).value == 1 counter15.skip_all() sim.run() assert counter15.count() == 60 counter15.skip_all() sim.step(DataStream.FromString('input 10'), 0) sim.run() assert counter15.count() == 0
def test_subtract_statement(parser): """Make sure we can copy data using subtract.""" parser.parse_file(get_path(u'basic_subtract.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() output1 = log.create_walker(DataStreamSelector.FromString('unbuffered 1')) output2 = log.create_walker(DataStreamSelector.FromString('unbuffered 2')) output3 = log.create_walker(DataStreamSelector.FromString('unbuffered 3')) sg.process_input(DataStream.FromString('input 1'), IOTileReading(0, 0, 15), None) sg.process_input(DataStream.FromString('input 2'), IOTileReading(0, 0, 20), None) sg.process_input(DataStream.FromString('input 3'), IOTileReading(0, 0, 25), None) assert output1.count() == 1 assert output2.count() == 1 assert output3.count() == 1 val1 = output1.pop() val2 = output2.pop() val3 = output3.pop() assert val1.value == 5 assert val2.value == 10 assert val3.value == 25