Skip to content

Commit a5155c4

Browse files
committed
add func tests
1 parent 06b9192 commit a5155c4

File tree

11 files changed

+6169
-8
lines changed

11 files changed

+6169
-8
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ vendor/
55
.DS_Store
66

77
#Tools
8+
node_modules/
89

910
# App
1011
.bouncer-key

docker-compose.yml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
build:
55
context: .
66
dockerfile: ./docker/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
7-
links:
7+
depends_on:
88
- crowdsec
99
- mysql
1010
- redis
@@ -24,7 +24,7 @@ services:
2424
build:
2525
context: .
2626
dockerfile: ./docker/wp5.5/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
27-
links:
27+
depends_on:
2828
- crowdsec
2929
- mysql
3030
- redis
@@ -44,7 +44,7 @@ services:
4444
build:
4545
context: .
4646
dockerfile: ./docker/wp5.4/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
47-
links:
47+
depends_on:
4848
- crowdsec
4949
- mysql
5050
- redis
@@ -64,7 +64,7 @@ services:
6464
build:
6565
context: .
6666
dockerfile: ./docker/wp5.3/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
67-
links:
67+
depends_on:
6868
- crowdsec
6969
- mysql
7070
- redis
@@ -84,7 +84,7 @@ services:
8484
build:
8585
context: .
8686
dockerfile: ./docker/wp5.2/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
87-
links:
87+
depends_on:
8888
- crowdsec
8989
- mysql
9090
- redis
@@ -104,7 +104,7 @@ services:
104104
build:
105105
context: .
106106
dockerfile: ./docker/wp5.1/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
107-
links:
107+
depends_on:
108108
- crowdsec
109109
- mysql
110110
- redis
@@ -124,7 +124,7 @@ services:
124124
build:
125125
context: .
126126
dockerfile: ./docker/wp5.0/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
127-
links:
127+
depends_on:
128128
- crowdsec
129129
- mysql
130130
- redis
@@ -144,7 +144,7 @@ services:
144144
build:
145145
context: .
146146
dockerfile: ./docker/wp4.9/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
147-
links:
147+
depends_on:
148148
- crowdsec
149149
- mysql
150150
- redis
@@ -164,6 +164,8 @@ services:
164164
image: crowdsecurity/crowdsec:latest
165165
environment:
166166
- DISABLE_AGENT=true
167+
ports:
168+
- "8080:8080"
167169
mysql:
168170
image: mysql:5.7
169171
environment:

docs/contribute.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
```bash
77
export CS_WORDPRESS_BOUNCER_PHP_VERSION=7.2
88
```
9+
## Run tests
10+
11+
```bash
12+
./tests-local.sh # headless mode for speed up
13+
14+
DEBUG ./tests-local.sh
15+
```
16+
17+
> Note: you can add `await jestPlaywright.debug();` at the moment you want to pause the process.
918
1019
Run containers:
1120

tests-local.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
# Context
4+
WORDPRESS_VERSION=5.5
5+
6+
# Default variables
7+
WATCHER_LOGIN='watcherLogin'
8+
WATCHER_PASSWORD='watcherPassword'
9+
10+
# Run stack
11+
docker-compose down --remove-orphans --timeout 0
12+
docker-compose up -d wordpress$WORDPRESS_VERSION crowdsec mysql redis memcached
13+
14+
# Setup CrowdSec
15+
export BOUNCER_KEY=`docker-compose exec crowdsec cscli bouncers add functional-tests -o raw`
16+
export CS_WP_HOST=`docker-compose exec crowdsec /sbin/ip route|awk '/default/ { printf $3 }'`
17+
docker-compose exec crowdsec cscli machines add $WATCHER_LOGIN --password $WATCHER_PASSWORD
18+
echo "Waiting for WordPress container to initialize..."
19+
until $(curl --output /dev/null --silent --head --fail http://localhost); do
20+
printf '.'
21+
sleep 0.1
22+
done
23+
24+
25+
# Run tests
26+
WORDPRESS_VERSION=$WORDPRESS_VERSION WATCHER_LOGIN=$WATCHER_LOGIN WATCHER_PASSWORD=$WATCHER_PASSWORD LAPI_URL_FROM_CONTAINERS='http://crowdsec:8080' LAPI_URL_FROM_HOST='http://localhost:8080' yarn --cwd ./tests/functional test --detectOpenHandles --runInBand
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
const notifier = require("node-notifier");
2+
const path = require("path");
3+
4+
const BASE_URL = "http://localhost";
5+
const BOUNCER_KEY = process.env.BOUNCER_KEY;
6+
const CLIENT_IP = process.env.CS_WP_HOST;
7+
const WORDPRESS_VERSION = process.env.WORDPRESS_VERSION;
8+
const ADMIN_LOGIN = "admin";
9+
const ADMIN_PASSWORD = "my_very_very_secret_admin_password";
10+
const LAPI_URL = process.env.LAPI_URL_FROM_CONTAINERS;
11+
const NOTIFY = !!process.env.DEBUG;
12+
const TIMEOUT = (!!process.env.DEBUG ? 5 * 60 : 5) * 1000;
13+
14+
const notify = (message) => {
15+
if (NOTIFY) {
16+
notifier.notify({
17+
title: "CrowdSec automation",
18+
message: message,
19+
icon: path.join(__dirname, "../icon.png"),
20+
});
21+
}
22+
};
23+
24+
const { addDecision, deleteAllDecisions } = require("../utils/watcherClient");
25+
26+
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
27+
28+
jest.setTimeout(TIMEOUT);
29+
30+
describe(`Install Stack: WordPress ${WORDPRESS_VERSION} + the CrowdSec plugin`, () => {
31+
beforeAll(async () => {});
32+
33+
afterAll(async () => {
34+
return await browser.close();
35+
});
36+
37+
const waitForNavigation = page.waitForNavigation();
38+
39+
it('Should install wordpress"', async () => {
40+
notify("Install wordpress");
41+
42+
// Go to home
43+
await page.goto(`${BASE_URL}`);
44+
45+
// "Language selection" page
46+
47+
await page.click('option[lang="en"]');
48+
await page.click("#language-continue");
49+
await waitForNavigation;
50+
51+
// "Account creation" page
52+
53+
await page.fill("#weblog_title", "My website");
54+
await page.fill("#user_login", ADMIN_LOGIN);
55+
await page.fill("#pass1", ADMIN_PASSWORD);
56+
await page.fill("#admin_email", "admin@admin.admin");
57+
await page.click("#submit");
58+
await waitForNavigation;
59+
60+
// "Success" page
61+
62+
await expect(page).toHaveText("h1", "Success!");
63+
await page.click(".wp-core-ui > .step > .button");
64+
await waitForNavigation;
65+
});
66+
67+
it('Should login to wp-admin"', async () => {
68+
notify("Login to wp-admin");
69+
// "Login" page
70+
await page.fill("#user_login", ADMIN_LOGIN);
71+
await page.fill("#user_pass", ADMIN_PASSWORD);
72+
await page.waitForSelector("#wp-submit");
73+
await page.click("#wp-submit");
74+
await waitForNavigation;
75+
});
76+
77+
it('Should install CrowdSec plugin"', async () => {
78+
notify("Install CrowdSec plugin");
79+
// "Plugins" page
80+
await page.goto(`${BASE_URL}/wp-admin/plugins.php'`);
81+
await page.click("#activate-crowdsec");
82+
await waitForNavigation;
83+
await expect(page).toHaveText("#message", "Plugin activated.");
84+
});
85+
86+
it('Should configure the connection details"', async () => {
87+
notify("Configure the connection details");
88+
// CrowdSec Menu
89+
await page.click(
90+
"#adminmenuwrap > #adminmenu > #toplevel_page_crowdsec_plugin > .wp-has-submenu > .wp-menu-name"
91+
);
92+
await waitForNavigation;
93+
94+
// CrowdSec Settings page: set connection details
95+
96+
await page.fill("[name=crowdsec_api_url]", LAPI_URL);
97+
await page.fill("[name=crowdsec_api_key]", BOUNCER_KEY);
98+
await page.click("[type=submit]");
99+
await waitForNavigation;
100+
101+
await expect(page).toHaveText(
102+
"#setting-error-settings_updated",
103+
"Settings saved."
104+
);
105+
});
106+
107+
it('Should reduce the cache durations"', async () => {
108+
notify("Reduce the cache durations");
109+
// CrowdSec Menu
110+
await page.click(
111+
"#toplevel_page_crowdsec_plugin > ul > li:nth-child(3) > a"
112+
);
113+
await waitForNavigation;
114+
115+
// CrowdSec Settings page: set connection details
116+
117+
await page.fill("[name=crowdsec_clean_ip_cache_duration]", "1");
118+
await page.fill("[name=crowdsec_bad_ip_cache_duration]", "1");
119+
await page.click("[type=submit]");
120+
await waitForNavigation;
121+
122+
await expect(page).toHaveText(
123+
"#setting-error-settings_updated",
124+
"Settings saved."
125+
);
126+
});
127+
128+
it('Should display the homepage with no remediation"', async () => {
129+
notify("Display the homepage with no remediation");
130+
131+
await page.goto(`${BASE_URL}`);
132+
await waitForNavigation;
133+
134+
const title = await page.title();
135+
await expect(title).toContain("Just another WordPress site");
136+
});
137+
138+
it('Should display a captcha wall"', async () => {
139+
notify("Display a captcha wall");
140+
141+
// add a captcha remediation
142+
await addDecision(CLIENT_IP, "captcha", "15m");
143+
await wait(1000);
144+
145+
await page.goto(`${BASE_URL}`);
146+
await waitForNavigation;
147+
148+
const title = await page.title();
149+
await expect(title).toContain("Oops..");
150+
await expect(page).toHaveText(
151+
".desc",
152+
"Please complete the security check."
153+
);
154+
155+
// Refresh the captcha 2 times
156+
await page.click("#refresh_link");
157+
await waitForNavigation;
158+
159+
await page.click("#refresh_link");
160+
await waitForNavigation;
161+
});
162+
163+
it('Should display a ban wall"', async () => {
164+
notify("Display a ban wall");
165+
166+
// add a ban remediation
167+
await addDecision(CLIENT_IP, "ban", "15m");
168+
await wait(1000);
169+
170+
await page.goto(`${BASE_URL}`);
171+
await waitForNavigation;
172+
173+
const title = await page.title();
174+
await expect(title).toContain("Oops..");
175+
await expect(page).toHaveText(
176+
".desc",
177+
"This page is protected against cyber attacks and your IP has been banned by our system."
178+
);
179+
});
180+
181+
it('Should display back the homepage with no remediation"', async () => {
182+
notify("Display back the homepage with no remediation");
183+
184+
// delete a ban remediation
185+
await deleteAllDecisions();
186+
await wait(1000);
187+
188+
await page.goto(`${BASE_URL}`);
189+
await waitForNavigation;
190+
191+
const title = await page.title();
192+
await expect(title).toContain("Just another WordPress site");
193+
});
194+
195+
it('Should enable the stream mode"', async () => {
196+
notify("Enable the stream mode");
197+
198+
await page.goto(
199+
`${BASE_URL}/wp-admin/admin.php?page=crowdsec_advanced_settings`
200+
);
201+
await waitForNavigation;
202+
203+
const title = await page.title();
204+
await expect(title).toContain("Advanced");
205+
206+
await page.click("[for=crowdsec_stream_mode]");
207+
208+
await page.fill("[name=crowdsec_stream_mode_refresh_frequency]", "1");
209+
await page.click("[type=submit]");
210+
await waitForNavigation;
211+
212+
await expect(page).toHaveText(
213+
"#setting-error-settings_updated",
214+
"Settings saved."
215+
);
216+
});
217+
218+
it('Should display a ban wall via stream mode"', async () => {
219+
notify("Display a ban wall via stream mode");
220+
221+
// add a ban remediation
222+
await addDecision(CLIENT_IP, "ban", "15m");
223+
await wait(2000);
224+
// force WP Cron to run cache update as bouncing is done before cache updating
225+
// This could be fixed by running homemade call to cache update
226+
// if it's the time to update cache
227+
await page.goto(`${BASE_URL}/wp-cron.php`);
228+
229+
await page.goto(`${BASE_URL}`);
230+
await waitForNavigation;
231+
232+
const title = await page.title();
233+
await expect(title).toContain("Oops..");
234+
await expect(page).toHaveText(
235+
".desc",
236+
"This page is protected against cyber attacks and your IP has been banned by our system."
237+
);
238+
});
239+
240+
it('Should display back the homepage with no remediation via stream mode"', async () => {
241+
notify("Display back the homepage with no remediation via stream mode");
242+
243+
// delete a ban remediation
244+
await deleteAllDecisions();
245+
await wait(2000);
246+
await page.goto(`${BASE_URL}/wp-cron.php`);
247+
248+
await page.goto(`${BASE_URL}`);
249+
await waitForNavigation;
250+
251+
const title = await page.title();
252+
await expect(title).toContain("Just another WordPress site");
253+
});
254+
});

tests/functional/icon.png

53.1 KB
Loading

0 commit comments

Comments
 (0)