Skip to content

Commit 06cc653

Browse files
authored
Merge pull request #1040 from oracle/sticky-session-tests
OWLS-72999 - Migrate Sticky Sessions test suite to github
2 parents 818477b + edd88b7 commit 06cc653

File tree

7 files changed

+465
-8
lines changed

7 files changed

+465
-8
lines changed

integration-tests/USECASES.MD

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,10 @@ Configuration Overrides Usecases
9696

9797
| Server Discovery | Use Case |
9898
| --- | --- |
99-
| Discover a newly started server | stop operator and apply the modified domain.yaml with replicas count increated, restart Operator and verify that the cluster is scaled up accordingly |
100-
| Discover dead weblogic servers | stop Operator, kill admin server and all managed servers in the cluster, restart Operator and verify that it restarts all dead servers |
99+
| Discover a newly started server | Stop operator and apply the modified domain.yaml with replicas count increased, restart Operator and verify that the cluster is scaled up accordingly |
100+
| Discover dead weblogic servers | Stop Operator, kill admin server and all managed servers in the cluster, restart Operator and verify that it restarts all dead servers |
101+
102+
| Sticky Session | Use Case |
103+
| --- | --- |
104+
| Server affinity | Use a web application deployed on Weblogic cluster to track HTTP session. Test server-affinity by sending two HTTP requests to Weblogic and verify that all requests are directed to same Weblogic server |
105+
| Session state isolation | Verify that values saved in a client session state are not visible to another client |

integration-tests/src/test/java/oracle/kubernetes/operator/ITServerDiscovery.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,15 @@ public static void staticPrepare() throws Exception {
8989
*/
9090
@AfterClass
9191
public static void staticUnPrepare() throws Exception {
92-
logger.info("+++++++++++++++++++++++++++++++++---------------------------------+");
93-
logger.info("BEGIN");
94-
logger.info("Run once, release cluster lease");
92+
if (!QUICKTEST) {
93+
logger.info("++++++++++++++++++++++++++++++++++");
94+
logger.info("BEGIN");
95+
logger.info("Run once, release cluster lease");
9596

96-
tearDown(new Object() {}.getClass().getEnclosingClass().getSimpleName());
97+
tearDown(new Object() {}.getClass().getEnclosingClass().getSimpleName());
9798

98-
logger.info("SUCCESS");
99+
logger.info("SUCCESS");
100+
}
99101
}
100102

101103
/**
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
// Copyright 2019, Oracle Corporation and/or its affiliates. All rights reserved.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at
3+
// http://oss.oracle.com/licenses/upl.
4+
5+
package oracle.kubernetes.operator;
6+
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
import java.util.regex.Matcher;
10+
import java.util.regex.Pattern;
11+
import oracle.kubernetes.operator.utils.Domain;
12+
import oracle.kubernetes.operator.utils.ExecResult;
13+
import oracle.kubernetes.operator.utils.Operator;
14+
import oracle.kubernetes.operator.utils.TestUtils;
15+
import org.junit.AfterClass;
16+
import org.junit.Assume;
17+
import org.junit.BeforeClass;
18+
import org.junit.FixMethodOrder;
19+
import org.junit.Test;
20+
import org.junit.runners.MethodSorters;
21+
22+
/**
23+
* Simple JUnit test file used for testing Operator.
24+
*
25+
* <p>This test is used for testing the affinity between a web client and a Weblogic server for the
26+
* duration of a HTTP session created by Voyager load balancer.
27+
*/
28+
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
29+
public class ITStickySession extends BaseTest {
30+
private static final String testAppName = "stickysessionapp";
31+
private static final String testAppPath = testAppName + "/StickySessionCounterServlet";
32+
private static final String scriptName = "buildDeployAppInPod.sh";
33+
34+
private static Map<String, String> httpAttrMap;
35+
36+
private static String httpHeaderFile;
37+
38+
private static Operator operator;
39+
private static Domain domain;
40+
41+
/**
42+
* This method gets called only once before any of the test methods are executed. It does the
43+
* initialization of the integration test properties defined in OperatorIT.properties and setting
44+
* the resultRoot, pvRoot and projectRoot attributes. It creates an operator, a Weblogic domain
45+
* and deploy a web application with persistent-store-type configured to replicated_if_clustered.
46+
*
47+
* @throws Exception
48+
*/
49+
@BeforeClass
50+
public static void staticPrepare() throws Exception {
51+
if (!QUICKTEST) {
52+
// initialize test properties and create the directories
53+
initialize(APP_PROPS_FILE);
54+
55+
// Create operator1
56+
if (operator == null) {
57+
logger.info("Creating Operator & waiting for the script to complete execution");
58+
operator = TestUtils.createOperator(OPERATOR1_YAML);
59+
}
60+
61+
// create domain
62+
if (domain == null) {
63+
logger.info("Creating WLS Domain & waiting for the script to complete execution");
64+
Map<String, Object> domainMap = TestUtils.loadYaml(DOMAINONPV_WLST_YAML);
65+
// Treafik doesn't work due to the bug 28050300. Use Voyager instead
66+
domainMap.put("LB_TYPE", "VOYAGER");
67+
domain = TestUtils.createDomain(domainMap);
68+
domain.verifyDomainCreated();
69+
}
70+
71+
httpHeaderFile = BaseTest.getResultDir() + "/headers";
72+
73+
httpAttrMap = new HashMap<String, String>();
74+
httpAttrMap.put("sessioncreatetime", "(.*)sessioncreatetime>(.*)</sessioncreatetime(.*)");
75+
httpAttrMap.put("sessionid", "(.*)sessionid>(.*)</sessionid(.*)");
76+
httpAttrMap.put("servername", "(.*)connectedservername>(.*)</connectedservername(.*)");
77+
httpAttrMap.put("count", "(.*)countattribute>(.*)</countattribute(.*)");
78+
79+
// Build WAR in the admin pod and deploy it from the admin pod to a weblogic target
80+
domain.buildDeployJavaAppInPod(
81+
testAppName, scriptName, BaseTest.getUsername(), BaseTest.getPassword());
82+
83+
// Wait some time for deployment gets ready
84+
Thread.sleep(10 * 1000);
85+
}
86+
}
87+
88+
/**
89+
* Releases k8s cluster lease, archives result, pv directories
90+
*
91+
* @throws Exception
92+
*/
93+
@AfterClass
94+
public static void staticUnPrepare() throws Exception {
95+
logger.info("+++++++++++++++++++++++++++++++++---------------------------------+");
96+
logger.info("BEGIN");
97+
logger.info("Run once, release cluster lease");
98+
99+
tearDown(new Object() {}.getClass().getEnclosingClass().getSimpleName());
100+
101+
logger.info("SUCCESS");
102+
}
103+
104+
/**
105+
* Use a web application deployed on Weblogic cluster to track HTTP session. In-memory replication
106+
* persistence method is configured to implement session persistence. server-affinity is achieved
107+
* by Voyager load balancer based on HTTP session information. This test sends two HTTP requests
108+
* to Weblogic and verify that all requests are directed to same Weblogic server.
109+
*
110+
* @throws Exception
111+
*/
112+
@Test
113+
public void testSameSessionStickiness() throws Exception {
114+
Assume.assumeFalse(QUICKTEST);
115+
String testMethodName = new Object() {}.getClass().getEnclosingMethod().getName();
116+
logTestBegin(testMethodName);
117+
118+
Map<String, Object> domainMap = domain.getDomainMap();
119+
String domainNS = domainMap.get("namespace").toString();
120+
String domainUid = domain.getDomainUid();
121+
122+
int counterNum = 4;
123+
String webServiceSetUrl = testAppPath + "?setCounter=" + counterNum;
124+
String webServiceGetUrl = testAppPath + "?getCounter";
125+
126+
String serverNameAttr = "servername";
127+
String sessionIDAttr = "sessionid";
128+
String countAttr = "count";
129+
130+
// Send the first HTTP request to the cluster to establish a connection
131+
ExecResult result = getHTTPResponse(webServiceSetUrl, " -D ");
132+
133+
// Retrieve the session id and connected server name from the first HTTP response
134+
String serverName1 = getHttpResponseAttribute(result.stdout(), serverNameAttr);
135+
String serverID1 = getHttpResponseAttribute(result.stdout(), sessionIDAttr);
136+
137+
Assume.assumeNotNull(serverName1);
138+
Assume.assumeNotNull(serverID1);
139+
140+
logger.info(
141+
"The first HTTP request established a connection with server <"
142+
+ serverName1
143+
+ ">, HTTP session id is <"
144+
+ serverID1
145+
+ ">");
146+
147+
// Send the second HTTP request to the cluster to get the count number
148+
result = getHTTPResponse(webServiceGetUrl, " -b ");
149+
150+
// Retrieve the session id and connected server name from the second HTTP response
151+
String serverName2 = getHttpResponseAttribute(result.stdout(), serverNameAttr);
152+
String serverID2 = getHttpResponseAttribute(result.stdout(), sessionIDAttr);
153+
String count = getHttpResponseAttribute(result.stdout(), countAttr);
154+
155+
Assume.assumeNotNull(serverName2);
156+
Assume.assumeNotNull(serverID2);
157+
Assume.assumeNotNull(count);
158+
159+
logger.info(
160+
"The second HTTP request connected to server <"
161+
+ serverName2
162+
+ "> with HTTP session id <"
163+
+ serverID2
164+
+ ">");
165+
166+
// Verify that the same session info is used
167+
Assume.assumeTrue("HTTP session should NOT change!", serverID1.equals(serverID2));
168+
logger.info("Same HTTP session id <" + serverID1 + "> is used");
169+
170+
// Verify server-affinity
171+
Assume.assumeTrue("Weblogic server name should NOT change!", serverName1.equals(serverName2));
172+
logger.info("Two HTTP requests are directed to same Weblogic server <" + serverName1 + ">");
173+
174+
// Verify that count numbers from two HTTP responses match
175+
Assume.assumeTrue("Count number does not match", Integer.parseInt(count) == counterNum);
176+
logger.info(
177+
"Count number <"
178+
+ count
179+
+ "> got from HTTP response matches "
180+
+ "original setting <"
181+
+ counterNum
182+
+ ">");
183+
184+
logger.info("SUCCESS - " + testMethodName);
185+
}
186+
187+
/**
188+
* Use a web application deployed on Weblogic cluster to track HTTP session. In-memory replication
189+
* persistence method is configured to implement session persistence. server-affinity is achieved
190+
* by Voyager load balancer based on HTTP session information. This test sends two HTTP requests
191+
* from two different clients to Weblogic and verify that HTTP sessions are isolated.
192+
*
193+
* @throws Exception
194+
*/
195+
@Test
196+
public void testDiffSessionsNoSharing() throws Exception {
197+
Assume.assumeFalse(QUICKTEST);
198+
String testMethodName = new Object() {}.getClass().getEnclosingMethod().getName();
199+
logTestBegin(testMethodName);
200+
201+
Map<String, Object> domainMap = domain.getDomainMap();
202+
String domainNS = domainMap.get("namespace").toString();
203+
String domainUid = domain.getDomainUid();
204+
205+
int counterNum = 4;
206+
String webServiceSetUrl = testAppPath + "?setCounter=" + counterNum;
207+
String webServiceGetUrl = testAppPath + "?getCounter";
208+
209+
String sessionIDAttr = "sessionid";
210+
String countAttr = "count";
211+
212+
// Client1 sends a HTTP request to set a count number
213+
ExecResult result = getHTTPResponse(webServiceSetUrl);
214+
215+
// Retrieve the session id from HTTP response
216+
String serverIDClient1 = getHttpResponseAttribute(result.stdout(), sessionIDAttr);
217+
Assume.assumeNotNull(serverIDClient1);
218+
219+
logger.info(
220+
"Client1 created a connection with HTTP session id <"
221+
+ serverIDClient1
222+
+ "> and set a count number to <"
223+
+ counterNum
224+
+ ">");
225+
226+
// Client2 sends a HTTP request to get a count number
227+
result = getHTTPResponse(webServiceGetUrl);
228+
229+
// Retrieve the session id and count number from HTTP response
230+
String serverIDClient2 = getHttpResponseAttribute(result.stdout(), sessionIDAttr);
231+
String count = getHttpResponseAttribute(result.stdout(), countAttr);
232+
233+
Assume.assumeNotNull(serverIDClient2);
234+
Assume.assumeNotNull(count);
235+
236+
logger.info(
237+
"Client2 created a connection with HTTP session id <"
238+
+ serverIDClient2
239+
+ "> and retrieved a count number <"
240+
+ count
241+
+ ">");
242+
243+
// Verify that each client session has its own session ID
244+
Assume.assumeFalse("HTTP session should NOT be same!", serverIDClient1.equals(serverIDClient2));
245+
246+
// Verify that count number retrieved from session state is not shared between two clients
247+
Assume.assumeTrue(
248+
"Count number <" + counterNum + "> set by client1 should be invisible to client2",
249+
count.equals("0"));
250+
251+
logger.info("SUCCESS - " + testMethodName);
252+
}
253+
254+
private String getHttpResponseAttribute(String httpResponseString, String attribute)
255+
throws Exception {
256+
String attrPatn = httpAttrMap.get(attribute);
257+
258+
Assume.assumeNotNull(attrPatn);
259+
260+
String httpAttribute = null;
261+
Pattern pattern = Pattern.compile(attrPatn);
262+
Matcher matcher = pattern.matcher(httpResponseString);
263+
264+
if (matcher.find()) {
265+
httpAttribute = matcher.group(2);
266+
}
267+
268+
return httpAttribute;
269+
}
270+
271+
private ExecResult getHTTPResponse(String webServiceURL, String... args) throws Exception {
272+
String headerOption = (args.length == 0) ? "" : args[0] + httpHeaderFile;
273+
274+
// Send a HTTP request
275+
String curlCmd = buildWebServiceUrl(webServiceURL, headerOption);
276+
logger.info("Send a HTTP request: " + curlCmd);
277+
ExecResult result = TestUtils.exec(curlCmd);
278+
279+
return result;
280+
}
281+
282+
private String buildWebServiceUrl(String curlURLPath, String paramToAppend) throws Exception {
283+
String nodePortHost = domain.getHostNameForCurl();
284+
int nodePort = domain.getLoadBalancerWebPort();
285+
286+
StringBuffer webServiceUrl = new StringBuffer("curl --silent ");
287+
webServiceUrl
288+
.append(" -H 'host: ")
289+
.append(domain.getDomainUid())
290+
.append(".org' ")
291+
.append(" http://")
292+
.append(nodePortHost)
293+
.append(":")
294+
.append(nodePort)
295+
.append("/")
296+
.append(curlURLPath)
297+
.append(paramToAppend);
298+
299+
return webServiceUrl.toString();
300+
}
301+
}

integration-tests/src/test/java/oracle/kubernetes/operator/utils/Domain.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,10 @@ protected void initialize(Map<String, Object> inputDomainMap) throws Exception {
12951295
"cp -rf " + BaseTest.getProjectRoot() + "/kubernetes/samples " + BaseTest.getResultDir());
12961296

12971297
this.voyager =
1298-
System.getenv("LB_TYPE") != null && System.getenv("LB_TYPE").equalsIgnoreCase("VOYAGER");
1298+
(System.getenv("LB_TYPE") != null && System.getenv("LB_TYPE").equalsIgnoreCase("VOYAGER"))
1299+
|| (inputDomainMap.containsKey("LB_TYPE")
1300+
&& ((String) inputDomainMap.get("LB_TYPE")).equalsIgnoreCase("VOYAGER"));
1301+
12991302
if (System.getenv("INGRESSPERDOMAIN") != null) {
13001303
INGRESSPERDOMAIN = new Boolean(System.getenv("INGRESSPERDOMAIN")).booleanValue();
13011304
}

0 commit comments

Comments
 (0)