715 lines
32 KiB
Java
715 lines
32 KiB
Java
package jmri.server.json.util;
|
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
|
import com.fasterxml.jackson.databind.node.NullNode;
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
|
|
import java.io.DataOutputStream;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
import jmri.DccLocoAddress;
|
|
import jmri.InstanceManager;
|
|
import jmri.Metadata;
|
|
import jmri.Version;
|
|
import jmri.server.json.JsonServerPreferences;
|
|
import jmri.jmrit.display.Editor;
|
|
import jmri.jmrit.display.switchboardEditor.SwitchboardEditor;
|
|
import jmri.profile.NullProfile;
|
|
import jmri.profile.Profile;
|
|
import jmri.profile.ProfileManager;
|
|
import jmri.server.json.JSON;
|
|
import jmri.server.json.JsonException;
|
|
import jmri.server.json.JsonHttpServiceTestBase;
|
|
import jmri.server.json.JsonMockConnection;
|
|
import jmri.server.json.JsonRequest;
|
|
import jmri.util.JUnitUtil;
|
|
import jmri.util.junit.annotations.DisabledIfHeadless;
|
|
import jmri.util.node.NodeIdentity;
|
|
import jmri.util.zeroconf.ZeroConfService;
|
|
import jmri.web.server.WebServerPreferences;
|
|
|
|
import org.junit.jupiter.api.*;
|
|
import org.junit.jupiter.api.io.TempDir;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
/**
|
|
*
|
|
* @author Randall Wood Copyright 2018
|
|
*/
|
|
public class JsonUtilHttpServiceTest extends JsonHttpServiceTestBase<JsonUtilHttpService> {
|
|
|
|
@BeforeEach
|
|
public void setUp(@TempDir File folder) throws Exception {
|
|
super.setUp();
|
|
service = new JsonUtilHttpService(mapper);
|
|
JUnitUtil.resetWindows(true, false); // list open windows when running tests
|
|
JUnitUtil.resetNodeIdentity();
|
|
JUnitUtil.resetProfileManager(new NullProfile("JsonUtilHttpServiceTest", "12345678", folder));
|
|
JUnitUtil.initConnectionConfigManager();
|
|
JUnitUtil.initZeroConfServiceManager();
|
|
// Initialize mock PermissionManager for session authentication tests
|
|
InstanceManager.store(new MockPermissionManager(), jmri.PermissionManager.class);
|
|
}
|
|
|
|
@AfterEach
|
|
@Override
|
|
public void tearDown() throws Exception {
|
|
assertTrue(JUnitUtil.resetZeroConfServiceManager());
|
|
JUnitUtil.clearShutDownManager();
|
|
super.tearDown();
|
|
}
|
|
|
|
/**
|
|
* Test of doGet method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if test fails in an unexpected
|
|
* manner
|
|
*/
|
|
@Test
|
|
public void testDoGet() throws JsonException {
|
|
InstanceManager.getDefault(JsonServerPreferences.class).setHeartbeatInterval(10);
|
|
assertEquals(service.getHello(10, new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGet(JSON.HELLO, null, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getMetadata(locale, Metadata.JMRIVERCANON, 42), service.doGet(JSON.METADATA, Metadata.JMRIVERCANON, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getMetadata(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGet(JSON.METADATA, null, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getNode(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGet(JSON.NODE, null, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getNetworkServices(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGet(JSON.NETWORK_SERVICE, null, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getNetworkServices(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGet(JSON.NETWORK_SERVICES, null, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
|
|
JsonException ex = assertThrows(JsonException.class, () ->
|
|
service.doGet(JSON.NETWORK_SERVICE, JSON.ZEROCONF_SERVICE_TYPE,
|
|
NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)),
|
|
"Expected exception not thrown.");
|
|
assertEquals(404, ex.getCode());
|
|
|
|
ex = assertThrows(JsonException.class, () ->
|
|
service.doGet("INVALID TYPE TOKEN", null, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)),
|
|
"Expected exception not thrown.");
|
|
assertEquals(500, ex.getCode());
|
|
|
|
ZeroConfService zcs = ZeroConfService.create(JSON.ZEROCONF_SERVICE_TYPE, 9999);
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == false;
|
|
}, "zcs.isPublished did not go false");
|
|
zcs.publish();
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == true;
|
|
}, "Published ZeroConf Service");
|
|
assertEquals(service.getNetworkService(JSON.ZEROCONF_SERVICE_TYPE,
|
|
new JsonRequest (locale, JSON.V5, JSON.GET, 42)),
|
|
service.doGet(JSON.NETWORK_SERVICE, JSON.ZEROCONF_SERVICE_TYPE,
|
|
NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
zcs.stop();
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == false;
|
|
},"zcs.isPublished did not go false after stop");
|
|
}
|
|
|
|
/**
|
|
* Test of doGetList method, of class JsonUtilHttpService. Verifies that
|
|
* JSON types that are lists are reported the same if requested using GET or
|
|
* LIST methods.
|
|
*
|
|
* @throws jmri.server.json.JsonException if test fails in an unexpected
|
|
* manner
|
|
*/
|
|
@Test
|
|
public void testDoGetList() throws JsonException {
|
|
InstanceManager.getDefault(JsonServerPreferences.class).setHeartbeatInterval(10);
|
|
assertEquals(service.getMetadata(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGetList(JSON.METADATA, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getNetworkServices(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGetList(JSON.NETWORK_SERVICES, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getSystemConnections(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGetList(JSON.SYSTEM_CONNECTIONS, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
assertEquals(service.getConfigProfiles(new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doGetList(JSON.CONFIG_PROFILES, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
}
|
|
|
|
/**
|
|
* Test of doPost method, of class JsonUtilHttpService. Verifies that POST
|
|
* and GET requests for HELLO message are the same.
|
|
*
|
|
* @throws jmri.server.json.JsonException if fails unexpectedly
|
|
*/
|
|
@Test
|
|
public void testDoPost() throws JsonException {
|
|
String type = JSON.HELLO;
|
|
String name = JSON.HELLO;
|
|
assertEquals(service.doGet(type, name, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)), service.doPost(type, name, NullNode.getInstance(), new JsonRequest(locale, JSON.V5, JSON.GET, 42)));
|
|
}
|
|
|
|
/**
|
|
* Test of getHello method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if messages are not schema valid
|
|
*/
|
|
@Test
|
|
public void testGetHello() throws JsonException {
|
|
int heartbeat = 1000; // one second
|
|
JsonNode result = service.getHello(heartbeat, new JsonRequest(locale, JSON.V5, JSON.GET, 0));
|
|
validate(result);
|
|
assertEquals( JSON.HELLO, result.path(JSON.TYPE).asText(), "Hello type");
|
|
JsonNode data = result.path(JSON.DATA);
|
|
assertEquals( Version.name(), data.path(JSON.JMRI).asText(), "JMRI Version");
|
|
assertEquals( JSON.V5_PROTOCOL_VERSION, data.path(JSON.JSON).asText(), "JSON Complete Version");
|
|
assertEquals( JSON.V5, data.path(JSON.VERSION).asText(), "JSON Version Identifier");
|
|
assertEquals( Math.round(heartbeat * 0.9f), data.path(JSON.HEARTBEAT).asInt(), "Heartbeat");
|
|
assertEquals( InstanceManager.getDefault(WebServerPreferences.class).getRailroadName(), data.path(JSON.RAILROAD).asText(),
|
|
"RR Name");
|
|
assertEquals( NodeIdentity.networkIdentity(), data.path(JSON.NODE).asText(), "Node Identity");
|
|
Profile profile = ProfileManager.getDefault().getActiveProfile();
|
|
assertNotNull(profile);
|
|
assertEquals( profile.getName(), data.path(JSON.ACTIVE_PROFILE).asText(), "Profile");
|
|
assertEquals( 2, result.size(), "Message has 2 elements");
|
|
assertEquals( 7, data.size(), "Message data has 7 elements");
|
|
result = service.getHello(heartbeat, new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
data = result.path(JSON.DATA);
|
|
assertEquals( 3, result.size(), "Message has 2 elements");
|
|
assertEquals( 7, data.size(), "Message data has 7 elements");
|
|
}
|
|
|
|
/**
|
|
* Test of getMetadata method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if messages are not schema valid
|
|
*/
|
|
@Test
|
|
public void testGetMetadata_Locale_String() throws JsonException {
|
|
JsonNode result;
|
|
for (String metadata : Metadata.getSystemNameList()) {
|
|
result = service.getMetadata(locale, metadata, 42);
|
|
validate(result);
|
|
assertEquals(JSON.METADATA, result.path(JSON.TYPE).asText());
|
|
assertEquals(metadata, result.path(JSON.DATA).path(JSON.NAME).asText());
|
|
assertEquals(Metadata.getBySystemName(metadata), result.path(JSON.DATA).path(JSON.VALUE).asText());
|
|
}
|
|
JsonException ex = assertThrows(JsonException.class, () ->
|
|
service.getMetadata(locale, "invalid_metadata_entry", 42),
|
|
"Expected exception not thrown");
|
|
assertEquals(404, ex.getCode());
|
|
}
|
|
|
|
/**
|
|
* Test of getMetadata method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if messages are not schema valid
|
|
*/
|
|
@Test
|
|
public void testGetMetadata_Locale() throws JsonException {
|
|
JsonNode result = service.getMetadata(new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
assertEquals(Metadata.getSystemNameList().size(), result.size());
|
|
}
|
|
|
|
/**
|
|
* Test of getNetworkServices method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if messages are not schema valid
|
|
*/
|
|
@Test
|
|
public void testGetNetworkServices() throws JsonException {
|
|
// no services published
|
|
JsonNode result = service.getNetworkServices(new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
assertEquals(0, result.size());
|
|
// publish a service
|
|
ZeroConfService zcs = ZeroConfService.create(JSON.ZEROCONF_SERVICE_TYPE, 9999);
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == false;
|
|
},"zcs.isPublished did not go false");
|
|
zcs.publish();
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == true;
|
|
}, "Published ZeroConf Service");
|
|
result = service.getNetworkServices(new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
assertEquals(1, result.size());
|
|
assertEquals(JSON.NETWORK_SERVICE, result.get(0).path(JSON.TYPE).asText());
|
|
JsonNode data = result.get(0).path(JSON.DATA);
|
|
assertFalse(data.isMissingNode());
|
|
assertEquals(InstanceManager.getDefault(WebServerPreferences.class).getRailroadName(), data.path(JSON.USERNAME).asText());
|
|
assertEquals(9999, data.path(JSON.PORT).asInt());
|
|
assertEquals(JSON.ZEROCONF_SERVICE_TYPE, data.path(JSON.TYPE).asText());
|
|
assertEquals(NodeIdentity.networkIdentity(), data.path(JSON.NODE).asText());
|
|
assertEquals(Metadata.getBySystemName(Metadata.JMRIVERCANON), data.path("jmri").asText());
|
|
assertEquals(Metadata.getBySystemName(Metadata.JMRIVERSION), data.path("version").asText());
|
|
zcs.stop();
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == false;
|
|
},"zcs.isPublished did not go false after stop");
|
|
}
|
|
|
|
/**
|
|
* Test of getNode method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if messages are not schema valid
|
|
*/
|
|
@Test
|
|
public void testGetNode() throws JsonException {
|
|
JsonNode result = service.getNode(new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
// We should have a single node with no history of nodes
|
|
// There are 3 "former" IDs when there is no history
|
|
assertEquals(JSON.NODE, result.path(JSON.TYPE).asText());
|
|
assertEquals(NodeIdentity.networkIdentity(), result.path(JSON.DATA).path(JSON.NODE).asText());
|
|
JsonNode nodes = result.path(JSON.DATA).path(JSON.FORMER_NODES);
|
|
assertTrue(nodes.isArray());
|
|
// Use whatever is returned by formerIdentities to avoid setup issues
|
|
// when running within an IDE
|
|
assertEquals(NodeIdentity.formerIdentities().size(), nodes.size());
|
|
}
|
|
|
|
/**
|
|
* Test of getSystemConnection method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if connection name not found
|
|
*/
|
|
@Test
|
|
public void testGetSystemConnection() throws JsonException {
|
|
JsonNode result = service.getSystemConnection("Internal", new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
// We should get back type, data and id
|
|
assertEquals(3, result.size());
|
|
// Data should exist and have at least 4 elements
|
|
assertTrue(result.path(JSON.DATA).size() >= 4);
|
|
assertEquals(JSON.SYSTEM_CONNECTION, result.path(JSON.TYPE).asText());
|
|
assertEquals("I", result.path(JSON.DATA).path(JSON.PREFIX).asText());
|
|
assertEquals("Internal", result.path(JSON.DATA).path(JSON.NAME).asText());
|
|
assertTrue(result.path(JSON.DATA).path(JSON.MFG).isNull());
|
|
}
|
|
|
|
/**
|
|
* Test of getSystemConnections method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if messages are not schema valid
|
|
*/
|
|
@Test
|
|
public void testGetSystemConnections() throws JsonException {
|
|
JsonNode result = service.getSystemConnections(new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
// We should only have one internal connection
|
|
assertEquals(1, result.size());
|
|
JsonNode connection = result.get(0);
|
|
assertEquals(JSON.SYSTEM_CONNECTION, connection.path(JSON.TYPE).asText());
|
|
assertEquals("I", connection.path(JSON.DATA).path(JSON.PREFIX).asText());
|
|
assertEquals("Internal", connection.path(JSON.DATA).path(JSON.NAME).asText());
|
|
assertTrue(connection.path(JSON.DATA).path(JSON.MFG).isNull());
|
|
}
|
|
|
|
/**
|
|
* Test of getNetworkService method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if test fails in an unexpected
|
|
* manner
|
|
*/
|
|
@Test
|
|
public void testGetNetworkService() throws JsonException {
|
|
JsonNode result;
|
|
// non-existent service
|
|
JsonException ex = assertThrows( JsonException.class, () ->
|
|
service.getNetworkService("non-existant-service",
|
|
new JsonRequest(locale, JSON.V5, JSON.GET, 42)),
|
|
"Expected exception not thrown ");
|
|
assertEquals(HttpServletResponse.SC_NOT_FOUND, ex.getCode());
|
|
|
|
// published service
|
|
ZeroConfService zcs = ZeroConfService.create(JSON.ZEROCONF_SERVICE_TYPE, 9999);
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == false;
|
|
},"zcs.isPublished did not go false");
|
|
zcs.publish();
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == true;
|
|
}, "Published ZeroConf Service");
|
|
result = service.getNetworkService(JSON.ZEROCONF_SERVICE_TYPE, new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
assertEquals(JSON.NETWORK_SERVICE, result.path(JSON.TYPE).asText());
|
|
JsonNode data = result.path(JSON.DATA);
|
|
assertFalse(data.isMissingNode());
|
|
assertEquals(InstanceManager.getDefault(WebServerPreferences.class).getRailroadName(), data.path(JSON.USERNAME).asText());
|
|
assertEquals(9999, data.path(JSON.PORT).asInt());
|
|
assertEquals(JSON.ZEROCONF_SERVICE_TYPE, data.path(JSON.TYPE).asText());
|
|
assertEquals(NodeIdentity.networkIdentity(), data.path(JSON.NODE).asText());
|
|
assertEquals(Metadata.getBySystemName(Metadata.JMRIVERCANON), data.path("jmri").asText());
|
|
assertEquals(Metadata.getBySystemName(Metadata.JMRIVERSION), data.path("version").asText());
|
|
zcs.stop();
|
|
JUnitUtil.waitFor(() -> {
|
|
return zcs.isPublished() == false;
|
|
},"zcs.isPublished did not go false after stop");
|
|
}
|
|
|
|
/**
|
|
* Test of getRailroad method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if messages are not schema valid
|
|
*/
|
|
@Test
|
|
public void testGetRailroad() throws JsonException {
|
|
JsonNode result = service.getRailroad(new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
assertEquals(JSON.RAILROAD, result.path(JSON.TYPE).asText());
|
|
JsonNode data = result.path(JSON.DATA);
|
|
assertEquals(InstanceManager.getDefault(WebServerPreferences.class).getRailroadName(),
|
|
data.path(JSON.NAME).asText());
|
|
}
|
|
|
|
/**
|
|
* Test of getPanel method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if the result cannot be validated
|
|
*/
|
|
@Test
|
|
@DisabledIfHeadless
|
|
public void testGetPanel() throws JsonException {
|
|
Editor editor = new SwitchboardEditor("test");
|
|
ObjectNode result = service.getPanel(editor, JSON.XML, 42);
|
|
validate(result);
|
|
JUnitUtil.dispose(editor.getTargetFrame());
|
|
JUnitUtil.dispose(editor);
|
|
}
|
|
|
|
/**
|
|
* Test of getPanels method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if the result cannot be validated
|
|
*/
|
|
@Test
|
|
@DisabledIfHeadless
|
|
public void testGetPanels_Locale_String() throws JsonException {
|
|
Editor editor = new SwitchboardEditor("test");
|
|
JsonNode result = service.getPanels(JSON.XML, 42);
|
|
validate(result);
|
|
JUnitUtil.dispose(editor.getTargetFrame());
|
|
JUnitUtil.dispose(editor);
|
|
}
|
|
|
|
/**
|
|
* Test of getPanels method, of class JsonUtilHttpService.
|
|
*
|
|
* @throws jmri.server.json.JsonException if the result cannot be validated
|
|
*/
|
|
@Test
|
|
@DisabledIfHeadless
|
|
public void testGetPanels_Locale() throws JsonException {
|
|
Editor editor = new SwitchboardEditor("test");
|
|
JsonNode result = service.getPanels(42);
|
|
validate(result);
|
|
JUnitUtil.dispose(editor.getTargetFrame());
|
|
JUnitUtil.dispose(editor);
|
|
}
|
|
|
|
/**
|
|
* Test of getConfigProfile method, of class JsonUtilHttpService.
|
|
* only runs negative test that a profile is not found
|
|
*
|
|
*/
|
|
@Test
|
|
public void testGetConfigProfile() {
|
|
JsonException ex = assertThrows( JsonException.class, () ->
|
|
service.getConfigProfile("non-existent-profile", new JsonRequest(locale, JSON.V5, JSON.GET, 42)),
|
|
"Expected exception not thrown");
|
|
assertEquals(HttpServletResponse.SC_NOT_FOUND, ex.getCode());
|
|
|
|
}
|
|
|
|
/**
|
|
* Test of getConfigProfiles method, of class JsonUtilHttpService. Only
|
|
* tests that result is schema valid and contains all profiles.
|
|
*
|
|
* @throws jmri.server.json.JsonException if unable to read profiles
|
|
*/
|
|
@Test
|
|
public void testGetConfigProfiles() throws JsonException {
|
|
ArrayNode result = service.getConfigProfiles(new JsonRequest(locale, JSON.V5, JSON.GET, 42));
|
|
validate(result);
|
|
assertEquals( ProfileManager.getDefault().getProfiles().length, result.size(), "Result has every profile");
|
|
}
|
|
|
|
/**
|
|
* Test of addressForString method, of class JsonUtilHttpService.
|
|
*/
|
|
@Test
|
|
public void testAddressForString() {
|
|
DccLocoAddress result = JsonUtilHttpService.addressForString("123(l)");
|
|
assertTrue( result.isLongAddress(), "Address is long");
|
|
assertEquals( 123, result.getNumber(), "Address is 123");
|
|
result = JsonUtilHttpService.addressForString("123(L)");
|
|
assertTrue( result.isLongAddress(), "Address is long");
|
|
assertEquals( 123, result.getNumber(), "Address is 123");
|
|
result = JsonUtilHttpService.addressForString("123(s)");
|
|
assertFalse( result.isLongAddress(), "Address is short");
|
|
assertEquals( 123, result.getNumber(), "Address is 123");
|
|
result = JsonUtilHttpService.addressForString("123");
|
|
assertFalse( result.isLongAddress(), "Address is short");
|
|
assertEquals( 123, result.getNumber(), "Address is 123");
|
|
result = JsonUtilHttpService.addressForString("3");
|
|
assertFalse( result.isLongAddress(), "Address is short");
|
|
assertEquals( 3, result.getNumber(), "Address is 3");
|
|
result = JsonUtilHttpService.addressForString("3(l)");
|
|
assertTrue( result.isLongAddress(), "Address is long");
|
|
assertEquals( 3, result.getNumber(), "Address is 3");
|
|
}
|
|
|
|
/**
|
|
* Test of postSessionLogin method with valid credentials.
|
|
*
|
|
* @throws jmri.server.json.JsonException if test fails unexpectedly
|
|
*/
|
|
@Test
|
|
public void testPostSessionLoginSuccess() throws JsonException {
|
|
// Create login request data
|
|
ObjectNode data = mapper.createObjectNode();
|
|
data.put("username", "testuser");
|
|
data.put("password", "testpass");
|
|
|
|
// Mock a successful login by setting up the permission system
|
|
// In actual usage, this would check against configured users
|
|
// For test purposes, we'll just verify the method handles the call
|
|
|
|
try {
|
|
JsonNode result = service.doPost(JSON.SESSION_LOGIN, "testuser", data,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
|
|
assertNotNull(result, "Result should not be null");
|
|
assertEquals(JSON.SESSION_LOGIN, result.path(JSON.TYPE).asText(), "Type should be sessionLogin");
|
|
JsonNode dataNode = result.path(JSON.DATA);
|
|
assertNotNull(dataNode, "Data node should not be null");
|
|
|
|
// Verify response structure (success field may or may not be present depending on actual login)
|
|
assertTrue(dataNode.has(JSON.USERNAME) || result.path(JSON.TYPE).asText().equals(JSON.SESSION_LOGIN),
|
|
"Response should have username or be sessionLogin type");
|
|
} catch (JsonException ex) {
|
|
// Expected for unauthorized user in test environment
|
|
assertTrue(ex.getCode() == 401 || ex.getCode() == 403,
|
|
"Should be unauthorized (401) or forbidden (403) for test user");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test of postSessionLogin method with missing username.
|
|
*/
|
|
@Test
|
|
public void testPostSessionLoginMissingUsername() {
|
|
ObjectNode data = mapper.createObjectNode();
|
|
data.put("password", "testpass");
|
|
|
|
JsonException ex = assertThrows(JsonException.class, () -> {
|
|
service.doPost(JSON.SESSION_LOGIN, null, data,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
});
|
|
|
|
assertEquals(400, ex.getCode(), "Should be bad request (400)");
|
|
assertTrue(ex.getMessage().contains("username") || ex.getMessage().contains("parameter"),
|
|
"Error message should mention username or missing parameter");
|
|
}
|
|
|
|
/**
|
|
* Test of postSessionLogin method with guest user.
|
|
*/
|
|
@Test
|
|
public void testPostSessionLoginGuestUser() {
|
|
ObjectNode data = mapper.createObjectNode();
|
|
data.put("username", "guest");
|
|
data.put("password", "");
|
|
|
|
// Guest users should be rejected
|
|
JsonException ex = assertThrows(JsonException.class, () -> {
|
|
service.doPost(JSON.SESSION_LOGIN, "guest", data,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
});
|
|
|
|
assertEquals(403, ex.getCode(), "Should be forbidden (403) for guest user");
|
|
assertTrue(ex.getMessage().toLowerCase().contains("guest"),
|
|
"Error message should mention guest");
|
|
}
|
|
|
|
/**
|
|
* Test of postSessionLogin method with guest user (should fail).
|
|
*/
|
|
@Test
|
|
public void testPostSessionLoginInvalidCredentials() {
|
|
ObjectNode data = mapper.createObjectNode();
|
|
data.put("username", "guest");
|
|
data.put("password", "anypassword");
|
|
|
|
JsonException ex = assertThrows(JsonException.class, () -> {
|
|
service.doPost(JSON.SESSION_LOGIN, "guest", data,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
});
|
|
|
|
assertEquals(403, ex.getCode(), "Should be forbidden (403) for guest user");
|
|
}
|
|
|
|
/**
|
|
* Test of postSessionLogout method.
|
|
*
|
|
* @throws jmri.server.json.JsonException if test fails unexpectedly
|
|
*/
|
|
@Test
|
|
public void testPostSessionLogout() throws JsonException {
|
|
ObjectNode data = mapper.createObjectNode();
|
|
data.put("token", "test-token-12345");
|
|
data.put(JSON.USERNAME, "testuser");
|
|
|
|
JsonNode result = service.doPost(JSON.SESSION_LOGOUT, "testuser", data,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
|
|
assertNotNull(result, "Result should not be null");
|
|
assertEquals(JSON.SESSION_LOGOUT, result.path(JSON.TYPE).asText(), "Type should be sessionLogout");
|
|
JsonNode dataNode = result.path(JSON.DATA);
|
|
assertNotNull(dataNode, "Data node should not be null");
|
|
assertEquals("test-token-12345", dataNode.path("authenticationToken").asText(), "Should return the token");
|
|
}
|
|
|
|
/**
|
|
* Test of postSessionLogout method with empty token.
|
|
*
|
|
* @throws jmri.server.json.JsonException if test fails unexpectedly
|
|
*/
|
|
@Test
|
|
public void testPostSessionLogoutEmptyToken() throws JsonException {
|
|
ObjectNode data = mapper.createObjectNode();
|
|
data.put("token", "");
|
|
|
|
// Logout should still succeed even with empty token
|
|
JsonNode result = service.doPost(JSON.SESSION_LOGOUT, null, data,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
|
|
assertNotNull(result, "Result should not be null");
|
|
assertEquals(JSON.SESSION_LOGOUT, result.path(JSON.TYPE).asText(), "Type should be sessionLogout");
|
|
}
|
|
|
|
/**
|
|
* Test session login/logout through socket service integration.
|
|
*
|
|
* @throws java.io.IOException if test fails unexpectedly
|
|
* @throws jmri.JmriException if test fails unexpectedly
|
|
* @throws jmri.server.json.JsonException if test fails unexpectedly
|
|
*/
|
|
@Test
|
|
public void testSocketServiceSessionMessages() throws IOException, jmri.JmriException, JsonException {
|
|
JsonMockConnection connection = new JsonMockConnection((DataOutputStream) null);
|
|
JsonUtilSocketService socketService = new JsonUtilSocketService(connection);
|
|
ObjectMapper testMapper = connection.getObjectMapper();
|
|
|
|
// Test LOGIN message
|
|
ObjectNode loginData = testMapper.createObjectNode();
|
|
loginData.put("username", "testuser");
|
|
loginData.put("password", "testpass");
|
|
|
|
try {
|
|
socketService.onMessage(JSON.SESSION_LOGIN, loginData,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
JsonNode message = connection.getMessage();
|
|
// Message should either be success or error (depending on permission setup)
|
|
assertNotNull(message, "Should receive a response message");
|
|
} catch (JsonException ex) {
|
|
// Expected if no valid user configured
|
|
assertTrue(ex.getCode() == 401 || ex.getCode() == 403,
|
|
"Should be auth error for test environment");
|
|
}
|
|
|
|
// Test LOGOUT message
|
|
ObjectNode logoutData = testMapper.createObjectNode();
|
|
logoutData.put("token", "test-token");
|
|
logoutData.put(JSON.USERNAME, "testuser");
|
|
|
|
socketService.onMessage(JSON.SESSION_LOGOUT, logoutData,
|
|
new JsonRequest(locale, JSON.V5, JSON.POST, 42));
|
|
JsonNode message = connection.getMessage();
|
|
assertNotNull(message, "Should receive logout response message");
|
|
assertEquals(JSON.SESSION_LOGOUT, message.path(JSON.TYPE).asText(),
|
|
"Response type should be sessionLogout");
|
|
}
|
|
|
|
/**
|
|
* Mock PermissionManager for testing session authentication.
|
|
*/
|
|
private static class MockPermissionManager implements jmri.PermissionManager {
|
|
@Override
|
|
public boolean remoteLogin(StringBuilder sessionId, java.util.Locale locale,
|
|
String username, String password) {
|
|
// Reject guest users
|
|
if ("guest".equals(username)) {
|
|
return false;
|
|
}
|
|
// Accept any non-guest user for testing
|
|
sessionId.append("test-session-").append(username);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void remoteLogout(String sessionId) {
|
|
// No-op for testing
|
|
}
|
|
|
|
@Override
|
|
public boolean isAGuestUser(String username) {
|
|
return "guest".equals(username);
|
|
}
|
|
|
|
@Override
|
|
public boolean isAGuestUser(jmri.User user) {
|
|
return user != null && isAGuestUser(user.getUserName());
|
|
}
|
|
|
|
// Stub implementations for other required methods
|
|
@Override
|
|
public jmri.Role addRole(String name) { return null; }
|
|
@Override
|
|
public void removeRole(String name) {}
|
|
@Override
|
|
public jmri.User addUser(String username, String password) { return null; }
|
|
@Override
|
|
public void removeUser(String username) {}
|
|
@Override
|
|
public void changePassword(String newPassword, String oldPassword) {}
|
|
@Override
|
|
public boolean login(String username, String password) { return false; }
|
|
@Override
|
|
public void logout() {}
|
|
@Override
|
|
public String getCurrentUserName() { return null; }
|
|
@Override
|
|
public boolean isCurrentUser(String username) { return false; }
|
|
@Override
|
|
public boolean isCurrentUser(jmri.User user) { return false; }
|
|
@Override
|
|
public boolean isCurrentUserPermittedToChangePassword() { return false; }
|
|
@Override
|
|
public boolean isLoggedIn() { return false; }
|
|
@Override
|
|
public boolean isRemotelyLoggedIn(String sessionId) { return false; }
|
|
@Override
|
|
public void addLoginListener(LoginListener listener) {}
|
|
@Override
|
|
public boolean isEnabled() { return true; }
|
|
@Override
|
|
public void setEnabled(boolean enabled) {}
|
|
@Override
|
|
public boolean isAllowEmptyPasswords() { return false; }
|
|
@Override
|
|
public void setAllowEmptyPasswords(boolean value) {}
|
|
@Override
|
|
public boolean hasAtLeastPermission(jmri.Permission permission, jmri.PermissionValue minValue) { return true; }
|
|
@Override
|
|
public boolean hasAtLeastRemotePermission(String sessionId, jmri.Permission permission, jmri.PermissionValue minValue) { return true; }
|
|
@Override
|
|
public boolean ensureAtLeastPermission(jmri.Permission permission, jmri.PermissionValue minValue) { return true; }
|
|
@Override
|
|
public void registerOwner(jmri.PermissionOwner owner) {}
|
|
@Override
|
|
public void registerPermission(jmri.Permission permission) {}
|
|
@Override
|
|
public void storePermissionSettings() {}
|
|
}
|
|
}
|
|
|