timing.swtbot: add Generic SegmentTable tests
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests / src / org / eclipse / tracecompass / analysis / timing / ui / swtbot / tests / table / SegmentTableTest.java
1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9 package org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests.table;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15
16 import java.io.BufferedReader;
17 import java.io.ByteArrayOutputStream;
18 import java.io.File;
19 import java.io.FileReader;
20 import java.io.IOException;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Random;
28 import java.util.stream.Collectors;
29
30 import org.apache.log4j.ConsoleAppender;
31 import org.apache.log4j.Logger;
32 import org.apache.log4j.SimpleLayout;
33 import org.eclipse.jdt.annotation.NonNull;
34 import org.eclipse.jdt.annotation.Nullable;
35 import org.eclipse.jface.viewers.TableViewer;
36 import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
37 import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
38 import org.eclipse.swtbot.swt.finder.SWTBot;
39 import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
40 import org.eclipse.swtbot.swt.finder.results.Result;
41 import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences;
42 import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu;
43 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable;
44 import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener;
45 import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider;
46 import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableView;
47 import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableViewer;
48 import org.eclipse.tracecompass.segmentstore.core.BasicSegment;
49 import org.eclipse.tracecompass.segmentstore.core.ISegment;
50 import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
51 import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory;
52 import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory.SegmentStoreType;
53 import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect;
54 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
55 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
56 import org.eclipse.tracecompass.tmf.ui.dialog.TmfFileDialogFactory;
57 import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers;
58 import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotUtils;
59 import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils;
60 import org.eclipse.ui.IViewPart;
61 import org.eclipse.ui.IWorkbench;
62 import org.eclipse.ui.PartInitException;
63 import org.eclipse.ui.PlatformUI;
64 import org.junit.After;
65 import org.junit.Before;
66 import org.junit.BeforeClass;
67 import org.junit.Test;
68
69 /**
70 * Tests of the latency table to extend it to custom tables, 4 steps are needed.
71 * <ol>
72 * <li>Override {@link #createSegment(long, long)}</li>
73 * <li>Override {@link #openTable()} to open the desired table view</li>
74 * <li>Override {@link #getSegStoreProvider()} to retrieve the segment store
75 * provider with the desirable aspects</li>
76 * <li>Override {@link #testTsv(String[])} to test the content of the output to
77 * TSV</li>
78 * </ol>
79 *
80 * Feel free to override any test and add additional tests but remember to call
81 * <code>super.test()</code> before.
82 *
83 * @author Matthew Khouzam
84 */
85 public class SegmentTableTest {
86
87 /**
88 * Test table
89 *
90 * @author Matthew Khouzam
91 */
92 public static final class TestSegmentStoreTableView extends AbstractSegmentStoreTableView {
93 /**
94 * ID of this view
95 */
96 public static final String ID = "org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests.table.TestSegmentStoreTableView"; //$NON-NLS-1$
97
98 /**
99 * Constructor
100 */
101 public TestSegmentStoreTableView() {
102 }
103
104 SegmentTableTest fTest;
105
106 /**
107 * Set the parent test
108 *
109 * @param test
110 * the test
111 */
112 public void setTest(SegmentTableTest test) {
113 fTest = test;
114 }
115
116 @Override
117 protected @NonNull AbstractSegmentStoreTableViewer createSegmentStoreViewer(@NonNull TableViewer tableViewer) {
118 return new AbstractSegmentStoreTableViewer(tableViewer) {
119
120 @Override
121 protected @Nullable ISegmentStoreProvider getSegmentStoreProvider(@NonNull ITmfTrace trace) {
122 return fTest.getSegStoreProvider();
123 }
124 };
125 }
126 }
127
128 private final class SimpleSegmentStoreProvider implements ISegmentStoreProvider {
129 @Override
130 public void removeListener(@NonNull IAnalysisProgressListener listener) {
131 // do nothing
132 }
133
134 @Override
135 public @Nullable ISegmentStore<@NonNull ISegment> getSegmentStore() {
136 return fSs;
137 }
138
139 @Override
140 public @NonNull Iterable<@NonNull ISegmentAspect> getSegmentAspects() {
141 return Collections.emptyList();
142 }
143
144 @Override
145 public void addListener(@NonNull IAnalysisProgressListener listener) {
146 // do nothing
147 }
148 }
149
150 private AbstractSegmentStoreTableView fTableView;
151 private AbstractSegmentStoreTableViewer fTable;
152 private ISegmentStoreProvider fSsp;
153 private final ISegmentStore<@NonNull ISegment> fSs = SegmentStoreFactory.createSegmentStore(SegmentStoreType.Fast);
154
155 /** The Log4j logger instance. */
156 private static final Logger fLogger = Logger.getRootLogger();
157
158 /**
159 * Before class, call by all subclassed
160 */
161 @BeforeClass
162 public static void beforeClass() {
163
164 SWTBotUtils.initialize();
165 Thread.currentThread().setName("SWTBotTest");
166 /* set up for swtbot */
167 SWTBotPreferences.TIMEOUT = 20000; /* 20 second timeout */
168 SWTBotPreferences.KEYBOARD_LAYOUT = "EN_US";
169 fLogger.removeAllAppenders();
170 fLogger.addAppender(new ConsoleAppender(new SimpleLayout(), ConsoleAppender.SYSTEM_OUT));
171 SWTWorkbenchBot bot = new SWTWorkbenchBot();
172 final List<SWTBotView> openViews = bot.views();
173 for (SWTBotView view : openViews) {
174 if (view.getTitle().equals("Welcome")) {
175 view.close();
176 bot.waitUntil(ConditionHelpers.ViewIsClosed(view));
177 }
178 }
179 /* Switch perspectives */
180 SWTBotUtils.switchToTracingPerspective();
181 /* Finish waiting for eclipse to load */
182 WaitUtils.waitForJobs();
183 }
184
185 /**
186 * Opens a latency table
187 */
188 @Before
189 public void init() {
190 setTableView(openTable());
191 assertNotNull(getTableView());
192 setTable(getTableView().getSegmentStoreViewer());
193 assertNotNull(getTable());
194 ISegmentStoreProvider segStoreProvider = getSegStoreProvider();
195 assertNotNull(segStoreProvider);
196 UIThreadRunnable.syncExec(() -> getTable().setSegmentProvider(segStoreProvider));
197 }
198
199 /**
200 * Close the table
201 */
202 @After
203 public void finish() {
204 new SWTWorkbenchBot().viewById(getTableView().getSite().getId()).close();
205 }
206
207 /**
208 * Create the table viewer to test
209 *
210 * @return the table viewer bot
211 */
212 protected AbstractSegmentStoreTableView openTable() {
213 AbstractSegmentStoreTableView tableView = getTableView();
214 if (tableView != null) {
215 return tableView;
216 }
217 IViewPart vp = null;
218 final IWorkbench workbench = PlatformUI.getWorkbench();
219 vp = UIThreadRunnable.syncExec((Result<IViewPart>) () -> {
220 try {
221 return workbench.getActiveWorkbenchWindow().getActivePage().showView(TestSegmentStoreTableView.ID);
222 } catch (PartInitException e) {
223 return null;
224 }
225 });
226 assertNotNull(vp);
227 assertTrue(vp instanceof TestSegmentStoreTableView);
228 TestSegmentStoreTableView testSegmentStoreTableView = (TestSegmentStoreTableView) vp;
229 testSegmentStoreTableView.setTest(this);
230 fTableView = testSegmentStoreTableView;
231
232 return fTableView;
233 }
234
235 /**
236 * Create a segment of the type supported by the table under test, with the
237 * requested start and end time
238 *
239 * @param start
240 * start time
241 * @param end
242 * end time
243 * @return the segment
244 */
245 protected @NonNull ISegment createSegment(long start, long end) {
246 return new BasicSegment(start, end);
247 }
248
249 /**
250 * Test a climbing data structure.
251 * <p>
252 * Create segments that are progressively larger and start later. Test that
253 * the "duration" column sorts well
254 */
255 @Test
256 public void climbTest() {
257 List<@NonNull ISegment> fixture = new ArrayList<>();
258 for (int i = 0; i < 100; i++) {
259 fixture.add(createSegment(i, 2 * i));
260 }
261
262 assertNotNull(getTable());
263 getTable().updateModel(fixture);
264 SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable());
265 SWTBot bot = new SWTBot();
266 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
267 tableBot.header("Duration").click();
268 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
269 tableBot.header("Duration").click();
270 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "99", 0, 2));
271 }
272
273 /**
274 * Test a decrementing data structure.
275 * <p>
276 * Create segments that are progressively shorter and start sooner,
277 * effectively the inverse sorted {@link #climbTest()} datastructure. Test
278 * that the "duration" column sorts well
279 */
280 @Test
281 public void decrementingTest() {
282 List<@NonNull ISegment> fixture = new ArrayList<>();
283 for (int i = 100; i >= 0; i--) {
284 fixture.add(createSegment(i, 2 * i));
285 }
286 assertNotNull(getTable());
287 getTable().updateModel(fixture);
288 SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable());
289 SWTBot bot = new SWTBot();
290 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "100", 0, 2));
291 tableBot.header("Duration").click();
292 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
293 tableBot.header("Duration").click();
294 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "100", 0, 2));
295 }
296
297 /**
298 * Test small table
299 * <p>
300 * Test table with 2 segments. Duration sort is tested.
301 */
302 @Test
303 public void smallTest() {
304 List<@NonNull ISegment> fixture = new ArrayList<>();
305 for (int i = 1; i >= 0; i--) {
306 fixture.add(createSegment(i, 2 * i));
307 }
308 assertNotNull(getTable());
309 getTable().updateModel(fixture);
310 SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable());
311 SWTBot bot = new SWTBot();
312 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2));
313 tableBot.header("Duration").click();
314 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
315 tableBot.header("Duration").click();
316 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2));
317 }
318
319 /**
320 * Test large table
321 * <p>
322 * Test table with over 9000 segments. Duration sort is tested.
323 */
324 @Test
325 public void largeTest() {
326 final int size = 1000000;
327 ISegment[] fixture = new ISegment[size];
328 for (int i = 0; i < size; i++) {
329 fixture[i] = createSegment(i, 2 * i);
330 }
331 assertNotNull(getTable());
332 getTable().updateModel(fixture);
333 SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable());
334 SWTBot bot = new SWTBot();
335 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
336 tableBot.header("Duration").click();
337 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
338 tableBot.header("Duration").click();
339 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "999,999", 0, 2));
340 }
341
342 /**
343 * Test table with segments that have durations spread into a random (white
344 * noise) distribution
345 * <p>
346 * Test table with a random distribution of segments. Duration sort is
347 * tested.
348 */
349 @Test
350 public void noiseTest() {
351 Random rnd = new Random();
352 rnd.setSeed(1234);
353 final int size = 1000000;
354 ISegment[] fixture = new ISegment[size];
355 for (int i = 0; i < size; i++) {
356 int start = Math.abs(rnd.nextInt(100000000));
357 int end = start + Math.abs(rnd.nextInt(1000000));
358 fixture[i] = (createSegment(start, end));
359 }
360 assertNotNull(getTable());
361 getTable().updateModel(fixture);
362 SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable());
363 SWTBot bot = new SWTBot();
364 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "894,633", 0, 2));
365 tableBot.header("Duration").click();
366 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
367 tableBot.header("Duration").click();
368 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "999,999", 0, 2));
369 }
370
371 /**
372 * Test table with segments that have durations spread into a gaussian
373 * (normal) distribution
374 * <p>
375 * Test table with a gaussian distribution of segments. Duration sort is
376 * tested.
377 */
378 @Test
379 public void gaussianNoiseTest() {
380 Random rnd = new Random();
381 rnd.setSeed(1234);
382 List<@NonNull ISegment> fixture = new ArrayList<>();
383 for (int i = 1; i <= 1000000; i++) {
384 int start = Math.abs(rnd.nextInt(100000000));
385 final int delta = Math.abs(rnd.nextInt(1000));
386 int end = start + delta * delta;
387 fixture.add(createSegment(start, end));
388 }
389 assertNotNull(getTable());
390 getTable().updateModel(fixture);
391 SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable());
392 SWTBot bot = new SWTBot();
393 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "400,689", 0, 2));
394 tableBot.header("Duration").click();
395 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "0", 0, 2));
396 tableBot.header("Duration").click();
397 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "998,001", 0, 2));
398 }
399
400 /**
401 * Test creating a tsv
402 *
403 * @throws NoSuchMethodException
404 * Error creating the tsv
405 * @throws IOException
406 * no such file or the file is locked.
407 */
408 @Test
409 public void testWriteToTsv() throws NoSuchMethodException, IOException {
410
411 List<@NonNull ISegment> fixture = new ArrayList<>();
412 for (int i = 1; i <= 20; i++) {
413 int start = i;
414 final int delta = i;
415 int end = start + delta * delta;
416 fixture.add(createSegment(start, end));
417 }
418 assertNotNull(getTable());
419 getTable().updateModel(fixture);
420 SWTBotTable tableBot = new SWTBotTable(getTable().getTableViewer().getTable());
421 SWTBot bot = new SWTBot();
422 bot.waitUntil(ConditionHelpers.isTableCellFilled(tableBot, "1", 0, 2));
423 SWTWorkbenchBot swtWorkbenchBot = new SWTWorkbenchBot();
424 SWTBotView viewBot = swtWorkbenchBot.viewById(getTableView().getSite().getId());
425 String[] lines = extractTsv(viewBot);
426 testTsv(lines);
427 List<String> actionResult = Arrays.asList(lines);
428 String absolutePath = TmfTraceManager.getTemporaryDirPath() + File.separator + "syscallLatencyTest.testWriteToTsv.tsv";
429 TmfFileDialogFactory.setOverrideFiles(absolutePath);
430 SWTBotMenu menuBot = viewBot.viewMenu().menu("Export to TSV");
431 try {
432 assertTrue(menuBot.isEnabled());
433 assertTrue(menuBot.isVisible());
434 menuBot.click();
435
436 try (BufferedReader br = new BufferedReader(new FileReader(absolutePath))) {
437 List<String> actual = br.lines().collect(Collectors.toList());
438 assertEquals("Both reads", actionResult, actual);
439 }
440 } finally {
441 new File(absolutePath).delete();
442 }
443
444 }
445
446 private String[] extractTsv(SWTBotView viewBot) throws NoSuchMethodException, SecurityException {
447 ByteArrayOutputStream os = new ByteArrayOutputStream();
448 assertNotNull(os);
449 Class<@NonNull AbstractSegmentStoreTableView> clazz = AbstractSegmentStoreTableView.class;
450 Method method = clazz.getDeclaredMethod("exportToTsv", java.io.OutputStream.class);
451 method.setAccessible(true);
452 final Exception[] except = new Exception[1];
453 UIThreadRunnable.syncExec(() -> {
454 try {
455 method.invoke(getTableView(), os);
456 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
457 except[0] = e;
458 }
459 });
460 assertNull(except[0]);
461 @SuppressWarnings("null")
462 String[] lines = String.valueOf(os).split(System.getProperty("line.separator"));
463 return lines;
464 }
465
466 /**
467 * Test the TSV generated. For each line, including the header, it should be
468 * asserted that it is equal to the expected line
469 *
470 * @param lines
471 * every entry, starting with the header
472 */
473 protected void testTsv(String[] lines) {
474 assertNotNull(lines);
475 assertEquals("number of lines", 21, lines.length);
476 assertEquals("header", "Start Time\tEnd Time\tDuration", lines[0]);
477 // not a straight up string compare due to time zones. Kathmandu and
478 // Eucla have 15 minute time zones.
479 assertTrue("line 1", lines[1].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s001\\t\\d\\d:\\d\\d:00.000 000 002\\t1"));
480 assertTrue("line 2", lines[2].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s002\\t\\d\\d:\\d\\d:00.000 000 006\\t4"));
481 assertTrue("line 3", lines[3].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s003\\t\\d\\d:\\d\\d:00.000 000 012\\t9"));
482 assertTrue("line 4", lines[4].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s004\\t\\d\\d:\\d\\d:00.000 000 020\\t16"));
483 assertTrue("line 5", lines[5].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s005\\t\\d\\d:\\d\\d:00.000 000 030\\t25"));
484 assertTrue("line 6", lines[6].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s006\\t\\d\\d:\\d\\d:00.000 000 042\\t36"));
485 assertTrue("line 7", lines[7].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s007\\t\\d\\d:\\d\\d:00.000 000 056\\t49"));
486 assertTrue("line 8", lines[8].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s008\\t\\d\\d:\\d\\d:00.000 000 072\\t64"));
487 assertTrue("line 9", lines[9].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s009\\t\\d\\d:\\d\\d:00.000 000 090\\t81"));
488 assertTrue("line 10", lines[10].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s010\\t\\d\\d:\\d\\d:00.000 000 110\\t100"));
489 assertTrue("line 11", lines[11].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s011\\t\\d\\d:\\d\\d:00.000 000 132\\t121"));
490 assertTrue("line 12", lines[12].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s012\\t\\d\\d:\\d\\d:00.000 000 156\\t144"));
491 assertTrue("line 13", lines[13].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s013\\t\\d\\d:\\d\\d:00.000 000 182\\t169"));
492 assertTrue("line 14", lines[14].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s014\\t\\d\\d:\\d\\d:00.000 000 210\\t196"));
493 assertTrue("line 15", lines[15].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s015\\t\\d\\d:\\d\\d:00.000 000 240\\t225"));
494 assertTrue("line 16", lines[16].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s016\\t\\d\\d:\\d\\d:00.000 000 272\\t256"));
495 assertTrue("line 17", lines[17].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s017\\t\\d\\d:\\d\\d:00.000 000 306\\t289"));
496 assertTrue("line 18", lines[18].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s018\\t\\d\\d:\\d\\d:00.000 000 342\\t324"));
497 assertTrue("line 19", lines[19].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s019\\t\\d\\d:\\d\\d:00.000 000 380\\t361"));
498 assertTrue("line 20", lines[20].matches("\\d\\d:\\d\\d:00\\.000\\s000\\s020\\t\\d\\d:\\d\\d:00.000 000 420\\t400"));
499 }
500
501 /**
502 * Gets the table view
503 *
504 * @return the table view
505 */
506 protected AbstractSegmentStoreTableView getTableView() {
507 return fTableView;
508 }
509
510 /**
511 * Sets the table view
512 *
513 * @param tableView
514 * the table view
515 */
516 protected void setTableView(AbstractSegmentStoreTableView tableView) {
517 fTableView = tableView;
518 }
519
520 /**
521 * Gets the table viewer
522 *
523 * @return the table viewer
524 */
525 protected AbstractSegmentStoreTableViewer getTable() {
526 return fTable;
527 }
528
529 /**
530 * Set the table viewer
531 *
532 * @param table
533 * the table viewer
534 */
535 protected void setTable(AbstractSegmentStoreTableViewer table) {
536 fTable = table;
537 }
538
539 /**
540 * get the segment store provider
541 *
542 * @return the segment store provider
543 */
544 protected ISegmentStoreProvider getSegStoreProvider() {
545 ISegmentStoreProvider ssp = fSsp;
546 if (ssp == null) {
547 ssp = new SimpleSegmentStoreProvider();
548 fSsp = ssp;
549 }
550 return ssp;
551 }
552 }
This page took 0.044391 seconds and 5 git commands to generate.