Fest slows down when testing with swingx jxtreetable

I do not know how to explain it. But I'll try .. Fest slows down to crawl while working with JXTreeTable from swingx. At first it does not slow down. It works fine for a while, but after a while, when the same actions are repeated, it slows down a lot.

I raised an error for this on github. Please tell me if this is what I am doing wrong. I can not reproduce the problem when I tried to create SSCCE.

In any case, here the video slows him down.

http://screencast.com/t/liNttCw2In0w

From 0.39 to 0.40, many operations are performed. They are executed when there is one line in JXTreeTable.

At the point in time from 0.49 to the end of the recording, the same operation is repeated, but the table now has three rows, the mouse takes a lot of time.

I attached a screenshot taken at a time when the holiday is slowing down, which is trying to explain it more

enter image description here

This is the code that does this work:

Step 1) Selecting a node from the tree is as follows:

JTreeFixture folioTreeFixture = importShareholders.panel ("treePanel"). tree ("folioTree");

folioTreeFixture.separator("~"); folioTreeFixture.selectPath(new StringWrapper("Shareholders", true)+"~"+ (ShareType.isEquity(shareType) ? new StringWrapper("Equity Folios", true) : new StringWrapper("Preference Folios", true))+"~"+ new FolioTreeRep(folio.getName(),folioNo, shareType).toString()); 

Step 2) Search and select a row from JXTreeTable

 int selectRow=-1; JTableFixture table=importShareholders.table("historyTable"); for(int i=0;i<table.rowCount();i++){ String certificateNumber = table.cell(TableCell.row(i).column(ShareholderHistoryTable.columnIndex(ShareholderHistoryTable.CERT_NO))).value(); String remarks=table.cell(TableCell.row(i).column(ShareholderHistoryTable.columnIndex(ShareholderHistoryTable.REMARKS))).value(); if(StringUtils.isEmpty(remarks) && StringUtils.isNotEmpty(certificateNumber) && Integer.parseInt(certificateNumber)==certNo){ selectRow=i; break; } } if(selectRow==-1){ fail("Couldn't find certificate number to transfer"); } 

Step 3) Display a popup menu and press a line

 table.showPopupMenuAt(TableCell.row(selectRow).column(0)).menuItem("btnTransfer").click(); 

I'm not sure why its slowing down. Please let me know if there is more information I can help with. I would appreciate help in solving the problem.

I profiled the application and I did not find anything unpleasant. I do not have much experience profiling applications. I would appreciate it if someone could look at it a second time. I profiled it with yourkit and uploaded a snapshot dump here:

https://www.dropbox.com/s/dh976v01q9c3sgj/ImportShareholderData.shouldTransferAndSplit-2013-06-14-shutdown.snapshot.zip

Any help would be greatly appreciated.

EDIT:

I think I forgot to mention the same thing when I do it manually. It only slows down the holiday. Does it make me believe there is a problem with the festival?

Excuse me.

EDIT 2: As a request to Marcin (sorry for delaying Marcin). Here is the code when the first line gets split

 public List<Integer> splitRowEqually(ShareType shareType, String date, int folioNo, int certNo, int... certnos) throws NoSuchFieldException, TorqueException { //select a tree node selectFolioInTree(shareType, folioNo); Pause.pause(new Condition("Wait until tab is created") { @Override public boolean test() { return importShareholders.tabbedPane().tabTitles().length>0; } }); //select a row on the table to split int row=selectRowWithCertNunber(certNo); List<Integer> rowsIndexes=new ArrayList<Integer>(); JTableFixture table = importShareholders.table(); //show popup menu on that row and select split table.showPopupMenuAt(row(row).column(columnIndex(TRANS_TYPE))).menuItem("btnSplit").click(); DialogFixture splitDialog=FinderUtilities.getDialogWithTitle("Split Share Certificate"); splitDialog.textBox("tfDateOfSplit").setText(date); int noOfShares= Integer.parseInt(table.cell(row(row).column(columnIndex(NO_OF_SHARES))).value()); int distFrom= Integer.parseInt(table.cell(row(row).column(columnIndex(DIST_NO_FROM))).value()); int distTo= Integer.parseInt(table.cell(row(row).column(columnIndex(DIST_NO_TO))).value()); //split the row into the number of times decided by the certnos array int noOfSharesInEachSplit=noOfShares/certnos.length; for(int i=0;i<certnos.length;i++){ int distToInSplit = distFrom + noOfSharesInEachSplit-1; enterSplitRowDetails(splitDialog, certnos[i], distFrom, distToInSplit<=distTo ? distToInSplit : distTo); distFrom=distToInSplit+1; rowsIndexes.add(row++); } splitDialog.button("btnSplit").click(); return rowsIndexes; } //selects a node from the left hand side tree public void selectFolioInTree(final ShareType shareType,final int folioNo) throws TorqueException { JTreeFixture folioTreeFixture = importShareholders.panel("treePanel").tree("folioTree"); folioTreeFixture.separator("~"); // I use these wrapper classes - StringWrapper and FolioTreeRep, so that I can get a html // string for the tree node like <html><b>Shareholder</b></html> String treePath = new StringWrapper("Shareholders", true) + "~" + (ShareType.isEquity(shareType) ? new StringWrapper("Equity Folios", true) : new StringWrapper("Preference Folios", true)) + "~" + new FolioTreeRep(mapOfFolioNames.get(folioNo), folioNo, shareType).toString(); folioTreeFixture.clickPath(treePath); } //search the table for a row that contains the cert no provided in the Certificate Number column. private int selectRowWithCertNunber(int certNo) throws NoSuchFieldException { int selectRow=-1; JTableFixture table=importShareholders.table("historyTable"); for(int i=0;i<table.rowCount();i++){ String certificateNumber = table.cell(row(i).column(columnIndex(CERT_NO))).value(); String remarks=table.cell(row(i).column(columnIndex(REMARKS))).value(); if(StringUtils.isEmpty(remarks) && StringUtils.isNotEmpty(certificateNumber) && Integer.parseInt(certificateNumber)==certNo){ selectRow=i; break; } } if(selectRow==-1){ fail("Couldn't find certificate number to transfer"); } return selectRow; } // enter details on the table in the SplitDialog private void enterSplitRowDetails(DialogFixture splitDialog, int cert, int distFrom, int distTo) { splitDialog.button("btnAdd").click(); int row = splitDialog.table().rowCount(); splitDialog.table().enterValue(row(row - 1).column(0), String.valueOf(cert)); splitDialog.table().enterValue(row(row - 1).column(1), String.valueOf(distFrom)); splitDialog.table().enterValue(row(row - 1).column(2), String.valueOf(distTo)); } 
+4
source share
2 answers

Umm ... This is a pretty interesting question;

I believe that the question contains less pressing details, especially information about the integration of the robot and IO, so I can’t just give you the correct answer ...

In any case, I will try to analyze the problem in my voice a little ...

First one . According to your comments in the screenshot, I can notice that all “30 second pauses or so” happen on some, as I can get, the process of reading the “select / search” stream (your application receives some data for output, etc. e). So perhaps this is much deeper than you think, because it is probably a thread problem;

I could not find the use of the GuiQuery / GuiTask / GuiActionRunne classes in your code snippets, so I can assume that the "synchronization problem" might require space in the case indicated ...

Second one . OK ... If this is a thread problem, I can assume that the robot and I / O solutions are in the same ONE thread (Main thread or something like that), because, according to your advice, like "Time from 0, 39 to 0.40, the set of operations is performed if the JXTreeTable has one line ".... the GUI is waiting for the completion of some process ...

Third . And again ... According to this problem as

"It is recommended that you enable automatic verification to ensure that all Swing Component Updates are performed in the Swings EDT (Event Dispatcher Thread). For those unfamiliar with EDT, it is responsible for processing and updating all Swing widgets in a separate thread, causing the application to never doesn’t lose the response to user gestures (just in short, more about EDT here). To do this, add the following, go to the test: "

 import org.fest.swing.edt.FailOnThreadViolationRepaintManager; import org.junit.BeforeClass; ... @BeforeClass public static void setUpOnce() { FailOnThreadViolationRepaintManager.install(); } 

The next step is to launch a frame or dialog. Since JUnit runs the thread on its own, we need to run a frame or dialog through Fest to ensure, again, that EDT is used correctly:

 import org.fest.swing.edt.GuiActionRunner; import org.fest.swing.edt.GuiQuery; import org.fest.swing.fixture.FrameFixture; import org.junit.Before; ... private FrameFixture testFrame; private AllTypesFrame frame; ... @Before public void setUp() { frame = GuiActionRunner.execute(new GuiQuery<AllTypesFrame>() { protected AllTypesFrame executeInEDT() { return new AllTypesFrame(); } }); testFrame = new FrameFixture(frame); testFrame.show(); } 

... makes me think that this may be the "thread problem" described in the First and Second tips ...

therefore, as a conclusion, I can say that perhaps you need to multithreadedly test your test, because this is obviously some kind of synchronization problem ...

PS @sethu, before you start your debugging, I want to point out a little ... I still suspect thread conflicts occur here (see My previous tips) because, as I noticed, your code snippets show the use of static expressions to call methods like Pause.pause(...) or FinderUtilities.getDialogWithTitle(...) , etc. I don’t see the whole architecture of the project, it’s difficult to analyze according to the bits presented, but it’s pretty clear that the “strong” “manual testing” is going well because the audience’s actions respond in real time, but testing the festival causes annoying delays because it uses some timer "for the countdown until a click emulation occurs, etc. and, of course, this is a background process that needs a separate thread ... Watch for debugging carefully, maybe somewhere in your code the user interface thread and the fest thread conflict (see static methods, thread.sleep, etc. ) points at which the fest thread can block (redefine) the user interface ...: S By the way, what method Pause.pause(...) do?

PPS If you have more information, comment on my answer


Let me know if my answer helps you

+1
source

I don’t know what your robot settings are, but you can at least try setting idleTimeout and other timeouts for the robot you are using. The default timeout is 10 seconds (see org.fest.swing.core.Settings). After I decrease it (first 1000 ms, next 100 ms), I noticed that the robot is faster.

 robot().settings().idleTimeout(YOUR_TIMEOUT) 

Here is my test setup and one test method. Hope is clear. Here you have mine before / after

 private static int testMethodCounter = 0; private static EmergencyAbortListener mEmergencyAbortListener; private FrameFixture workbenchFrame; private Robot robot2; private static final int myIdleTimeout = 100; @Before public void setUp() throws Exception { // my workaround to be able to start the app once and reuse for all tests if (testMethodCounter == 0) { robot2 = BasicRobot.robotWithNewAwtHierarchy(); GuiActionRunner.execute(new GuiTask() { @Override protected void executeInEDT() throws Throwable { ApplicationLauncher.application(ProgramRun.class).start(); } }); } else { // the second test method see all before created gui components robot2 = BasicRobot.robotWithCurrentAwtHierarchy(); } testMethodCounter++; robot2.settings().idleTimeout(myIdleTimeout); workbenchFrame = WindowFinder.findFrame(FrameNames.WORKBENCH.getName()).withTimeout(10000) .using(robot2); } @After public void tearDown() { // current window will not be closed robot2.cleanUpWithoutDisposingWindows(); } @Test public void someSmokeTest() throws Exception { Pause.pause(1000); // perform some test specific gui actions // here is very important moment, I need new robot because // workbenchFrame.button(ButtonNames.SOME_BUTTON_NAME).click(); creates new dialog // which will be avilable in AWT stack after creation robot2.cleanUpWithoutDisposingWindows(); robot2 = BasicRobot.robotWithCurrentAwtHierarchy(); // the new Robot needs timeout setup // without this I have long breaks between gui events robot2.settings().idleTimeout(myIdleTimeout); workbenchFrame.button(ButtonNames.SOME_BUTTON_NAME).click(); DialogFixture dialog = WindowFinder.findDialog("dialog2") .withTimeout(5000).using(robot2); // some actions on the dialog // once again next new dialog workbenchFrame.menuItem(MenuItemNames.NAME).click(); robot2.cleanUpWithoutDisposingWindows(); robot2 = BasicRobot.robotWithCurrentAwtHierarchy(); // and idleTimeout setup once again, new Robot needs new setup robot2.settings().idleTimeout(myIdleTimeout); // next actions + assertion } 
0
source

Source: https://habr.com/ru/post/1486157/


All Articles