Skip to content

Commit 1c406f4

Browse files
committed
Add server.env LCLS test automation (issues #376, #422, #424)
Implements automated integration tests for Liberty Language Server (liberty-ls) features in server.env files, closing issues #376, #422, and #424. Note: depends on the Page Object Model (#2b9cec9) and shared test suite refactor (#1f2e2a4) which have not yet been merged. Changes: - src/test/shared/serverEnvSuite.ts (new): shared parameterised test suite covering three LCLS features in server.env: - Hover support for WLP_USER_DIR and LOG_DIR (issue #424) - Type-ahead/completion: WLP_LOG -> WLP_LOGGING_MESSAGE_FORMAT (issue #422) - Diagnostics + quick fix for invalid variable values (issue #376) - src/test/MavenTestLSPServerEnv.ts (new): Maven entry-point wiring the shared suite with Maven project path and hover test cases - src/test/resources/maven/.../server.env (new): empty server.env resource file for the Maven test wrapper app (populated dynamically by tests) - src/test/pages/ProblemsPage.ts: fixed hasDiagnostic() to use its message and markerType parameters instead of hardcoded values, making it reusable across all test suites
1 parent 1f2e2a4 commit 1c406f4

5 files changed

Lines changed: 227 additions & 3 deletions

File tree

src/test/MavenTestLSPServerEnv.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as utils from './utils/testUtils';
2+
import { runServerEnvSuite } from './shared/serverEnvSuite';
3+
4+
runServerEnvSuite({
5+
buildTool: 'maven',
6+
getProjectPath: utils.getMvnProjectPath,
7+
hoverTestCases: [
8+
{ element: 'WLP_USER_DIR', line: 1, column: 1, expectedDoc: 'The user or custom configuration directory that is used to store shared and server-specific configuration. See the path_to_liberty/wlp/README.TXT file for details about shared resource locations. A server configuration is at the %WLP_USER_DIR%/servers/serverName location. The default value is the user directory in the installation directory.' },
9+
{ element: 'LOG_DIR', line: 2, column: 1, expectedDoc: 'The directory that contains the log file. The default value is %WLP_OUTPUT_DIR%/serverName/logs' },
10+
]
11+
});

src/test/pages/ProblemsPage.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ export class ProblemsPage {
1010
const bottomBar = new BottomBarPanel();
1111
await bottomBar.toggle(true);
1212
let problemsView = await bottomBar.openProblemsView();
13-
let markers = await problemsView.getAllVisibleMarkers(MarkerType.Any);
13+
let markers = await problemsView.getAllVisibleMarkers(markerType);
1414
for (const marker of markers) {
1515
const text = await marker.getText();
1616
// Check if text contains your diagnostic message
17-
if(text.includes('Only public methods can be exposed as resource methods.')){
17+
if(text.includes(message)){
1818
return true;
1919
}
2020
}

src/test/resources/maven/liberty-maven-test-wrapper-app/src/main/liberty/config/server.env

Whitespace-only changes.

src/test/shared/serverEnvSuite.ts

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import * as path from 'path';
2+
import { logger } from '../utils/testLogger';
3+
import { EditorView, VSBrowser, WebDriver } from 'vscode-extension-tester';
4+
import { EditorPage } from '../pages/EditorPage';
5+
import * as utils from '../utils/testUtils';
6+
import { expect } from 'chai';
7+
import { CodeAssistPage } from '../pages/CodeAssistPage';
8+
import { ProblemsPage } from '../pages/ProblemsPage';
9+
import { QuickFixPage } from '../pages/QuickFixPage';
10+
11+
export interface ServerEnvConfig {
12+
buildTool: 'maven' | 'gradle';
13+
getProjectPath: () => string;
14+
hoverTestCases: Array<{
15+
element: string;
16+
line: number;
17+
column: number;
18+
expectedDoc: string;
19+
}>;
20+
}
21+
22+
export function runServerEnvSuite(config: ServerEnvConfig){
23+
describe(`Server Env functionality tests for ${config.buildTool === 'maven' ? 'Maven' : 'Gradle'} Project`, () => {
24+
// Compute the test file path using config
25+
let serverEnv : EditorPage;
26+
let wait: any;
27+
28+
before(async function() {
29+
this.timeout(60000);
30+
31+
logger.info(`Setting up ${config.buildTool === 'maven' ? 'Maven' : 'Gradle'} LSP Hover tests`);
32+
33+
// Wait for workbench to be ready
34+
await VSBrowser.instance.openResources(config.getProjectPath());
35+
await VSBrowser.instance.waitForWorkbench();
36+
37+
wait = utils.getWaitHelper();
38+
39+
logger.info('Opening server.env file for all tests');
40+
const serverEnvPath = path.resolve(
41+
config.getProjectPath(),
42+
'src',
43+
'main',
44+
'liberty',
45+
'config',
46+
'server.env'
47+
);
48+
logger.info(`Server.env path: ${serverEnvPath}`);
49+
50+
serverEnv = await new EditorPage().openFile(serverEnvPath, 'server.env');
51+
logger.info('Server.env file opened and editor obtained');
52+
});
53+
54+
afterEach(async function() {
55+
// Take screenshot on failure but don't close editor
56+
if (this.currentTest?.state === 'failed') {
57+
await VSBrowser.instance.driver.takeScreenshot();
58+
logger.error(`Test failed: ${this.currentTest.title}`);
59+
}
60+
});
61+
62+
after(async function() {
63+
this.timeout(10000); // Increase timeout for cleanup operations
64+
// Clear server.env file, same logic as in restSnippetSuite.ts
65+
try {
66+
if (serverEnv) {
67+
// Select all text first, then clear
68+
const currentText = await serverEnv.getEditor().getText();
69+
try {
70+
await serverEnv.getEditor().selectText(currentText);
71+
await wait.sleep(300);
72+
} catch (selectError) {
73+
// selectText may fail but setText still works
74+
}
75+
76+
await serverEnv.clear();
77+
logger.info('Reset TestRest.java to empty after test');
78+
}
79+
} catch (error) {
80+
logger.error('Failed to reset TestRest.java', error);
81+
}
82+
// Close editor after all tests complete
83+
try {
84+
await new EditorView().closeAllEditors();
85+
logger.info('Closed all editors after test suite');
86+
} catch (error) {
87+
logger.error('Failed to close editors in after hook', error);
88+
}
89+
90+
utils.copyScreenshotsToProjectFolder(config.buildTool);
91+
});
92+
93+
it('Liberty Language Server should initialize', async function() {
94+
this.timeout(60000);
95+
logger.testStart('Liberty Language Server should initialize');
96+
97+
try {
98+
await utils.waitForLanguageServerInit(
99+
'Language Support for Liberty',
100+
'Initialized Liberty Language server',
101+
60
102+
);
103+
logger.testComplete('Liberty Language Server initialized successfully');
104+
} catch (error) {
105+
logger.testFailed('Liberty Language Server should initialize', error);
106+
throw error;
107+
}
108+
});
109+
110+
const hoverTestCases = config.hoverTestCases;
111+
112+
hoverTestCases.forEach(testCase => {
113+
it(`Hover over ${testCase.element} shows Liberty Language Server documentation`, async function() {
114+
this.timeout(30000);
115+
logger.testStart(`Hover over ${testCase.element} shows Liberty Language Server documentation`);
116+
await serverEnv.getEditor().setText('WLP_USER_DIR=/opt/wlp/usr\nLOG_DIR=/logs\n');
117+
await serverEnv.getEditor().save();
118+
await wait.sleep(1000);
119+
120+
try {
121+
122+
const hoverText = await serverEnv.hoverOver(testCase.line, testCase.column, testCase.element);
123+
expect(hoverText).to.not.be.empty;
124+
logger.stepSuccess(3, `Hover widget displayed with Liberty Language Server content for ${testCase.element}`);
125+
126+
logger.step(4, 'Verifying hover contains expected documentation');
127+
expect(hoverText).to.include(testCase.expectedDoc);
128+
logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`);
129+
130+
logger.testComplete(`Hover over ${testCase.element} shows Liberty Language Server documentation`);
131+
} catch (error) {
132+
logger.testFailed(`Hover over ${testCase.element} shows Liberty Language Server documentation`, error);
133+
throw error;
134+
}
135+
});
136+
});
137+
138+
it('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT type ahead', async function () {
139+
this.timeout(275000);
140+
logger.testStart('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT type ahead');
141+
142+
try {
143+
logger.step(1, 'Positioning cursor');
144+
await serverEnv.getEditor().setCursor(3, 1);
145+
146+
logger.step(2, 'Opening content assist');
147+
const codeAssist = new CodeAssistPage();
148+
await codeAssist.insertSnippet(serverEnv, 'WLP_LOG', 'WLP_LOGGING_MESSAGE_FORMAT');
149+
logger.stepSuccess(2, 'Completion inserted');
150+
const after = await serverEnv.getEditor().getText();
151+
expect(after).to.include('WLP_LOGGING_MESSAGE_FORMAT');
152+
await wait.sleep(1000);
153+
154+
const lineText = await serverEnv.getEditor().getTextAtLine(3);
155+
await serverEnv.getEditor().setTextAtLine(3, lineText.trimEnd() + '=JSON');
156+
157+
await serverEnv.getEditor().save();
158+
await wait.sleep(500);
159+
160+
161+
logger.testComplete('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT completion');
162+
} catch (error) {
163+
logger.testFailed('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT completion', error);
164+
throw error;
165+
}
166+
});
167+
it('Show that INVALID text displays diagnostic and quick fix removes it ', async function () {
168+
this.timeout(90000);
169+
logger.testStart('Show that INVALID text displays diagnostic and quick fix removes it');
170+
try {
171+
172+
await serverEnv.replaceTextWithinLineContaining('WLP_LOGGING_MESSAGE_FORMAT', 'JSON' , 'INVALID');
173+
174+
// Save file and wait for reanalysis
175+
await serverEnv.getEditor().save();
176+
await wait.sleep(500);
177+
178+
// Check that the diagnostic is there
179+
let problems = new ProblemsPage();
180+
const found = await problems.hasDiagnostic('The value `INVALID` is not valid for the variable `WLP_LOGGING_MESSAGE_FORMAT`.');
181+
expect(found).to.be.true;
182+
logger.testComplete('Diagnostic shows INVALID variable');
183+
184+
// Quick fix implementation to get rid of diagnostic
185+
// Re-find line and place cursor on "methodname()"
186+
const buffer = await serverEnv.getEditor().getText();
187+
logger.info('Buffer before quick fix: ' + JSON.stringify(buffer));
188+
189+
await new QuickFixPage().applyFix(serverEnv, 'INVALID', 'Replace value with JSON');
190+
await wait.sleep(3000);
191+
await serverEnv.getEditor().save();
192+
await wait.sleep(5000);
193+
194+
const after = await serverEnv.getEditor().getText();
195+
expect(after).to.include('JSON');
196+
expect(await problems.hasDiagnostic('The value `INVALID` is not valid for the variable `WLP_LOGGING_MESSAGE_FORMAT`.')).to.be.false;
197+
198+
} catch (error) {
199+
logger.testFailed('Diagnostic/quick-fix test flow failed', error);
200+
throw error;
201+
}
202+
203+
});
204+
205+
206+
207+
208+
209+
210+
211+
});
212+
}

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"node_modules",
2020
".vscode-test",
2121
"test-resources",
22-
"test-resource-old"
22+
"test-resource-old",
23+
"out"
2324
]
2425
}

0 commit comments

Comments
 (0)