@Test
	public void testEditLiveBytesWritesTarget() throws Throwable {
		runSwing(() -> memBytesProvider.setAutoReadMemorySpec(readNone));

		createRmiConnection();
		addMemoryMethods();
		createTrace();
		try (Transaction tx = tb.startTransaction()) {
			tb.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
			tb.createObjectsProcessAndThreads();

			tb.trace.getMemoryManager()
					.addRegion("Processes[1].Memory[exe:.text]", Lifespan.nowOn(0L),
						tb.range(0x55550000, 0x5555ffff), TraceMemoryFlag.READ,
						TraceMemoryFlag.EXECUTE);
		}
		waitForDomainObject(tb.trace);
		TraceObject process = tb.obj("Processes[1]");
		rmiCx.publishTarget(tool, tb.trace);

		traceManager.openTrace(tb.trace);
		traceManager.activateTrace(tb.trace);
		waitForSwing();

		controlService.setCurrentMode(tb.trace, ControlMode.RW_TARGET);
		DockingActionIf actionEdit = getAction(memBytesPlugin, "Enable/Disable Byteviewer Editing");

		performAction(actionEdit);
		goToDyn(tb.addr(0x55550800));
		runSwingLater(() -> sendKeyStrokesForText("42"));
		/**
		 * One for each key press :/
		 * 
		 * TODO: Perhaps also a curious result that the second is 0x02 and not 0x42. In the test, we
		 * can easily see because the method doesn't actually mutate the database. However, in
		 * practice, what if the method is too slow to mutate, and the next keystroke wins the race?
		 */
		handleWriteMemInvocation(process, tb.addr(0x55550800), new Bytes(0x40));
		handleWriteMemInvocation(process, tb.addr(0x55550800), new Bytes(0x02));
		performAction(actionEdit);

		rmiCx.withdrawTarget(tool, tb.trace);
	}
Because goToDyn has to retry, it can generate many read requests. Turn off auto-read and
then flush out any pending reads, so that all the tasks can complete.
Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java