package sd; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.AfterEach; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import sd.model.TrafficLight; import sd.model.TrafficLightState; /** * Test class to verify traffic light coordination within an intersection. * Ensures that only ONE traffic light can be GREEN at any given time. */ public class TrafficLightCoordinationTest { private IntersectionProcess intersectionProcess; @BeforeEach public void setUp() throws IOException { // Create an intersection with multiple traffic lights intersectionProcess = new IntersectionProcess("Cr2", "src/main/resources/simulation.properties"); intersectionProcess.initialize(); } @AfterEach public void tearDown() throws InterruptedException { if (intersectionProcess != null) { intersectionProcess.shutdown(); } } /** * Test that verifies mutual exclusion between traffic lights. * Monitors all traffic lights for 10 seconds and ensures that * at most ONE light is GREEN at any point in time. */ @Test public void testOnlyOneGreenLightAtATime() throws InterruptedException { System.out.println("\n=== Testing Traffic Light Mutual Exclusion ==="); // Start the intersection Thread intersectionThread = new Thread(() -> { try { intersectionProcess.start(); } catch (IOException e) { e.printStackTrace(); } }); intersectionThread.start(); // Monitor traffic lights for violations AtomicInteger maxGreenSimultaneously = new AtomicInteger(0); AtomicInteger violationCount = new AtomicInteger(0); List violations = new ArrayList<>(); // Monitor for 10 seconds long endTime = System.currentTimeMillis() + 10000; while (System.currentTimeMillis() < endTime) { int greenCount = 0; StringBuilder currentState = new StringBuilder("States: "); for (TrafficLight light : intersectionProcess.getIntersection().getTrafficLights()) { TrafficLightState state = light.getState(); currentState.append(light.getDirection()).append("=").append(state).append(" "); if (state == TrafficLightState.GREEN) { greenCount++; } } // Update maximum simultaneous green lights if (greenCount > maxGreenSimultaneously.get()) { maxGreenSimultaneously.set(greenCount); } // Check for violations (more than one green) if (greenCount > 1) { violationCount.incrementAndGet(); String violation = String.format("[VIOLATION] %d lights GREEN simultaneously: %s", greenCount, currentState.toString()); violations.add(violation); System.err.println(violation); } Thread.sleep(50); // Check every 50ms } System.out.println("\n=== Test Results ==="); System.out.println("Maximum simultaneous GREEN lights: " + maxGreenSimultaneously.get()); System.out.println("Total violations detected: " + violationCount.get()); if (!violations.isEmpty()) { System.err.println("\nViolation details:"); violations.forEach(System.err::println); } // Assert that we never had more than one green light assertEquals(0, violationCount.get(), "Traffic light coordination violated! Multiple lights were GREEN simultaneously."); assertTrue(maxGreenSimultaneously.get() <= 1, "At most ONE light should be GREEN at any time. Found: " + maxGreenSimultaneously.get()); System.out.println("\nTraffic light coordination working correctly!"); } /** * Test that verifies all traffic lights get a chance to be GREEN. * Ensures fairness in the coordination mechanism. */ @Test public void testAllLightsGetGreenTime() throws InterruptedException { System.out.println("\n=== Testing Traffic Light Fairness ==="); // Start the intersection Thread intersectionThread = new Thread(() -> { try { intersectionProcess.start(); } catch (IOException e) { e.printStackTrace(); } }); intersectionThread.start(); // Track which lights have been green List lights = intersectionProcess.getIntersection().getTrafficLights(); boolean[] hasBeenGreen = new boolean[lights.size()]; // Monitor for 60 seconds (enough time for all lights to cycle: 18+18+12 = 48s) long endTime = System.currentTimeMillis() + 60000; while (System.currentTimeMillis() < endTime) { for (int i = 0; i < lights.size(); i++) { if (lights.get(i).getState() == TrafficLightState.GREEN) { hasBeenGreen[i] = true; System.out.println("✓ " + lights.get(i).getDirection() + " has been GREEN"); } } Thread.sleep(100); } // Check if all lights got green time int greenCount = 0; System.out.println("\n=== Fairness Results ==="); for (int i = 0; i < lights.size(); i++) { String status = hasBeenGreen[i] ? "✓ YES" : "✗ NO"; System.out.println(lights.get(i).getDirection() + " got GREEN time: " + status); if (hasBeenGreen[i]) greenCount++; } assertTrue(greenCount > 0, "At least one light should have been GREEN during the test"); System.out.println("\n" + greenCount + "/" + lights.size() + " lights were GREEN during test period"); } /** * Test that verifies the state transitions are consistent. */ @Test public void testStateTransitionsAreConsistent() throws InterruptedException { System.out.println("\n=== Testing State Transition Consistency ==="); Thread intersectionThread = new Thread(() -> { try { intersectionProcess.start(); } catch (IOException e) { e.printStackTrace(); } }); intersectionThread.start(); List lights = intersectionProcess.getIntersection().getTrafficLights(); TrafficLightState[] previousStates = new TrafficLightState[lights.size()]; // Initialize previous states for (int i = 0; i < lights.size(); i++) { previousStates[i] = lights.get(i).getState(); } int transitionCount = 0; long endTime = System.currentTimeMillis() + 8000; while (System.currentTimeMillis() < endTime) { for (int i = 0; i < lights.size(); i++) { TrafficLightState currentState = lights.get(i).getState(); if (currentState != previousStates[i]) { transitionCount++; System.out.println(lights.get(i).getDirection() + " transitioned: " + previousStates[i] + " → " + currentState); previousStates[i] = currentState; } } Thread.sleep(100); } System.out.println("\nTotal state transitions observed: " + transitionCount); assertTrue(transitionCount > 0, "There should be state transitions during the test period"); } }