@Test
	public void testRefreshBreakpoints() throws Exception {
		try (JshellAndConnection conn = startAndConnectJshell()) {
			start(conn, "HelloWorld.class");

			RemoteMethod refreshBreakpoints = conn.getMethod("refresh_breakpoints");
			RemoteMethod stepInto = conn.getMethod("step_into");
			try (ManagedDomainObject mdo = openDomainObject("/New Traces/HelloWorld.class")) {
				tb = new ToyDBTraceBuilder((Trace) mdo.get());
				txPut(conn, "Threads");

				TraceObject thread = waitForObject("VMs[].Threads[main]");
				stepInto.invoke(Map.of("thread", thread));
				waitTxDone();

				conn.execute("VirtualMachine vm = manager.getCurrentVM();");
				conn.execute("Location loc = manager.getCurrentLocation();");
				conn.execute(
					"BreakpointRequest brkReq = vm.eventRequestManager().createBreakpointRequest(loc);");

				TraceObject brkSet = waitForObject("VMs[].Breakpoints");
				List<TraceObjectValue> brks = waitForPass(() -> {
					refreshBreakpoints.invoke(Map.of("container", brkSet));
					List<TraceObjectValue> d = waitForValues("VMs[].Breakpoints[]");
					assertEquals(1, d.size());
					return d;
				});
				assertTrue(brks.get(0).getEntryKey().contains("breakpoint request"));

				conn.execute(
					"String path = \"VMs[OpenJDK 64-Bit Server VM].Classes[java.lang.Thread]\";");
				conn.execute(
					"ReferenceType reftype = (ReferenceType) jdiManager.objForPath(path);");
				conn.execute("Field field = reftype.fieldByName(\"tid\");");
				conn.execute(
					"AccessWatchpointRequest brkReq = vm.eventRequestManager().createAccessWatchpointRequest(field);");

				TraceObject brkSet2 = waitForObject("VMs[].Breakpoints");
				brks = waitForPass(() -> {
					refreshBreakpoints.invoke(Map.of("container", brkSet2));
					List<TraceObjectValue> d = waitForValues("VMs[].Breakpoints[]");
					assertEquals(2, d.size());
					return d;
				});
				assertTrue(brks.get(0).getEntryKey().contains("access watchpoint request"));
			}
		}
	}
Because we control the target artifact, we know the steps precisely. NOTE: This must be the
same at least for step_into and step_over, otherwise, we can't know for sure step_over
actually behaves any differently than step_into. By matching with step_into, we can assure
ourselves that step_over actually encountered an invoke* bytecode instruction, because if it
didn't then step_into ought to fail.
Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/JavaMethodsTest.java