feat: F4.6g1 the echo server and the generic client windows
Oracle EchoWindowRun uses Java's echo server and client windows as a person does; SaveAfterRunRun echo saves what Java keeps after the run. The room takes setActive with a port, connect/disconnect/send, sends both views and writes the server's port and the client's target back. The editor's windows show Java's buttons, fields and lines; a port that is no port is marked and not handed over (Java's button throws). Core fix: an empty message (one empty segment with the push, as Java's erstelleSegmente makes) counted as a repeat and never arrived. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
// Uses FILIUS' own echo server and generic client windows
|
||||
// (GUIApplicationServerBausteinWindow, GUIApplicationClientBausteinWindow on
|
||||
// their GUIDesktopPanels) on mail-lan's network as a person does: the
|
||||
// server's port field and start button, the client's address and port
|
||||
// fields, "Verbinden"/"Trennen", the message field and "Senden" — a port
|
||||
// that is no number too, an empty message, the server stopped while the
|
||||
// client is connected, a port nobody listens on, a name nobody knows. After
|
||||
// each step it writes what both windows show: the buttons' texts, the
|
||||
// fields (and whether they can be typed into), the lines. The reference for
|
||||
// the editor's echo windows (packages/sim/test/echoWindow.test.ts).
|
||||
//
|
||||
// Usage: java -cp filius.jar:lib/*:classes EchoWindowRun <scenario.json> <output json>
|
||||
|
||||
import filius.gui.anwendungssicht.GUIApplicationClientBausteinWindow;
|
||||
import filius.gui.anwendungssicht.GUIApplicationServerBausteinWindow;
|
||||
import filius.gui.anwendungssicht.GUIDesktopPanel;
|
||||
import filius.software.system.Betriebssystem;
|
||||
|
||||
import java.awt.FlowLayout;
|
||||
import java.io.FileOutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
public class EchoWindowRun {
|
||||
static final String CLIENT = "00000000-0000-0000-0000-000000000201";
|
||||
static final String SERVER = "00000000-0000-0000-0000-000000000203";
|
||||
|
||||
static final List<Object> steps = new ArrayList<>();
|
||||
static GUIApplicationServerBausteinWindow server;
|
||||
static GUIApplicationClientBausteinWindow client;
|
||||
/** Exceptions the windows' buttons threw on the event thread since the last step. */
|
||||
static final List<String> thrown = new ArrayList<>();
|
||||
|
||||
static Object field(Class<?> owner, Object object, String name) throws Exception {
|
||||
Field field = owner.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(object);
|
||||
}
|
||||
|
||||
static void onEdt(Runnable action) throws Exception {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
action.run();
|
||||
} catch (RuntimeException error) {
|
||||
synchronized (thrown) {
|
||||
thrown.add(error.getClass().getSimpleName() + ": " + error.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
Thread.sleep(400);
|
||||
}
|
||||
|
||||
static Map<String, Object> textField(JTextField field) {
|
||||
Map<String, Object> shown = new LinkedHashMap<>();
|
||||
shown.put("text", field.getText());
|
||||
shown.put("editable", field.isEditable());
|
||||
return shown;
|
||||
}
|
||||
|
||||
static void step(String name) throws Exception {
|
||||
Class<?> s = GUIApplicationServerBausteinWindow.class;
|
||||
Class<?> c = GUIApplicationClientBausteinWindow.class;
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("step", name);
|
||||
Map<String, Object> serverShown = new LinkedHashMap<>();
|
||||
serverShown.put("button", ((JButton) field(s, server, "bStartStop")).getText());
|
||||
serverShown.put("port", textField((JTextField) field(s, server, "tfPort")));
|
||||
serverShown.put("log", ((JTextArea) field(s, server, "taLog")).getText());
|
||||
result.put("server", serverShown);
|
||||
Map<String, Object> clientShown = new LinkedHashMap<>();
|
||||
clientShown.put("connect", ((JButton) field(c, client, "btVerbinden")).getText());
|
||||
clientShown.put("sendEnabled", ((JButton) field(c, client, "btSenden")).isEnabled());
|
||||
clientShown.put("address", textField((JTextField) field(c, client, "tfServerAdresse")));
|
||||
clientShown.put("port", textField((JTextField) field(c, client, "tfServerPort")));
|
||||
clientShown.put("message", ((JTextArea) field(c, client, "taSenden")).getText());
|
||||
clientShown.put("output", ((JTextArea) field(c, client, "taAusgabe")).getText());
|
||||
result.put("client", clientShown);
|
||||
synchronized (thrown) {
|
||||
result.put("thrown", new ArrayList<>(thrown));
|
||||
thrown.clear();
|
||||
}
|
||||
steps.add(result);
|
||||
}
|
||||
|
||||
static void type(Class<?> owner, Object window, String name, String text) throws Exception {
|
||||
Object component = field(owner, window, name);
|
||||
onEdt(() -> ((javax.swing.text.JTextComponent) component).setText(text));
|
||||
}
|
||||
|
||||
static void press(Class<?> owner, Object window, String name, long wait) throws Exception {
|
||||
JButton button = (JButton) field(owner, window, name);
|
||||
onEdt(button::doClick);
|
||||
Thread.sleep(wait);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
run(args);
|
||||
} catch (Throwable error) {
|
||||
error.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
static void run(String[] args) throws Exception {
|
||||
ScenarioNetwork network = ScenarioNetwork.read(args[0]);
|
||||
Betriebssystem serverSystem = (Betriebssystem) network.nodes.get(SERVER).getSystemSoftware();
|
||||
Betriebssystem clientSystem = (Betriebssystem) network.nodes.get(CLIENT).getSystemSoftware();
|
||||
serverSystem.installApp("filius.software.clientserver.ServerBaustein", false);
|
||||
clientSystem.installApp("filius.software.clientserver.ClientBaustein", false);
|
||||
network.start();
|
||||
Thread.sleep(500);
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
GUIDesktopPanel serverDesktop = new GUIDesktopPanel(serverSystem);
|
||||
GUIDesktopPanel clientDesktop = new GUIDesktopPanel(clientSystem);
|
||||
frame.getContentPane().setLayout(new FlowLayout());
|
||||
frame.getContentPane().add(serverDesktop);
|
||||
frame.getContentPane().add(clientDesktop);
|
||||
server = (GUIApplicationServerBausteinWindow) serverDesktop.starteAnwendung("filius.software.clientserver.ServerBaustein");
|
||||
client = (GUIApplicationClientBausteinWindow) clientDesktop.starteAnwendung("filius.software.clientserver.ClientBaustein");
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
});
|
||||
Thread.sleep(500);
|
||||
Class<?> s = GUIApplicationServerBausteinWindow.class;
|
||||
Class<?> c = GUIApplicationClientBausteinWindow.class;
|
||||
step("open");
|
||||
|
||||
type(s, server, "tfPort", "abc");
|
||||
press(s, server, "bStartStop", 500);
|
||||
step("server: start with port abc");
|
||||
type(s, server, "tfPort", "55555");
|
||||
press(s, server, "bStartStop", 1000);
|
||||
step("server: start with port 55555");
|
||||
|
||||
type(c, client, "tfServerAdresse", "192.168.0.30");
|
||||
type(c, client, "tfServerPort", "x");
|
||||
press(c, client, "btVerbinden", 500);
|
||||
step("client: connect with port x");
|
||||
type(c, client, "tfServerAdresse", "192.168.0.30");
|
||||
type(c, client, "tfServerPort", "55555");
|
||||
press(c, client, "btVerbinden", 6000);
|
||||
step("client: connect to 192.168.0.30:55555");
|
||||
type(c, client, "taSenden", "Hallo Echo");
|
||||
press(c, client, "btSenden", 4000);
|
||||
step("client: send Hallo Echo");
|
||||
type(c, client, "taSenden", "");
|
||||
press(c, client, "btSenden", 4000);
|
||||
step("client: send nothing");
|
||||
type(c, client, "taSenden", "Zeile 1\nZeile 2");
|
||||
press(c, client, "btSenden", 4000);
|
||||
step("client: send two lines");
|
||||
|
||||
press(s, server, "bStartStop", 4000);
|
||||
step("server: stop while connected");
|
||||
type(c, client, "taSenden", "noch da?");
|
||||
press(c, client, "btSenden", 8000);
|
||||
step("client: send after the server stopped");
|
||||
press(c, client, "btVerbinden", 3000);
|
||||
step("client: Trennen");
|
||||
|
||||
press(s, server, "bStartStop", 1000);
|
||||
step("server: start again");
|
||||
press(c, client, "btVerbinden", 6000);
|
||||
step("client: connect again");
|
||||
press(c, client, "btVerbinden", 3000);
|
||||
step("client: Trennen again");
|
||||
|
||||
type(c, client, "tfServerPort", "4711");
|
||||
press(c, client, "btVerbinden", 12000);
|
||||
step("client: connect to a port nobody listens on");
|
||||
type(c, client, "tfServerAdresse", "gibtsnicht");
|
||||
type(c, client, "tfServerPort", "55555");
|
||||
press(c, client, "btVerbinden", 12000);
|
||||
step("client: connect to a name nobody knows");
|
||||
|
||||
Map<String, Object> output = new LinkedHashMap<>();
|
||||
output.put("steps", steps);
|
||||
try (FileOutputStream out = new FileOutputStream(args[1])) {
|
||||
out.write((FlsOracle.Json.write(output, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
network.stop();
|
||||
System.out.println("echo window steps: " + steps.size());
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,17 @@
|
||||
// domain set to senior.org
|
||||
// dhcp einfaches_rechnernetz_komplett: the notebooks get their
|
||||
// addresses from the server (10 s)
|
||||
// echo email_komplett, with FILIUS' echo server installed on Rechner 2
|
||||
// and its client on Rechner 1 before the start: the server on port
|
||||
// 7777 (as its window sets it), the client connected to it, a
|
||||
// message sent, the client left connected
|
||||
|
||||
import filius.gui.GUIContainer;
|
||||
import filius.gui.netzwerksicht.GUIKnotenItem;
|
||||
import filius.hardware.knoten.Knoten;
|
||||
import filius.rahmenprogramm.SzenarioVerwaltung;
|
||||
import filius.software.clientserver.ClientBaustein;
|
||||
import filius.software.clientserver.ServerBaustein;
|
||||
import filius.software.email.Email;
|
||||
import filius.software.email.EmailAnwendung;
|
||||
import filius.software.email.EmailKonto;
|
||||
@@ -93,6 +99,10 @@ public class SaveAfterRunRun {
|
||||
if (story.equals("email")) {
|
||||
((Betriebssystem) system("Rechner 1")).installAndStartAppIfAvailable("filius.software.lokal.Terminal");
|
||||
}
|
||||
if (story.equals("echo")) {
|
||||
((Betriebssystem) system("Rechner 2")).installAndStartAppIfAvailable("filius.software.clientserver.ServerBaustein");
|
||||
((Betriebssystem) system("Rechner 1")).installAndStartAppIfAvailable("filius.software.clientserver.ClientBaustein");
|
||||
}
|
||||
network.start();
|
||||
Thread.sleep(2000);
|
||||
switch (story) {
|
||||
@@ -130,6 +140,22 @@ public class SaveAfterRunRun {
|
||||
case "dhcp":
|
||||
Thread.sleep(10000);
|
||||
break;
|
||||
case "echo": {
|
||||
// GUIApplicationServerBausteinWindow's start button, then its client's "Verbinden" and "Senden".
|
||||
ServerBaustein server = (ServerBaustein) system("Rechner 2").holeSoftware("filius.software.clientserver.ServerBaustein");
|
||||
server.setPort(7777);
|
||||
server.setAktiv(true);
|
||||
server.setPort(7777);
|
||||
Thread.sleep(1000);
|
||||
ClientBaustein client = (ClientBaustein) system("Rechner 1").holeSoftware("filius.software.clientserver.ClientBaustein");
|
||||
client.setZielIPAdresse(system("Rechner 2").primaryIPAdresse());
|
||||
client.setZielPort(7777);
|
||||
client.verbinden();
|
||||
Thread.sleep(6000);
|
||||
client.senden("Hallo");
|
||||
Thread.sleep(4000);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown story " + story);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user