Livt packages

Livt.Net

Version 1.4.1

Ethernet, IPv4, TCP, UDP, ARP, TFTP, and Telnet networking components for Livt hardware.

Published files (163)

tests/services/NetworkServiceTest.lvt

namespace Livt.Net.Tests

using Livt.Net

/**
 * Exercises successive protocol requests and held response ownership through a test link.
 */
@Test
component NetworkServiceTest
{
	// Shared request parsers; source remains owned by this fixture.
	ethernet: EthernetFrameParser<TestFrameReceiver<128>>
	ipv4: Ipv4PacketParser<EthernetFrameParser<TestFrameReceiver<128>>>

	receiver: TestFrameReceiver<128>
	service: NetworkService<TestFrameReceiver<128>>
	transmitter: TestFrameTransmitter<NetworkService<TestFrameReceiver<128>>>
	endpoint: FrameService<TestFrameReceiver<128>, NetworkService<TestFrameReceiver<128>>, TestFrameTransmitter<NetworkService<TestFrameReceiver<128>>>>

	/**
	 * Builds the fixed link, common service and lifecycle coordinator.
	 */
	new()
	{
		this.receiver = new TestFrameReceiver<128>()
		var mac: byte[6] = [0x00,0x00,0x5E,0x00,0xFA,0xCE]
		var ip: byte[4] = [10,0,0,1]
		this.ethernet = new EthernetFrameParser<TestFrameReceiver<128>>(this.receiver)
		this.ipv4 = new Ipv4PacketParser<EthernetFrameParser<TestFrameReceiver<128>>>(this.ethernet)
		this.service = new NetworkService<TestFrameReceiver<128>>(this.receiver, this.ethernet, this.ipv4, mac, ip)
		this.transmitter = new TestFrameTransmitter<NetworkService<TestFrameReceiver<128>>>(this.service)
		this.endpoint = new FrameService<TestFrameReceiver<128>, NetworkService<TestFrameReceiver<128>>, TestFrameTransmitter<NetworkService<TestFrameReceiver<128>>>>(this.receiver, this.service, this.transmitter)
	}

	/**
	 * Publishes a fresh initialized frame independently of response storage.
	 */
	fn Inject(frame: byte[60])
	{
		for (var i = 0; i < 60; i++) {
			assert this.receiver.InjectByte(i, frame[i]) == FrameLinkResult.Success
		}

		assert this.receiver.Publish(false, 0) == FrameLinkResult.Success
	}

	/**
	 * Checks every emitted byte and retained completion, then permits the next request.
	 */
	fn Complete(expected: byte[60])
	{
		for (var i = 0; i <= 60; i++) {
			this.transmitter.Advance()
		}

		assert this.endpoint.Poll() == FrameServiceProgress.Completed
		assert !this.service.IsReady()
		assert !this.transmitter.IsSourceBorrowed()
		var value: byte = 0xEE

		for (var i = 0; i < 60; i++) {
			assert this.transmitter.TryReadCaptured(i, value) == PacketDataResult.Success
			assert value == expected[i]
		}

		var outcome = FrameTransmitOutcome.DeviceFailure
		assert this.endpoint.TryGetCompletion(outcome) == FrameLinkResult.Success
		assert outcome == FrameTransmitOutcome.Delivered
		assert this.endpoint.Poll() == FrameServiceProgress.Completed
		assert this.endpoint.TryGetCompletion(outcome) == FrameLinkResult.Success
		assert outcome == FrameTransmitOutcome.Delivered
		assert this.endpoint.TryAcknowledgeCompletion() == FrameLinkResult.Success
		assert this.endpoint.TryGetCompletion(outcome) == FrameLinkResult.NotReady
	}

	/**
	 * Covers ARP/ICMP byte equivalence, admission stalls, busy graphs and terminal cleanup.
	 */
	@Test
	fn HandlesSuccessiveRequestsWithoutOverwritingHeldResponses()
	{
		assert this.endpoint.Poll() == FrameServiceProgress.Idle
		this.transmitter.SetReady(false)
		this.Inject(ServicePackets.ARP)
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		assert !this.receiver.HasReceiveFrame()
		assert this.service.GetResponseProtocol() == NetworkProtocol.Arp
		assert this.service.TryHandle() == ServiceResult.Busy
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		assert !this.transmitter.IsSourceBorrowed()
		assert this.service.IsReady()
		this.Inject(ServicePackets.ICMP)
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		assert this.receiver.HasReceiveFrame()
		assert !this.receiver.IsReady()
		assert this.service.GetResponseProtocol() == NetworkProtocol.Arp
		this.transmitter.SetReady(true)
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		assert this.transmitter.IsSourceBorrowed()
		assert this.service.TryHandle() == ServiceResult.Busy
		this.Complete(ServicePackets.ARP_REPLY)
		assert this.receiver.HasReceiveFrame()
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		assert !this.receiver.HasReceiveFrame()
		assert this.service.GetResponseProtocol() == NetworkProtocol.Icmp
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		this.Complete(ServicePackets.ICMP_REPLY)

		var unknown: byte[60] = ServicePackets.ARP
		unknown[12] = 0x88
		unknown[13] = 0xB5
		this.Inject(unknown)
		assert this.endpoint.Poll() == FrameServiceProgress.Ignored
		assert !this.service.IsReady()
		var value: byte = 0xEE
		assert this.service.TryRead(0, value) == PacketDataResult.NotReady
		assert value == 0x00
		assert this.receiver.InjectByte(0, 0x00) == FrameLinkResult.Success
		assert this.receiver.Publish(false, 0) == FrameLinkResult.Success
		assert this.endpoint.Poll() == FrameServiceProgress.Rejected
		assert !this.receiver.HasReceiveFrame()

		// A rejected admission cleans up the response without a TX borrow.
		this.Inject(ServicePackets.ARP)
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		this.transmitter.SetFailure(true)
		assert this.endpoint.Poll() == FrameServiceProgress.Completed
		assert !this.service.IsReady()
		var outcome = FrameTransmitOutcome.Delivered
		assert this.endpoint.TryGetCompletion(outcome) == FrameLinkResult.Success
		assert outcome == FrameTransmitOutcome.DeviceFailure
		assert this.endpoint.TryAcknowledgeCompletion() == FrameLinkResult.Success
		this.transmitter.SetFailure(false)

		// Cancellation acceptance never releases the graph before terminal quiescence.
		this.Inject(ServicePackets.ICMP)
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		assert this.endpoint.TryCancel() == FrameLinkResult.Accepted
		assert this.service.IsReady()
		assert this.endpoint.Poll() == FrameServiceProgress.Pending
		this.transmitter.Advance()
		assert this.endpoint.Poll() == FrameServiceProgress.Completed
		assert !this.service.IsReady()
		assert this.endpoint.TryGetCompletion(outcome) == FrameLinkResult.Success
		assert outcome == FrameTransmitOutcome.Cancelled
		assert this.endpoint.TryAcknowledgeCompletion() == FrameLinkResult.Success
	}
}