blob: 02c421423381873d609104a6a6d2b0a5563c9a7d [file] [log] [blame]
Andrea Campanella7bbe7b12017-05-03 16:03:38 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Andrea Campanella7bbe7b12017-05-03 16:03:38 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.netconf.ctl.impl;
17
18import com.google.common.collect.ImmutableList;
19import org.apache.sshd.common.NamedFactory;
20import org.apache.sshd.server.Command;
21import org.apache.sshd.server.SshServer;
22import org.apache.sshd.server.auth.password.PasswordAuthenticator;
23import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
24import org.apache.sshd.server.session.ServerSession;
Yuta HIGUCHIe9761742017-09-10 15:10:19 -070025import org.bouncycastle.jce.provider.BouncyCastleProvider;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070026import org.junit.AfterClass;
27import org.junit.BeforeClass;
28import org.junit.Test;
29import org.onlab.junit.TestTools;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070030import org.onosproject.netconf.NetconfDeviceInfo;
31import org.onosproject.netconf.NetconfException;
32import org.onosproject.netconf.NetconfSession;
Kamil Stasiak9f59f442017-05-02 11:02:24 +020033import org.onosproject.netconf.DatastoreId;
34import org.onlab.packet.Ip4Address;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070035import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38import java.io.File;
Yuta HIGUCHIe9761742017-09-10 15:10:19 -070039import java.security.Security;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070040import java.util.Arrays;
41import java.util.Collection;
42import java.util.List;
43import java.util.Optional;
Sean Condonf096a9d2017-10-26 11:30:22 +010044import java.util.OptionalInt;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070045import java.util.concurrent.Callable;
46import java.util.concurrent.ExecutorService;
47import java.util.concurrent.Executors;
48import java.util.concurrent.FutureTask;
49import java.util.regex.Pattern;
50
51import static org.hamcrest.Matchers.containsInAnyOrder;
Kamil Stasiak9f59f442017-05-02 11:02:24 +020052import static org.junit.Assert.assertTrue;
53import static org.junit.Assert.assertThat;
54import static org.junit.Assert.assertNotNull;
55import static org.junit.Assert.fail;
56import static org.junit.Assert.assertFalse;
57import static org.onosproject.netconf.DatastoreId.CANDIDATE;
58import static org.onosproject.netconf.DatastoreId.RUNNING;
59import static org.onosproject.netconf.DatastoreId.STARTUP;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070060
61/**
62 * Unit tests for NetconfSession.
63 * <p>
64 * Sets up an SSH Server with Apache SSHD and connects to it using 2 clients
65 * Truly verifies that the NETCONF flows are compliant with a NETCONF server.
66 */
67public class NetconfSessionMinaImplTest {
68 private static final Logger log = LoggerFactory
Yuta HIGUCHIe9761742017-09-10 15:10:19 -070069 .getLogger(NetconfSessionMinaImplTest.class);
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070070
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070071 private static final String TEST_USERNAME = "netconf";
72 private static final String TEST_PASSWORD = "netconf123";
73 private static final String TEST_HOSTNAME = "127.0.0.1";
74
75 private static final String TEST_SERFILE =
76 System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + "testkey.ser";
77
78 private static final String SAMPLE_REQUEST =
79 "<some-yang-element xmlns=\"some-namespace\">"
80 + "<some-child-element/>"
81 + "</some-yang-element>";
82
Kamil Stasiak9f59f442017-05-02 11:02:24 +020083 protected static final String EDIT_CONFIG_REQUEST =
Andrea Campanella7bbe7b12017-05-03 16:03:38 -070084 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><rpc message-id=\"6\" "
85 + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
86 + "<edit-config>\n"
87 + "<target><running/></target>\n"
88 + "<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
89 + "<some-yang-element xmlns=\"some-namespace\">"
90 + "<some-child-element/></some-yang-element></config>\n"
91 + "</edit-config>\n"
92 + "</rpc>]]>]]>";
93
94 static final List<String> DEFAULT_CAPABILITIES = ImmutableList.<String>builder()
95 .add("urn:ietf:params:netconf:base:1.0")
Kamil Stasiak9f59f442017-05-02 11:02:24 +020096 .add("urn:ietf:params:netconf:capability:writable-running:1.0")
97 .add("urn:ietf:params:netconf:capability:candidate:1.0")
98 .add("urn:ietf:params:netconf:capability:startup:1.0")
99 .add("urn:ietf:params:netconf:capability:rollback-on-error:1.0")
100 .add("urn:ietf:params:netconf:capability:interleave:1.0")
101 .add("urn:ietf:params:netconf:capability:notification:1.0")
102 .add("urn:ietf:params:netconf:capability:validate:1.0")
103 .add("urn:ietf:params:netconf:capability:validate:1.1")
104 .build();
105
106 static final List<String> DEFAULT_CAPABILITIES_1_1 = ImmutableList.<String>builder()
107 .add("urn:ietf:params:netconf:base:1.0")
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700108 .add("urn:ietf:params:netconf:base:1.1")
109 .add("urn:ietf:params:netconf:capability:writable-running:1.0")
110 .add("urn:ietf:params:netconf:capability:candidate:1.0")
111 .add("urn:ietf:params:netconf:capability:startup:1.0")
112 .add("urn:ietf:params:netconf:capability:rollback-on-error:1.0")
113 .add("urn:ietf:params:netconf:capability:interleave:1.0")
114 .add("urn:ietf:params:netconf:capability:notification:1.0")
115 .add("urn:ietf:params:netconf:capability:validate:1.0")
116 .add("urn:ietf:params:netconf:capability:validate:1.1")
117 .build();
118
119
120 private static NetconfSession session1;
121 private static NetconfSession session2;
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200122 private static NetconfSession session3;
123 private static NetconfSession session4;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700124 private static SshServer sshServerNetconf;
125
126 @BeforeClass
127 public static void setUp() throws Exception {
Yuta HIGUCHIe9761742017-09-10 15:10:19 -0700128 Security.addProvider(new BouncyCastleProvider());
129 int portNumber = TestTools.findAvailablePort(50830);
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700130 sshServerNetconf = SshServer.setUpDefaultServer();
131 sshServerNetconf.setPasswordAuthenticator(
132 new PasswordAuthenticator() {
133 @Override
134 public boolean authenticate(
135 String username,
136 String password,
137 ServerSession session) {
138 return TEST_USERNAME.equals(username) && TEST_PASSWORD.equals(password);
139 }
140 });
Yuta HIGUCHIe9761742017-09-10 15:10:19 -0700141 sshServerNetconf.setPort(portNumber);
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700142 SimpleGeneratorHostKeyProvider provider = new SimpleGeneratorHostKeyProvider();
143 provider.setFile(new File(TEST_SERFILE));
144 sshServerNetconf.setKeyPairProvider(provider);
145 sshServerNetconf.setSubsystemFactories(
146 Arrays.<NamedFactory<Command>>asList(new NetconfSshdTestSubsystem.Factory()));
147 sshServerNetconf.open();
Yuta HIGUCHIe9761742017-09-10 15:10:19 -0700148 log.info("SSH Server opened on port {}", portNumber);
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700149
150 NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(
Yuta HIGUCHIe9761742017-09-10 15:10:19 -0700151 TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), portNumber);
Sean Condonf096a9d2017-10-26 11:30:22 +0100152 deviceInfo.setConnectTimeoutSec(OptionalInt.of(30));
153 deviceInfo.setReplyTimeoutSec(OptionalInt.of(30));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700154
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200155 session1 = new NetconfSessionMinaImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700156 log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session1.getSessionId());
157 assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("-1"));
158 assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("0"));
159 assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
160
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200161 session2 = new NetconfSessionMinaImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700162 log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session2.getSessionId());
163 assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("-1"));
164 assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("0"));
165 assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200166
167 session3 = new NetconfSessionMinaImpl(deviceInfo);
168 log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session3.getSessionId());
169 assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("-1"));
170 assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("0"));
171 assertThat(session3.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES_1_1.toArray()));
172
173 session4 = new NetconfSessionMinaImpl(deviceInfo);
174 log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session4.getSessionId());
175 assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("-1"));
176 assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("0"));
177 assertThat(session4.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES_1_1.toArray()));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700178 }
179
180 @AfterClass
181 public static void tearDown() throws Exception {
182 if (session1 != null) {
183 session1.close();
184 }
185 if (session2 != null) {
186 session2.close();
187 }
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200188 if (session3 != null) {
189 session3.close();
190 }
191 if (session4 != null) {
192 session4.close();
193 }
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700194
195 sshServerNetconf.stop();
196 }
197
198 @Test
199 public void testEditConfigRequest() {
200 log.info("Starting edit-config async");
201 assertNotNull("Incorrect sessionId", session1.getSessionId());
202 try {
203 assertTrue("NETCONF edit-config command failed",
Yuta HIGUCHIdd7c3f82017-09-03 14:18:01 -0700204 session1.editConfig(RUNNING,
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200205 null, SAMPLE_REQUEST));
206 } catch (NetconfException e) {
207 e.printStackTrace();
208 fail("NETCONF edit-config test failed: " + e.getMessage());
209 }
210 log.info("Finishing edit-config async");
211 }
212
213 @Test
214 public void testEditConfigRequestWithChunkedFraming() {
215 log.info("Starting edit-config async");
216
217 assertNotNull("Incorrect sessionId", session3.getSessionId());
218 try {
219 assertTrue("NETCONF edit-config command failed",
Yuta HIGUCHIdd7c3f82017-09-03 14:18:01 -0700220 session3.editConfig(RUNNING,
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200221 null, SAMPLE_REQUEST));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700222 } catch (NetconfException e) {
223 e.printStackTrace();
224 fail("NETCONF edit-config test failed: " + e.getMessage());
225 }
226 log.info("Finishing edit-config async");
227 }
228
229 @Test
230 public void testEditConfigRequestWithOnlyNewConfiguration() {
231 log.info("Starting edit-config async");
232 assertNotNull("Incorrect sessionId", session1.getSessionId());
233 try {
234 assertTrue("NETCONF edit-config command failed",
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200235 session1.editConfig(EDIT_CONFIG_REQUEST));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700236 } catch (NetconfException e) {
237 e.printStackTrace();
238 fail("NETCONF edit-config test failed: " + e.getMessage());
239 }
240 log.info("Finishing edit-config async");
241 }
242
243 @Test
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200244 public void testEditConfigRequestWithOnlyNewConfigurationWithChunkedFraming() {
245 log.info("Starting edit-config async");
246 assertNotNull("Incorrect sessionId", session3.getSessionId());
247 try {
248 assertTrue("NETCONF edit-config command failed",
249 session3.editConfig(EDIT_CONFIG_REQUEST));
250 } catch (NetconfException e) {
251 e.printStackTrace();
252 fail("NETCONF edit-config test failed: " + e.getMessage());
253 }
254 log.info("Finishing edit-config async");
255 }
256
257 @Test
258 public void testDeleteConfigRequestWithRunningDatastoreIdDuration() {
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700259 log.info("Starting delete-config async");
260 assertNotNull("Incorrect sessionId", session1.getSessionId());
261 try {
262 assertFalse("NETCONF delete-config command failed",
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200263 session1.deleteConfig(RUNNING));
264 } catch (NetconfException e) {
265 e.printStackTrace();
266 fail("NETCONF delete-config test failed: " + e.getMessage());
267 }
268 log.info("Finishing delete-config async");
269 }
270
271 @Test
272 public void testDeleteConfigRequestWithRunningDatastoreIdDurationWithChunkedFraming() {
273 log.info("Starting delete-config async");
274 assertNotNull("Incorrect sessionId", session3.getSessionId());
275 try {
276 assertFalse("NETCONF delete-config command failed",
277 session3.deleteConfig(RUNNING));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700278 } catch (NetconfException e) {
279 e.printStackTrace();
280 fail("NETCONF delete-config test failed: " + e.getMessage());
281 }
282 log.info("Finishing delete-config async");
283 }
284
285 @Test
286 public void testCopyConfigRequest() {
287 log.info("Starting copy-config async");
288 assertNotNull("Incorrect sessionId", session1.getSessionId());
289 try {
290 assertTrue("NETCONF copy-config command failed",
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200291 session1.copyConfig(RUNNING.toString(),
292 "candidate"));
293 } catch (NetconfException e) {
294 e.printStackTrace();
295 fail("NETCONF edit-config test failed: " + e.getMessage());
296 }
297 log.info("Finishing copy-config async");
298 }
299
300 @Test
301 public void testCopyConfigRequestWithChunkedFraming() {
302 log.info("Starting copy-config async");
303 assertNotNull("Incorrect sessionId", session3.getSessionId());
304 try {
305 assertTrue("NETCONF copy-config command failed",
306 session3.copyConfig(RUNNING.toString(),
307 "candidate"));
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700308 } catch (NetconfException e) {
309 e.printStackTrace();
310 fail("NETCONF edit-config test failed: " + e.getMessage());
311 }
312 log.info("Finishing copy-config async");
313 }
314
315 @Test
316 public void testGetConfigRequest() {
317 log.info("Starting get-config async");
318 assertNotNull("Incorrect sessionId", session1.getSessionId());
319 try {
320 assertTrue("NETCONF get-config running command failed. ",
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200321 GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700322
323 assertTrue("NETCONF get-config candidate command failed. ",
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200324 GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
325
326 } catch (NetconfException e) {
327 e.printStackTrace();
328 fail("NETCONF get-config test failed: " + e.getMessage());
329 }
330 log.info("Finishing get-config async");
331 }
332
333 @Test
334 public void testGetConfigRequestWithChunkedFraming() {
335 log.info("Starting get-config async");
336 assertNotNull("Incorrect sessionId", session3.getSessionId());
337 try {
338 assertTrue("NETCONF get-config running command failed. ",
339 GET_REPLY_PATTERN.matcher(session3.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
340
341 assertTrue("NETCONF get-config candidate command failed. ",
342 GET_REPLY_PATTERN.matcher(session3.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700343
344 } catch (NetconfException e) {
345 e.printStackTrace();
346 fail("NETCONF get-config test failed: " + e.getMessage());
347 }
348 log.info("Finishing get-config async");
349 }
350
351 @Test
352 public void testGetRequest() {
353 log.info("Starting get async");
354 assertNotNull("Incorrect sessionId", session1.getSessionId());
355 try {
356 assertTrue("NETCONF get running command failed. ",
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200357 GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
358
359 } catch (NetconfException e) {
360 e.printStackTrace();
361 fail("NETCONF get test failed: " + e.getMessage());
362 }
363 log.info("Finishing get async");
364 }
365
366 @Test
367 public void testGetRequestWithChunkedFraming() {
368 log.info("Starting get async");
369 assertNotNull("Incorrect sessionId", session3.getSessionId());
370 try {
371 assertTrue("NETCONF get running command failed. ",
372 GET_REPLY_PATTERN.matcher(session3.get(SAMPLE_REQUEST, null)).matches());
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700373
374 } catch (NetconfException e) {
375 e.printStackTrace();
376 fail("NETCONF get test failed: " + e.getMessage());
377 }
378 log.info("Finishing get async");
379 }
380
381 @Test
382 public void testLockRequest() {
383 log.info("Starting lock async");
384 assertNotNull("Incorrect sessionId", session1.getSessionId());
385 try {
386 assertTrue("NETCONF lock request failed", session1.lock());
387 } catch (NetconfException e) {
388 e.printStackTrace();
389 fail("NETCONF lock test failed: " + e.getMessage());
390 }
391 log.info("Finishing lock async");
392 }
393
394 @Test
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200395 public void testLockRequestWithChunkedFraming() {
396 log.info("Starting lock async");
397 assertNotNull("Incorrect sessionId", session3.getSessionId());
398 try {
399 assertTrue("NETCONF lock request failed", session3.lock());
400 } catch (NetconfException e) {
401 e.printStackTrace();
402 fail("NETCONF lock test failed: " + e.getMessage());
403 }
404 log.info("Finishing lock async");
405 }
406
407 @Test
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700408 public void testUnLockRequest() {
409 log.info("Starting unlock async");
410 assertNotNull("Incorrect sessionId", session1.getSessionId());
411 try {
412 assertTrue("NETCONF unlock request failed", session1.unlock());
413 } catch (NetconfException e) {
414 e.printStackTrace();
415 fail("NETCONF unlock test failed: " + e.getMessage());
416 }
417 log.info("Finishing unlock async");
418 }
419
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200420 @Test
421 public void testUnLockRequestWithChunkedFraming() {
422 log.info("Starting unlock async");
423 assertNotNull("Incorrect sessionId", session3.getSessionId());
424 try {
425 assertTrue("NETCONF unlock request failed", session3.unlock());
426 } catch (NetconfException e) {
427 e.printStackTrace();
428 fail("NETCONF unlock test failed: " + e.getMessage());
429 }
430 log.info("Finishing unlock async");
431 }
432
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700433
434 @Test
435 public void testConcurrentSameSessionAccess() throws InterruptedException {
436 NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
437 NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session1, RUNNING, "startup");
438
439 FutureTask<Boolean> futureCopyConfig1 = new FutureTask<>(testCopyConfig1);
440 FutureTask<Boolean> futureCopyConfig2 = new FutureTask<>(testCopyConfig2);
441
442 ExecutorService executor = Executors.newFixedThreadPool(2);
443 log.info("Starting concurrent execution of copy-config through same session");
444 executor.execute(futureCopyConfig1);
445 executor.execute(futureCopyConfig2);
446
447 int count = 0;
448 while (count < 10) {
449 if (futureCopyConfig1.isDone() && futureCopyConfig2.isDone()) {
450 executor.shutdown();
451 log.info("Finished concurrent same session execution");
452 return;
453 }
454 Thread.sleep(100L);
455 count++;
456 }
457 fail("NETCONF test failed to complete.");
458 }
459
460 @Test
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200461 public void testConcurrentSameSessionAccessWithChunkedFraming() throws InterruptedException {
462 NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
463 NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session3, RUNNING, "startup");
464
465 FutureTask<Boolean> futureCopyConfig1 = new FutureTask<>(testCopyConfig1);
466 FutureTask<Boolean> futureCopyConfig2 = new FutureTask<>(testCopyConfig2);
467
468 ExecutorService executor = Executors.newFixedThreadPool(2);
469 log.info("Starting concurrent execution of copy-config through same session");
470 executor.execute(futureCopyConfig1);
471 executor.execute(futureCopyConfig2);
472
473 int count = 0;
474 while (count < 10) {
475 if (futureCopyConfig1.isDone() && futureCopyConfig2.isDone()) {
476 executor.shutdown();
477 log.info("Finished concurrent same session execution");
478 return;
479 }
480 Thread.sleep(100L);
481 count++;
482 }
483 fail("NETCONF test failed to complete.");
484 }
485
486 @Test
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700487 public void test2SessionAccess() throws InterruptedException {
488 NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
489 NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session2, RUNNING, "candidate");
490
491 FutureTask<Boolean> futureCopySession1 = new FutureTask<>(testCopySession1);
492 FutureTask<Boolean> futureCopySession2 = new FutureTask<>(testCopySession2);
493
494 ExecutorService executor = Executors.newFixedThreadPool(2);
495 log.info("Starting concurrent execution of copy-config through 2 different sessions");
496 executor.execute(futureCopySession1);
497 executor.execute(futureCopySession2);
498
499 int count = 0;
500 while (count < 10) {
501 if (futureCopySession1.isDone() && futureCopySession2.isDone()) {
502 executor.shutdown();
503 log.info("Finished concurrent 2 session execution");
504 return;
505 }
506 Thread.sleep(100L);
507 count++;
508 }
509 fail("NETCONF test failed to complete.");
510 }
511
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200512 @Test
513 public void test2SessionAccessWithChunkedFraming() throws InterruptedException {
514 NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session3, RUNNING, "candidate");
515 NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session4, RUNNING, "candidate");
516
517 FutureTask<Boolean> futureCopySession1 = new FutureTask<>(testCopySession1);
518 FutureTask<Boolean> futureCopySession2 = new FutureTask<>(testCopySession2);
519
520 ExecutorService executor = Executors.newFixedThreadPool(2);
521 log.info("Starting concurrent execution of copy-config through 2 different sessions");
522 executor.execute(futureCopySession1);
523 executor.execute(futureCopySession2);
524
525 int count = 0;
526 while (count < 10) {
527 if (futureCopySession1.isDone() && futureCopySession2.isDone()) {
528 executor.shutdown();
529 log.info("Finished concurrent 2 session execution");
530 return;
531 }
532 Thread.sleep(100L);
533 count++;
534 }
535 fail("NETCONF test failed to complete.");
536 }
537
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700538
539 public static String getTestHelloReply(Optional<Long> sessionId) {
540 return getTestHelloReply(DEFAULT_CAPABILITIES, sessionId);
541 }
542
543 public static String getTestHelloReply(Collection<String> capabilities, Optional<Long> sessionId) {
544 StringBuffer sb = new StringBuffer();
545
546 sb.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
547 sb.append("<capabilities>");
548 capabilities.forEach(capability -> {
549 sb.append("<capability>").append(capability).append("</capability>");
550 });
551 sb.append("</capabilities>");
552 if (sessionId.isPresent()) {
553 sb.append("<session-id>");
554 sb.append(sessionId.get().toString());
555 sb.append("</session-id>");
556 }
557 sb.append("</hello>");
558
559 return sb.toString();
560 }
561
562 public static String getOkReply(Optional<Integer> messageId) {
563 StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
564 sb.append("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ");
565 if (messageId.isPresent()) {
566 sb.append("message-id=\"");
567 sb.append(String.valueOf(messageId.get()));
568 sb.append("\">");
569 }
570 sb.append("<ok/>");
571 sb.append("</rpc-reply>");
572 return sb.toString();
573 }
574
575 public static String getGetReply(Optional<Integer> messageId) {
576 StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
577 sb.append("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ");
578 if (messageId.isPresent()) {
579 sb.append("message-id=\"");
580 sb.append(String.valueOf(messageId.get()));
581 sb.append("\">");
582 }
583 sb.append("<data>\n");
584 sb.append(SAMPLE_REQUEST);
585 sb.append("</data>\n");
586 sb.append("</rpc-reply>");
587 return sb.toString();
588 }
589
590 public static final Pattern HELLO_REQ_PATTERN =
591 Pattern.compile("(<\\?xml).*"
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200592 + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
593 + "( *)(<capabilities>)\\R?"
594 + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
595 + "( *)(<capability>urn:ietf:params:netconf:base:1.1</capability>)\\R?"
596 + "( *)(</capabilities>)\\R?"
597 + "(</hello>)\\R? *",
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700598 Pattern.DOTALL);
599
600 public static final Pattern EDIT_CONFIG_REQ_PATTERN =
601 Pattern.compile("(<\\?xml).*"
602 + "(<rpc message-id=\")[0-9]*(\") *(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
603 + "(<edit-config>)\\R?"
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200604 + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
605 + "(<" + RUNNING.toString() + "/>)|"
606 + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700607 + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
608 + ".*"
609 + "(</config>)\\R?(</edit-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
610
611
612 public static final Pattern LOCK_REQ_PATTERN =
613 Pattern.compile("(<\\?xml).*"
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200614 + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
615 + "message-id=\")[0-9]*(\">)\\R?"
616 + "(<lock>)\\R?"
617 + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
618 + "(<" + RUNNING.toString() + "/>)|"
619 + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
620 + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700621
622 public static final Pattern UNLOCK_REQ_PATTERN =
623 Pattern.compile("(<\\?xml).*"
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200624 + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
625 + "message-id=\")[0-9]*(\">)\\R?"
626 + "(<unlock>)\\R?"
627 + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
628 + "(<" + RUNNING.toString() + "/>)|"
629 + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
630 + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700631
632 public static final Pattern COPY_CONFIG_REQ_PATTERN =
633 Pattern.compile("(<\\?xml).*"
634 + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
635 + "(<copy-config>)\\R?"
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200636 + "(<target>\\R?((<" + CANDIDATE.toString() + "/>)|"
637 + "(<" + RUNNING.toString() + "/>)|"
638 + "(<" + STARTUP.toString() + "/>))\\R?</target>)\\R?"
639 + "(<source>)\\R?(<config>)(("
640 + CANDIDATE.toString() + ")|("
641 + RUNNING.toString() + ")|("
642 + STARTUP.toString()
643 + "))(</config>)\\R?(</source>)\\R?"
644 + "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700645
646 public static final Pattern GET_CONFIG_REQ_PATTERN =
647 Pattern.compile("(<\\?xml).*"
648 + "(<rpc message-id=\")[0-9]*(\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
649 + "(<get-config>)\\R?" + "(<source>)\\R?((<"
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200650 + CANDIDATE.toString()
651 + "/>)|(<" + RUNNING.toString()
652 + "/>)|(<" + STARTUP.toString()
653 + "/>))\\R?(</source>)\\R?"
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700654 + "(<filter type=\"subtree\">).*(</filter>)\\R?"
655 + "(</get-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
656
657 public static final Pattern GET_REPLY_PATTERN =
658 Pattern.compile("(<\\?xml).*"
659 + "(<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
660 + "(<data>).*(</data>)\\R?"
661 + "(</rpc-reply>)\\R?", Pattern.DOTALL);
662
663 public static final Pattern GET_REQ_PATTERN =
664 Pattern.compile("(<\\?xml).*"
665 + "(<rpc message-id=\")[0-9]*(\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
666 + "(<get>)\\R?"
667 + "(<filter type=\"subtree\">).*(</filter>)\\R?"
668 + "(</get>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
669
670 public class NCCopyConfigCallable implements Callable<Boolean> {
671 private NetconfSession session;
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200672 private DatastoreId target;
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700673 private String source;
674
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200675 public NCCopyConfigCallable(NetconfSession session, DatastoreId target, String source) {
Andrea Campanella7bbe7b12017-05-03 16:03:38 -0700676 this.session = session;
677 this.target = target;
678 this.source = source;
679 }
680
681 @Override
682 public Boolean call() throws Exception {
683 return session.copyConfig(target, source);
684 }
685 }
Kamil Stasiak9f59f442017-05-02 11:02:24 +0200686}