Skip to content

Commit 56d2832

Browse files
committed
Move MothershipHelper to testAutomation repository
1 parent ca4c066 commit 56d2832

File tree

2 files changed

+374
-2
lines changed

2 files changed

+374
-2
lines changed

src/org/labkey/test/tests/filecontent/FileContentUploadTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,8 @@ public void testCalculateFileRootSize() throws Exception
374374

375375
private @NotNull Integer getFileRootSize() throws IOException, CommandException
376376
{
377-
return JSONUtils.getProperty("jsonMetrics.modules.FileContent.fileRootsTotalSize",
378-
new MothershipHelper(this).getUsageReportJson());
377+
return JSONUtils.getProperty("modules.FileContent.fileRootsTotalSize",
378+
new MothershipHelper(this).getUsageMetrics());
379379
}
380380

381381
@NotNull
Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
package org.labkey.test.util.mothership;
2+
3+
import org.apache.commons.lang3.tuple.Pair;
4+
import org.apache.hc.client5.http.classic.methods.HttpPost;
5+
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
6+
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
7+
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
8+
import org.apache.hc.core5.http.HttpStatus;
9+
import org.apache.hc.core5.http.NameValuePair;
10+
import org.apache.hc.core5.http.io.entity.EntityUtils;
11+
import org.apache.hc.core5.http.message.BasicNameValuePair;
12+
import org.apache.hc.core5.http.protocol.HttpContext;
13+
import org.jetbrains.annotations.NotNull;
14+
import org.jetbrains.annotations.Nullable;
15+
import org.labkey.remoteapi.CommandException;
16+
import org.labkey.remoteapi.CommandResponse;
17+
import org.labkey.remoteapi.Connection;
18+
import org.labkey.remoteapi.SimpleGetCommand;
19+
import org.labkey.remoteapi.SimplePostCommand;
20+
import org.labkey.remoteapi.query.Filter;
21+
import org.labkey.remoteapi.query.SelectRowsCommand;
22+
import org.labkey.remoteapi.query.SelectRowsResponse;
23+
import org.labkey.remoteapi.query.Sort;
24+
import org.labkey.remoteapi.query.UpdateRowsCommand;
25+
import org.labkey.test.LabKeySiteWrapper;
26+
import org.labkey.test.WebTestHelper;
27+
import org.labkey.test.pages.core.admin.CustomizeSitePage;
28+
import org.labkey.test.pages.core.admin.logger.ManagerPage;
29+
import org.labkey.test.pages.mothership.ShowInstallationsPage;
30+
import org.labkey.test.pages.test.TestActions;
31+
import org.labkey.test.util.APIUserHelper;
32+
import org.labkey.test.util.Log4jUtils;
33+
import org.labkey.test.util.LogMethod;
34+
import org.labkey.test.util.LoggedParam;
35+
import org.labkey.test.util.Maps;
36+
import org.labkey.test.util.TestLogger;
37+
import org.openqa.selenium.NotFoundException;
38+
import org.openqa.selenium.WebDriver;
39+
import org.openqa.selenium.WrapsDriver;
40+
41+
import java.io.IOException;
42+
import java.util.ArrayList;
43+
import java.util.Date;
44+
import java.util.HashMap;
45+
import java.util.List;
46+
import java.util.Map;
47+
48+
import static org.junit.Assert.assertEquals;
49+
50+
public class MothershipHelper extends LabKeySiteWrapper
51+
{
52+
public static final String ID_COLUMN = "ExceptionStackTraceId";
53+
public static final String SERVER_INSTALLATION_ID_COLUMN = "ServerInstallationId";
54+
public static final String SERVER_INSTALLATION_NAME_COLUMN = "ServerHostName";
55+
public static final String SERVER_INSTALLATION_QUERY = "ServerInstallation";
56+
public static final String MOTHERSHIP_PROJECT = "_mothership";
57+
public static final String MOTHERSHIP_CONTROLLER = "mothership";
58+
public static final String MOTHERSHIP_SCHEMA = "mothership";
59+
public static final String HOST_NAME = "localhost"; //org.labkey.api.util.MothershipReport.Target.local
60+
public static final String TEST_HOST_NAME = "TEST_localhost"; //org.labkey.api.util.MothershipReport.Target.test
61+
62+
private boolean selfReportingEnabled;
63+
64+
private final WrapsDriver _driver;
65+
66+
public MothershipHelper(WrapsDriver driver)
67+
{
68+
_driver = driver;
69+
selfReportingEnabled = false;
70+
}
71+
72+
@Override
73+
public WebDriver getWrappedDriver()
74+
{
75+
return _driver.getWrappedDriver();
76+
}
77+
78+
public void enableDebugLoggers()
79+
{
80+
Log4jUtils.setLogLevel("org.labkey.mothership", ManagerPage.LoggingLevel.DEBUG);
81+
Log4jUtils.setLogLevel("org.labkey.api.util.MothershipReport", ManagerPage.LoggingLevel.DEBUG);
82+
}
83+
84+
public Integer getServerInstallationId(String hostName) throws IOException, CommandException
85+
{
86+
Map<String, Object> installationInfo = getServerInstallationInfo(hostName);
87+
return (Integer) installationInfo.get(SERVER_INSTALLATION_ID_COLUMN);
88+
}
89+
90+
public Date getLastPing(String hostName) throws IOException, CommandException
91+
{
92+
try
93+
{
94+
Map<String, Object> installationInfo = getServerInstallationInfo(hostName);
95+
return (Date) installationInfo.get("LastPing");
96+
}
97+
catch (NotFoundException ignore)
98+
{
99+
return null;
100+
}
101+
}
102+
103+
public Map<String, Object> getLatestServerInfo() throws IOException, CommandException
104+
{
105+
return getServerInstallationInfo(null);
106+
}
107+
108+
private Map<String, Object> getServerInstallationInfo(String hostName) throws IOException, CommandException
109+
{
110+
SelectRowsCommand selectRows = new SelectRowsCommand(MOTHERSHIP_SCHEMA, SERVER_INSTALLATION_QUERY);
111+
if (hostName != null)
112+
{
113+
selectRows.addFilter(new Filter(SERVER_INSTALLATION_NAME_COLUMN, hostName));
114+
}
115+
selectRows.addSort("LastPing", Sort.Direction.DESCENDING);
116+
selectRows.setColumns(List.of("*"));
117+
selectRows.setMaxRows(1);
118+
SelectRowsResponse response = selectRows.execute(createDefaultConnection(), MOTHERSHIP_PROJECT);
119+
if (response.getRows().size() != 1)
120+
{
121+
ShowInstallationsPage installationsPage = ShowInstallationsPage.beginAt(this);
122+
if (hostName == null)
123+
{
124+
throw new NotFoundException("No mothership server info available.");
125+
}
126+
else
127+
{
128+
List<String> hostNames = installationsPage.getInstallationGrid().getColumnDataAsText(SERVER_INSTALLATION_NAME_COLUMN);
129+
throw new NotFoundException(String.format("Unable to find server installation [%s]. Found: %s", hostName, hostNames));
130+
}
131+
}
132+
return response.getRows().get(0);
133+
}
134+
135+
public int getLatestStackTraceId()
136+
{
137+
Map<String, Object> lastStackTrace = getLatestStackTrace();
138+
if (lastStackTrace == null)
139+
return 0;
140+
141+
return (Integer) lastStackTrace.get(ID_COLUMN);
142+
}
143+
144+
public @Nullable Map<String, Object> getLatestStackTrace()
145+
{
146+
Connection connection = createDefaultConnection();
147+
SelectRowsCommand command = new SelectRowsCommand("mothership", "ExceptionStackTrace");
148+
command.addSort("LastReport", Sort.Direction.DESCENDING);
149+
command.setMaxRows(1);
150+
try
151+
{
152+
SelectRowsResponse response = command.execute(connection, MOTHERSHIP_PROJECT);
153+
if (response.getRows().isEmpty())
154+
return null;
155+
return response.getRows().get(0);
156+
}
157+
catch (IOException|CommandException e)
158+
{
159+
throw new RuntimeException(e);
160+
}
161+
}
162+
163+
public void resetStackTrace(int exceptionStackTraceId)
164+
{
165+
updateStackTrace(exceptionStackTraceId, "", "", "");
166+
}
167+
168+
public void updateStackTrace(int exceptionStackTraceId, String bugNumber, String comments, String assignedToEmail)
169+
{
170+
Connection connection = createDefaultConnection();
171+
SimplePostCommand command = new SimplePostCommand("mothership", "updateStackTrace");
172+
Map<String, Object> params = new HashMap<>();
173+
params.put(ID_COLUMN, exceptionStackTraceId);
174+
if (bugNumber != null)
175+
params.put("bugNumber", bugNumber);
176+
if (comments != null)
177+
params.put("comments", comments);
178+
if (assignedToEmail != null)
179+
{
180+
String assignedToId = assignedToEmail.isEmpty() ? "" : new APIUserHelper(this).getUserId(assignedToEmail).toString();
181+
params.put("assignedTo", assignedToId);
182+
}
183+
command.setParameters(params);
184+
try
185+
{
186+
command.execute(connection, MOTHERSHIP_PROJECT);
187+
}
188+
catch (IOException|CommandException e)
189+
{
190+
throw new RuntimeException(e);
191+
}
192+
}
193+
194+
public int getReportCount(int stackTraceId)
195+
{
196+
Connection connection = createDefaultConnection();
197+
SelectRowsCommand command = new SelectRowsCommand("mothership", "ExceptionStackTrace");
198+
command.addFilter(ID_COLUMN, stackTraceId, Filter.Operator.EQUAL);
199+
try
200+
{
201+
SelectRowsResponse response = command.execute(connection, MOTHERSHIP_PROJECT);
202+
return (int) response.getRows().get(0).get("instances");
203+
}
204+
catch (IOException|CommandException e)
205+
{
206+
throw new RuntimeException(e);
207+
}
208+
}
209+
210+
public enum ReportLevel
211+
{
212+
NONE,
213+
ON
214+
}
215+
216+
public void createUsageReport(ReportLevel level, boolean submit, String forwardedFor)
217+
{
218+
createMothershipReport("CheckForUpdates", level, submit, forwardedFor);
219+
}
220+
221+
public void createExceptionReport(ReportLevel level, boolean submit)
222+
{
223+
createMothershipReport("ReportException", level, submit, null);
224+
}
225+
226+
private void createMothershipReport(String type, ReportLevel level, boolean submit, @Nullable String forwardedFor)
227+
{
228+
String relativeUrl = getTestMothershipReportUrl(type, level, submit, forwardedFor);
229+
beginAt(relativeUrl);
230+
}
231+
232+
public void submitMockUsageReport(String hostName, String serverGUID, String sessionGUID) throws IOException, CommandException
233+
{
234+
Map<String, Object> usageReportJson = getUsageReportJson();
235+
usageReportJson.put("serverHostName", hostName);
236+
usageReportJson.put("serverGUID", serverGUID);
237+
usageReportJson.put("serverSessionGUID", sessionGUID);
238+
submitUsageReport(usageReportJson);
239+
}
240+
241+
public Map<String, Object> getUsageReportJson() throws IOException, CommandException
242+
{
243+
SimpleGetCommand command = new SimpleGetCommand("admin", "testMothershipReport");
244+
command.setParameters(getMothershipReportParams("CheckForUpdates", ReportLevel.ON, false, null));
245+
CommandResponse response = command.execute(createDefaultConnection(), "/");
246+
return response.getParsedData();
247+
}
248+
249+
public Map<String, Object> getUsageMetrics() throws IOException, CommandException
250+
{
251+
return (Map<String, Object>) getUsageReportJson().get("jsonMetrics");
252+
}
253+
254+
private void submitUsageReport(Map<String, Object> report) throws IOException
255+
{
256+
// 'jsonMetrics' is converted to a JSON object by 'testMothershipReport'. Needs to be a string to submit.
257+
report.computeIfPresent("jsonMetrics", (k, v) -> v.toString());
258+
String url = WebTestHelper.buildURL(MOTHERSHIP_CONTROLLER, MOTHERSHIP_PROJECT, "checkForUpdates");
259+
HttpContext context = WebTestHelper.getBasicHttpContext();
260+
261+
try (CloseableHttpClient httpClient = WebTestHelper.getHttpClient())
262+
{
263+
HttpPost method = new HttpPost(url);
264+
List<NameValuePair> args = new ArrayList<>();
265+
for (Map.Entry<String, Object> reportVal : report.entrySet())
266+
{
267+
args.add(new BasicNameValuePair(reportVal.getKey(), reportVal.getValue().toString()));
268+
}
269+
method.setEntity(new UrlEncodedFormEntity(args));
270+
271+
try (CloseableHttpResponse response = httpClient.execute(method, context))
272+
{
273+
int status = response.getCode();
274+
assertEquals("Report submitted status", HttpStatus.SC_OK, status);
275+
assertEquals("Success", response.getHeaders("MothershipStatus")[0].getValue());
276+
EntityUtils.consumeQuietly(response.getEntity());
277+
}
278+
}
279+
}
280+
281+
@NotNull
282+
public static String getTestMothershipReportUrl(String type, ReportLevel level, boolean submit, @Nullable String forwardedFor)
283+
{
284+
Map<String, Object> params = getMothershipReportParams(type, level, submit, forwardedFor);
285+
return WebTestHelper.buildURL("admin", "testMothershipReport", params);
286+
}
287+
288+
@NotNull
289+
private static Map<String, Object> getMothershipReportParams(String type, ReportLevel level, boolean submit, @Nullable String forwardedFor)
290+
{
291+
Map<String, Object> params = new HashMap<>();
292+
params.put("type", type);
293+
params.put("level", level.toString());
294+
params.put("submit", submit);
295+
params.put("testMode", true);
296+
if (null != forwardedFor)
297+
params.put("forwardedFor", forwardedFor);
298+
return params;
299+
}
300+
301+
@LogMethod
302+
public void setIgnoreExceptions(boolean ignore) throws IOException, CommandException
303+
{
304+
try
305+
{
306+
String serverName = executeScript("return LABKEY.serverName;", String.class);
307+
int installationId = getServerInstallationId(serverName);
308+
// Set the flag for the installation
309+
UpdateRowsCommand update = new UpdateRowsCommand("mothership", SERVER_INSTALLATION_QUERY);
310+
update.addRow(Maps.of(SERVER_INSTALLATION_ID_COLUMN, installationId, "IgnoreExceptions", ignore));
311+
update.execute(createDefaultConnection(), MOTHERSHIP_PROJECT);
312+
}
313+
catch (NotFoundException notFound)
314+
{
315+
TestLogger.log("No existing server installation record to update.");
316+
if (ignore)
317+
{
318+
throw new IllegalStateException("Attempting to set ignore exceptions true but no existing server installation record.", notFound);
319+
}
320+
}
321+
}
322+
323+
public void ensureSelfReportingEnabled()
324+
{
325+
if (!selfReportingEnabled)
326+
{
327+
CustomizeSitePage.beginAt(this)
328+
.setExceptionSelfReporting(true)
329+
.save();
330+
selfReportingEnabled = true;
331+
}
332+
}
333+
334+
public void disableExceptionReporting()
335+
{
336+
CustomizeSitePage.beginAt(this)
337+
.setExceptionReportingLevel(CustomizeSitePage.ReportingLevel.NONE)
338+
.setExceptionSelfReporting(false)
339+
.save();
340+
selfReportingEnabled = false;
341+
}
342+
343+
public int triggerException(TestActions.ExceptionActions action)
344+
{
345+
return triggerExceptions(action).get(0);
346+
}
347+
348+
public List<Integer> triggerExceptions(TestActions.ExceptionActions... actions)
349+
{
350+
List<Pair<TestActions.ExceptionActions, String>> actionsWithMessages = new ArrayList<>();
351+
for (TestActions.ExceptionActions action : actions)
352+
{
353+
actionsWithMessages.add(Pair.of(action, null));
354+
}
355+
return triggerExceptions(actionsWithMessages);
356+
}
357+
358+
@LogMethod
359+
public List<Integer> triggerExceptions(@LoggedParam List<Pair<TestActions.ExceptionActions, String>> actionsWithMessages)
360+
{
361+
List<Integer> exceptionIds = new ArrayList<>();
362+
checkErrors();
363+
for (Pair<TestActions.ExceptionActions, String> action : actionsWithMessages)
364+
{
365+
action.getLeft().triggerException(action.getRight());
366+
sleep(100); // Wait for mothership to pick up exception
367+
exceptionIds.add(getLatestStackTraceId());
368+
}
369+
resetErrors();
370+
return exceptionIds;
371+
}
372+
}

0 commit comments

Comments
 (0)